diff --git a/blog/storybook-testing.mdx b/blog/storybook-testing.mdx new file mode 100644 index 0000000..bfe42d3 --- /dev/null +++ b/blog/storybook-testing.mdx @@ -0,0 +1,26 @@ +--- +title: Скриншотное тестирование со Storybook +slug: screenshot-testing-with-storybook +hide_table_of_contents: false +date: 2024-09-11T13:00 +--- + +[Storybook][storybook] - это инструмент для разработки пользовательских интерфейсов на основе компонентов. Он позволяет разработчикам независимо визуализировать компоненты в различных состояниях в изолированной от остальных компонентов среде. +Такой "шоурум" идеально подходит для скриншотного тестирования ваших компонентов, т.к. за счет этой изолированной среды такие тесты получаются в разы стабильнее и быстрее, чем вариант с e2e. + +С помощью плагина [@testplane/storybook][testplane-storybook] предоставляется возможность автоматически проверять изменения ваших компонентов с помощью скриншотного тестирования без единой строчки кода теста. +Вам достаточно описать ваш компонент в `Storybook`, а `testplane` при запуске автоматически сгенерит все необходимые тесты, прогонит их в нужных браузерах и предоставит визуальный отчет для обновления скриншотов. +При этом, если для компонентов была задекларирована [play-функция][play-function], то `testplane` перед началом теста выполнит ее, чтобы привести компонент в нужное состояние. + +Но если и этих возможностей вам не хватит, то вы можете прямо в story-файле описать testplane-тест, который будет выполнен как дополнительный тест для компонента. + +### Как использовать? + +Узнайте больше об этом в нашей документации Скриншотное тестирование со Storybook. + +[Пример проекта][example] с настроенным скриншотным тестированием со Storybook можно посмотреть в нашем репозитории на GitHub. + +[storybook][https://storybook.js.org] +[testplane-storybook][https://github.com/gemini-testing/testplane-storybook] +[play-function][https://storybook.js.org/docs/writing-stories/play-function] +[example]: https://github.com/gemini-testing/testplane/examples/storybook-autoscreenshots diff --git a/docs/visual-testing/visual-testing-intro.mdx b/docs/visual-testing/visual-testing-intro.mdx new file mode 100644 index 0000000..58fd0fb --- /dev/null +++ b/docs/visual-testing/visual-testing-intro.mdx @@ -0,0 +1,56 @@ +# Визуальное тестирование + +В testplane реализовано визуальное тестирование, с помощью которого пользователь может проверить визуальные изменения отдельного компонента, вьюпорта или всей страницы целиком. +Для анализа тестов, сохранения/обновления измененных изображений и запуска тестов рекомендуется использовать плагин [html-reporter][html-reporter], который предоставляет удобный UI для всех действий. + +### Особенности сравнения скриншотов + +При вызове команды `assertView` осуществляется поиск нужного элемента на странице с его автоматическим ожиданием. По умолчанию перед снятием скриншота на странице будет отключена анимация, чтобы исключить в будущем нестабильность теста из-за изменяющегося состояния элемента. + +При сравнении учитываются следующие настройки: + +- мигающая каретка в текстовых инпутах игнорируется по умолчанию +- на изображении игнорируются элементы, которые были указаны в опциях сравнения +- учитываются настройки точности сравнения (допустимые отклонения) +- учитываются настройки точности сравнения антиалиасинга для шрифтов (самый частый дифф на скриншотах) + +### Использование + +```typescript +await browser.assertView(state, options); +await browser.assertView(state, selector, options); +await element.assertView(state, options); +``` + +Команда `assertView` доступна как в контексте браузера, так и в контексте найденного элемента. Набор аргументов при этом отличается: + +```typescript +it("check search view", async ({ browser }) => { + // ... + + // taking screenshot of the current viewport + await browser.assertView("viewport-screen"); + + // taking screenshot of a specific element (from the browser context) + await browser.assertView("any-state-name", ".DocSearch", opts); + + const searchInput = await browser.$(".DocSearch"); + await searchInput.click(); + + // taking screenshot of a previously found item (from the element context) + await searchInput.assertView("any-state-name"); +}); +``` + +Подробнее о возможностях команды `assertView` читайте в соответствующих разделах. + +### Связанные команды + +- [browser.assertView][browser-command] +- [element.assertView][element-command] + +[html-reporter]: ../../html-reporter/html-reporter-setup + +[looks-same]:[https://github.com/gemini-testing/looks-same] +[browser-command]: https://testplane.io/docs/v8/commands/browser/assertView/ +[element-command]: https://testplane.io/docs/v8/commands/element/assertView/ diff --git a/docs/visual-testing/with-storybook.mdx b/docs/visual-testing/with-storybook.mdx new file mode 100644 index 0000000..193a4ae --- /dev/null +++ b/docs/visual-testing/with-storybook.mdx @@ -0,0 +1,256 @@ +import Admonition from "@theme/Admonition"; + +# Скриншотное тестирование со Storybook + +[Storybook][storybook] - это инструмент для разработки пользовательских интерфейсов на основе компонентов. Он позволяет разработчикам независимо визуализировать компоненты в различных состояниях в изолированной от остальных компонентов среде. +Такой "шоурум" идеально подходит для скриншотного тестирования ваших компонентов, т.к. за счет этой изолированной среды такие тесты получаются в разы стабильнее и быстрее, чем вариант с e2e. + +С помощью плагина [@testplane/storybook][testplane-storybook] предоставляется возможность автоматически проверять изменения ваших компонентов с помощью скриншотного тестирования. +Вам достаточно описать ваш компонент в `Storybook`, а `testplane` при запуске автоматически сгенерит все необходимые тесты, прогонит их в нужных браузерах и предоставит визуальный отчет для обновления скриншотов. + +## Как использовать? {#how_to_use} + +### Шаг 1: Установка необходимых зависимостей + +Если в Вашем проекте еще нет `Testplane`, то рекомендуем ознакомиться с разделом [quickstart][quickstart] или выполнить в директории Вашего проекта команду ниже: + +```bash +npm init testplane@latest +``` + +Устанавливаем плагин для `testplane` + +```bash +npm install @testplane/storybook --save-dev +``` + +### Шаг 2: Настройка плагина + +Для работы плагина достаточно минимальной настройки - нужно просто объявить его в конфиге `testplane` без дополнительных опций: + +```typescript +// .testplane.conf.ts +export default { + plugins: { + "@testplane/storybook": {}, + + // other Testplane plugins... + }, + + // other Testplane settings... +}; +``` + +### Шаг 3: Запуск тестов + +Для запуска storybook-тестов необходимо добавить опцию `--storybook`. Опция `--update-refs` позволяет сохранить/обновить эталонные изображения через CLI: + +```bash +npx testplane --storybook --update-refs +``` + +С помощью GUI-режима вы можете визуально оценить изменения в скриншотах, обновить их или перезапустить тесты: + +```bash +npx testplane gui --storybook +``` + +Если в Вашем проекте используется Storybook версии 6.x, то в настройках Storybook необходимо включить сохранение json-файла с Вашими историями: + +```typescript +// .storybook/main.js +export default { + // ... + features: { + // ... + buildStoriesJson: true, + }, +}; +``` + +## Кастомные тесты {#custom_tests} + +Некоторые компоненты перед скриншотом нужно привести в какое-либо состояние. Для этого у сторибука есть сущность под названием [play-функция][play-function]. Если она определена, мы сначала выполним все action-ы из нее, и только после этого сделаем скриншот. +Если вам не хватает выразительности Storybook, то вы можете в самой "Истории" описать testplane-тест, который будет выполнен как дополнительный тест для компонента. + +```typescript +// stories/Primary.stories.ts +import type { StoryObj } from "@storybook/react"; +import type { WithTestplane } from "@testplane/storybook"; + +export const Primary: WithTestplane = { + args: { + primary: true, + label: "Button", + }, + testplane: { + "my test": async ({ browser, expect }) => { + const element = await browser.$(".storybook-button"); + + await expect(element).toHaveText("Button"); + }, + }, +}; +``` + +Также для теста можно добавить дополнительные настройки + +```typescript +// stories/Primary.stories.ts +import type { WithTestplane } from "@testplane/storybook"; +import type { Meta, StoryObj } from "@storybook/react"; + +const meta: WithTestplane> = { + 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; +``` + + + При добавлении testplane-тестов расширение Ваших story-файлов должно быть `.js` или `.ts`. + + +## Параметры конфигурации плагина + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
**Параметр****Тип****По умолчанию****Описание**
enabled`Boolean`trueВключить / отключить плагин.
storybookConfigDir`String`".storybook"Путь к директории конфигурационного файла Storybook.
autoScreenshots`Boolean`trueВключить / отключить авто матическое скриншотное тестирование (будут выполняться только вручную описанные tetplane-тесты)
localport`Number`6006Порт для запуска dev-сервера Storybook.
remoteStorybookUrl`String`""Урл удаленного Storybook. Если указан, то локальный dev-сервер Storybook не будет запущен.
browserIds`Array`[]Массив id браузеров, в которых будут запущены тесты. По умолчанию тесты будут запущены во всех браузерах, описанных в конфиге testplane
+ +Например, для запуска тестов на Storybook, опубликованном удаленно на `s3`, настройка будет выглядеть следующим образом: + +```typescript +// .testplane.conf.ts +export default { + plugins: { + "@testplane/storybook": { + remoteStorybookUrl: "https://yastatic.net/s3/storybook/index.html", + }, + + // other Testplane plugins... + }, + + // other Testplane settings... +}; +``` + +## Дополнительные настройки {#extra_config} + +В Вашем проекте уже могут быть настроены другие типы тестирования, запускающиеся с помощью `testplane`. Чтобы не смешивать сущности, мы рекомендуем для storybook-тестов использовать отдельный конфиг и указывать его при запуске тестов. + +```bash +npx testplane --storybook --config .testplane.storybook.conf.ts +``` + +Сокращенная версия запуска + +```bash +npx testplane --storybook -c .testplane.storybook.conf.ts +``` + +Отдельный конфиг позволит Вам описать хранение скриншотов сторибуков рядом с Вашим story-файлом: + +```typescript +// .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); + }, + // other Testplane settings... +}; +``` + +В данном примере эталонные скриншоты будут сохранены в директории `screens//` относительно директории Вашего story-файла. + +## Оптимизация запуска тестов {#optimize_run} + +Storybook-тесты сами по себе довольно быстрые, т.к. для них не нужно сложное окружение, а на странице рендерится только один компонент. +В контексте браузера 1 раз создается окружения для тестирования Storybook и переиспользуется от теста к тесту. Поэтому, для максимальной скорости прохождения тестов мы рекомендуем выставлять опцию [testsPerSession][tests-per-session] со значением не меньше 20, чтобы переиспользовать браузерную сессию как можно дольше: + +```typescript +// .testplane.storybook.conf.ts +export default { + testsPerSession: 40, // set value for all browsers + + browsers: { + "chrome-desktop": { + testsPerSession: 50, // or set value for current browser + }, + firefox: { + // ... + }, + }, + + // other Testplane settings... +}; +``` + +Также, для storybook-тестов будет проигнорирована опция [isolation][isolation], чтобы не пресоздавать окружение на каджый тест (это никак не влияет на стабильность тестов). + +[storybook]: [https://storybook.js.org] +[testplane-storybook]: [https://github.com/gemini-testing/testplane-storybook] +[play-function]: [https://storybook.js.org/docs/writing-stories/play-function] +[quickstart]: ./quickstart/index +[tests-per-session]: ./config/browsers/#tests_per_session +[isolation]: ./config/browsers/#isolation diff --git a/sidebars.ts b/sidebars.ts index 508caf2..9025fec 100644 --- a/sidebars.ts +++ b/sidebars.ts @@ -25,6 +25,12 @@ const sidebars: SidebarsConfig = { items: [{ type: "autogenerated", dirName: "config" }], link: { type: "doc", id: "config/main" }, }, + { + type: "category", + label: "Visual testing", + items: [{ type: "autogenerated", dirName: "visual-testing" }], + link: { type: "doc", id: "visual-testing/visual-testing-intro" }, + }, { type: "category", label: "Guides",