Перейти к основному содержимому

Скриншотное тестирование со Storybook

Storybook — это инструмент для разработки пользовательских интерфейсов на основе компонентов. Он позволяет разработчикам независимо визуализировать компоненты в различных состояниях в изолированной от остальных компонентов среде. Такой "шоурум" идеально подходит для скриншотного тестирования ваших компонентов, т.к. за счет этой изолированной среды такие тесты получаются в разы стабильнее и быстрее, чем вариант с e2e.

С помощью плагина @testplane/storybook предоставляется возможность автоматически проверять изменения ваших компонентов с помощью скриншотного тестирования. Вам достаточно описать ваш компонент в Storybook, а testplane при запуске автоматически сгенерит все необходимые тесты, прогонит их в нужных браузерах и предоставит визуальный отчет для обновления скриншотов.

Как использовать?

Шаг 1: Установка необходимых зависимостей

Если в Вашем проекте еще нет Testplane, то рекомендуем ознакомиться с разделом quickstart или выполнить в директории Вашего проекта команду ниже:

npm init testplane@latest

Устанавливаем плагин для testplane

npm install @testplane/storybook --save-dev

Шаг 2: Настройка плагина

Для работы плагина достаточно минимальной настройки — нужно просто объявить его в конфиге testplane без дополнительных опций:

.testplane.conf.ts
export default {
plugins: {
"@testplane/storybook": {},

// other Testplane plugins...
},

// другие настройки Testplane...
};

Шаг 3: Запуск тестов

Для запуска storybook-тестов необходимо добавить опцию --storybook. Опция --update-refs позволяет сохранить/обновить эталонные изображения через CLI:

npx testplane --storybook --update-refs

С помощью GUI-режима вы можете визуально оценить изменения в скриншотах, обновить их или перезапустить тесты:

npx testplane gui --storybook

Если в Вашем проекте используется Storybook версии 6.x, то в настройках Storybook необходимо включить сохранение json-файла с Вашими историями:

.storybook/main.js
export default {
// ...
features: {
// ...
buildStoriesJson: true,
},
};

Кастомные тесты

Некоторые компоненты перед скриншотом нужно привести в какое-либо состояние. Для этого у сторибука есть сущность под названием play-функция. Если она определена, мы сначала выполним все action-ы из нее, и только после этого сделаем скриншот. Если вам не хватает выразительности Storybook, то вы можете в самой истории описать testplane-тест, который будет выполнен как дополнительный тест для компонента.

stories/Primary.stories.ts
import type { StoryObj } from "@storybook/react";
import type { WithTestplane } from "@testplane/storybook";

export const Primary: WithTestplane<StoryObj> = {
args: {
primary: true,
label: "Button",
},
testplane: {
"my test": async ({ browser, expect }) => {
const element = await browser.$(".storybook-button");

await expect(element).toHaveText("Button");
},
},
};

Также для теста можно добавить дополнительные настройки:

stories/Primary.stories.ts
import type { WithTestplane } from "@testplane/storybook";
import type { Meta, StoryObj } from "@storybook/react";

const meta: WithTestplane<Meta<typeof Button>> = {
title: "Example/Button",
component: Button,
testplane: {
skip: false, // if true, skips all Testplane tests from this story file
autoscreenshotSelector: ".my-selector", // Custom selector to auto-screenshot elements
browserIds: ["chrome"], // Testplane browsers to run tests from this story file
assertViewOpts: {
// override default assertView options for tests from this file
ignoreDiffPixelCount: 5,
},
},
};

export default meta;
warning

При добавлении testplane-тестов расширение Ваших story-файлов должно быть .js или .ts. Форматы jsx/tsx еще не поддержаны.

Параметры конфигурации плагина

Плагин имеет ряд опций для более гибкой настройки. Например, для запуска тестов на Storybook, опубликованном удаленно на s3, настройка будет выглядеть следующим образом:

.testplane.conf.ts
export default {
plugins: {
"@testplane/storybook": {
remoteStorybookUrl: "https://yastatic.net/s3/storybook/index.html",
},

// other Testplane plugins...
},

// другие настройки Testplane...
};

Весь список доступных опций можно посмотреть на странице плагина.

Дополнительные настройки

В Вашем проекте уже могут быть настроены другие типы тестирования, запускающиеся с помощью testplane. Чтобы не смешивать сущности, мы рекомендуем для storybook-тестов использовать отдельный конфиг и указывать его при запуске тестов.

npx testplane --storybook --config .testplane.storybook.conf.ts

Сокращенная версия запуска:

npx testplane --storybook -c .testplane.storybook.conf.ts

Отдельный конфиг позволит Вам описать хранение скриншотов сторибуков рядом с Вашим story-файлом:

.testplane.storybook.conf.ts
import path from "path";
import { getStoryFile } from "@testplane/storybook";

export default {
screenshotsDir: test => {
const relativeStoryFilePath = getStoryFile(test);
const relativeStoryFileDirPath = path.dirname(relativeStoryFilePath);

return path.join(relativeStoryFileDirPath, "screens", test.id, test.browserId);
},
// другие настройки Testplane...
};

В данном примере эталонные скриншоты будут сохранены в директории screens/<testId>/<browserId> относительно директории Вашего story-файла.

Оптимизация запуска тестов

Storybook-тесты сами по себе довольно быстрые, т.к. для них не нужно сложное окружение, а на странице рендерится только один компонент. В контексте браузера 1 раз создается окружения для тестирования Storybook и переиспользуется от теста к тесту. Поэтому, для максимальной скорости прохождения тестов мы рекомендуем выставлять опцию testsPerSession со значением не меньше 20, чтобы переиспользовать браузерную сессию как можно дольше:

.testplane.storybook.conf.ts
export default {
testsPerSession: 40, // можно установить количество тестов для сессии сразу для всех браузеров

browsers: {
"chrome-desktop": {
testsPerSession: 50, // или установить значение для конкретного браузера
},
firefox: {
// ...
},
},

// другие настройки Testplane...
};

Также, для storybook-тестов будет проигнорирована опция isolation, чтобы не пресоздавать окружение на каджый тест (это никак не влияет на стабильность тестов).