@testplane/storybook
Обзор
Используйте плагин @testplane/storybook для автоматической проверки изменения ваших компонентов с помощью скриншотного тестирования без единой строчки кода теста.
Этот плагин предоставляет:
- автоматическую генерацию скриншотных проверок для ваших storybook-файлов;
- возможность писать testplane-тесты прямо внутри ваших storybook-историй.
Установка
npm install @testplane/storybook --save-dev
Настройка
Storybook
Если используется storybook@6
, то Вам необходимо включить опцию buildStoriesJson в storybook
конфиге:
export default {
// ...
features: {
// ...
buildStoriesJson: true,
},
};
Этого не нужно делать для версий storybook@7 и выше.
Testplane
Добавьте плагин @testplane/storybook
в Ваш Testplane конфиг:
export default {
plugins: {
"@testplane/storybook": {},
// другие плагины Testplane...
},
// другие настройки Testplane...
};
При такой минимальной конфигурации Вы уже сможете выполнить команду npx testplane --storybook
, чтобы автоматически протестировать каждую историю в storybook с помощью команды Testplane assertView. Testplane откроет каждую историю, подождет завершения функции play (если она определена), а затем вызовет команду assertView
для компонента. Эти тесты будут сгенерированы в рантайме и не останутся на файловой системе после окончания тестов.
Расшифровка параметров конфигурации
Параметр | Тип | По умолчанию | Описание |
enabled | Boolean | true | Включить / отключить плагин. |
storybookConfigDir | String | ".storybook" | Путь к директории конфигурационного файла Storybook. |
autoScreenshots | Boolean | true | Включить / отключить автоматическое скриншотное тестирование |
autoscreenshotSelector | String | "" | Кастомный селектор, используемый в автоматических скриншотных тестах |
autoScreenshotStorybookGlobals | Record<string, Record<string, unknown>> | Комплекты глобальных параметров storybook, для каждого из которых следует генерировать автоматические скриншотные тесты | |
localport | Number | 6006 | Порт для запуска dev-сервера Storybook. |
remoteStorybookUrl | String | "" | Урл удаленного Storybook. Если указан, то локальный dev-сервер Storybook не будет запущен. |
browserIds | Array<String | RegExp> | [] | Массив id браузеров, в которых будут запущены тесты. По умолчанию тесты будут запущены во всех браузерах, описанных в конфиге testplane |
Производительность тестов Storybook сильно зависит от параметра Testplane testsPerSession, так как скорость этих тестов увеличивается при повторном использовании существующих сессий. Поэтому рекомендуется устанавливать значения около 20 и более. Такой тип тестов так же проигнорирует опцию Testplane isolation. Изоляция будет отключена принудительно для оптимизации скорости прохождения тестов.
autoScreenshotStorybookGlobals
К примеру, с autoScreenshotStorybookGlobals
со значением:
{
"default": {},
"light theme": {
"theme": "light"
},
"dark theme": {
"theme": "dark"
}
}
Для каждой стори будут сгенерированы 3 автоскриншотных теста, каждый из которых устанавливает соответствующие глобальные параметры сторибука:
... Autoscreenshot default
... Autoscreenshot light theme
... Autoscreenshot dark theme
Продвинутое использование
Если на Вашем проекте используется ts-node
, то Вы можете писать testplane-тесты прямо внутри истории:
Для примеров ниже файлы Storybook историй должны иметь расширение .js
или .ts
. Форматы
jsx/tsx еще не поддержаны.
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");
},
},
};
Также Вы можете дополнительно установить набор опций в конфиге сторей по умолчанию:
import type { WithTestplane } from "@testplane/storybook";
import type { Meta, StoryObj } from "@storybook/react";
const meta: WithTestplane<Meta<typeof Button>> = {
title: "Example/Button",
component: Button,
testplaneConfig: {
// Если true, все testplane-тесты этого файла будут отключены
skip: false,
// П ереопределяет опцию "autoScreenshots", описанную в конфиге плагина
autoScreenshots: true,
// Переопределяет "autoscreenshotSelector", описанный в конфиге плагина
autoscreenshotSelector: ".my-selector",
// Расширяет "autoScreenshotStorybookGlobals", описанные в конфиге плагина
autoScreenshotStorybookGlobals: { "dark theme": { theme: "dark" } },
// Список Testplane браузеров, в которых нужно запустить тест
browserIds: ["chrome"],
// Переопределяет опции команды assertView для тестов конкретного файла
assertViewOpts: {
ignoreDiffPixelCount: 5,
},
},
};
export default meta;
И затем переопределить эти опции для конкретных экспортов:
import type { StoryObj } from "@storybook/react";
import type { WithTestplane } from "@testplane/storybook";
export const Primary: WithTestplane<StoryObj> = {
args: {
primary: true,
label: "Button",
},
testplaneConfig: {
// Переопределяет testplaneConfig.skip из экспорта по умолчанию
skip: true,
// Расширяет testplaneConfig.assertViewOpts из экспорта по умолчанию
assertViewOpts: {
// Значение "ignoreDiffPixelCount: 5" будет унаследовано из default export
ignoreElements: [".some-selector"],
},
// Добавляет дополнительные наборы глобальных значений Storybook
autoScreenshotStorybookGlobals: { "ru locale": { locale: "ru" } },
},
};
Вы также можете отключить конкретные наборы для всего файла историй (в экспорте по умолчанию) и для отдельной истории (в именованном экспорте), установив значение null:
import type { WithTestplane } from "@testplane/storybook";
import type { Meta, StoryObj } from "@storybook/react";
const meta: WithTestplane<Meta<typeof Button>> = {
title: "Example/Button",
component: Button,
testplaneConfig: {
autoScreenshotStorybookGlobals: { "dark theme": { theme: "dark" } },
},
};
export default meta;
export const Primary: WithTestplane<StoryObj> = {
// ...другие свойства Storybook
testplaneConfig: {
// Не тестировать эту story в темной теме
autoScreenshotStorybookGlobals: { "dark theme": null },
},
};
Помимо расширения и отключения, Вы также можете полностью перезаписать "autoScreenshotStorybookGlobals", передав значение как функцию:
import type { StoryObj } from "@storybook/react";
import type { WithTestplane } from "@testplane/storybook";
export const Primary: WithTestplane<StoryObj> = {
// ...другие свойства Storybook
testplaneConfig: {
// Заменяет все глобальные наборы Storybook значений для этой story
autoScreenshotStorybookGlobals: () => ({ "ru locale": { locale: "ru" } }),
},
};
В Вашем проекте уже могут быть настроены другие типы тестирования, запускающиеся с помощью testplane
. Чтобы не смешивать сущности, мы рекомендуем для storybook описать отдельный конфиг, а при запуске указывать путь к нему с помощью CLI-опции. Например:
npx testplane --storybook -c .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>
рядом с Вашими файлами историй.