Skip to content

Commit 3684ac1

Browse files
committed
docs(storybook): add documentation about storybook
1 parent b41127a commit 3684ac1

File tree

4 files changed

+344
-0
lines changed

4 files changed

+344
-0
lines changed

blog/storybook-testing.mdx

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
---
2+
title: Скриншотное тестирование со Storybook
3+
slug: screenshot-testing-with-storybook
4+
hide_table_of_contents: false
5+
date: 2024-09-11T13:00
6+
---
7+
8+
[Storybook][storybook] - это инструмент для разработки пользовательских интерфейсов на основе компонентов. Он позволяет разработчикам независимо визуализировать компоненты в различных состояниях в изолированной от остальных компонентов среде.
9+
Такой "шоурум" идеально подходит для скриншотного тестирования ваших компонентов, т.к. за счет этой изолированной среды такие тесты получаются в разы стабильнее и быстрее, чем вариант с e2e.
10+
11+
С помощью плагина [@testplane/storybook][testplane-storybook] предоставляется возможность автоматически проверять изменения ваших компонентов с помощью скриншотного тестирования без единой строчки кода теста.
12+
Вам достаточно описать ваш компонент в `Storybook`, а `testplane` при запуске автоматически сгенерит все необходимые тесты, прогонит их в нужных браузерах и предоставит визуальный отчет для обновления скриншотов.
13+
При этом, если для компонентов была задекларирована [play-функция][play-function], то `testplane` перед началом теста выполнит ее, чтобы привести компонент в нужное состояние.
14+
15+
Но если и этих возможностей вам не хватит, то вы можете прямо в story-файле описать testplane-тест, который будет выполнен как дополнительный тест для компонента.
16+
17+
### Как использовать?
18+
19+
Узнайте больше об этом в нашей документации <a href="/docs/v8/visual-testing/with-storybook">Скриншотное тестирование со Storybook</a>.
20+
21+
[Пример проекта][example] с настроенным скриншотным тестированием со Storybook можно посмотреть в нашем репозитории на GitHub.
22+
23+
[storybook][https://storybook.js.org]
24+
[testplane-storybook][https://github.com/gemini-testing/testplane-storybook]
25+
[play-function][https://storybook.js.org/docs/writing-stories/play-function]
26+
[example]: https://github.com/gemini-testing/testplane/examples/storybook-autoscreenshots
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
# Визуальное тестирование
2+
3+
В testplane реализовано визуальное тестирование, с помощью которого пользователь может проверить визуальные изменения отдельного компонента, вьюпорта или всей страницы целиком.
4+
Для анализа тестов, сохранения/обновления измененных изображений и запуска тестов рекомендуется использовать плагин [html-reporter][html-reporter], который предоставляет удобный UI для всех действий.
5+
6+
### Особенности сравнения скриншотов
7+
8+
При вызове команды `assertView` осуществляется поиск нужного элемента на странице с его автоматическим ожиданием. По умолчанию перед снятием скриншота на странице будет отключена анимация, чтобы исключить в будущем нестабильность теста из-за изменяющегося состояния элемента.
9+
10+
При сравнении учитываются следующие настройки:
11+
12+
- мигающая каретка в текстовых инпутах игнорируется по умолчанию
13+
- на изображении игнорируются элементы, которые были указаны в опциях сравнения
14+
- учитываются настройки точности сравнения (допустимые отклонения)
15+
- учитываются настройки точности сравнения антиалиасинга для шрифтов (самый частый дифф на скриншотах)
16+
17+
### Использование
18+
19+
```typescript
20+
await browser.assertView(state, options);
21+
await browser.assertView(state, selector, options);
22+
await element.assertView(state, options);
23+
```
24+
25+
Команда `assertView` доступна как в контексте браузера, так и в контексте найденного элемента. Набор аргументов при этом отличается:
26+
27+
```typescript
28+
it("check search view", async ({ browser }) => {
29+
// ...
30+
31+
// taking screenshot of the current viewport
32+
await browser.assertView("viewport-screen");
33+
34+
// taking screenshot of a specific element (from the browser context)
35+
await browser.assertView("any-state-name", ".DocSearch", opts);
36+
37+
const searchInput = await browser.$(".DocSearch");
38+
await searchInput.click();
39+
40+
// taking screenshot of a previously found item (from the element context)
41+
await searchInput.assertView("any-state-name");
42+
});
43+
```
44+
45+
Подробнее о возможностях команды `assertView` читайте в соответствующих разделах.
46+
47+
### Связанные команды
48+
49+
- [browser.assertView][browser-command]
50+
- [element.assertView][element-command]
51+
52+
[html-reporter]: ../../html-reporter/html-reporter-setup
53+
54+
[looks-same]:[https://github.com/gemini-testing/looks-same]
55+
[browser-command]: https://testplane.io/docs/v8/commands/browser/assertView/
56+
[element-command]: https://testplane.io/docs/v8/commands/element/assertView/
+256
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,256 @@
1+
import Admonition from "@theme/Admonition";
2+
3+
# Скриншотное тестирование со Storybook
4+
5+
[Storybook][storybook] - это инструмент для разработки пользовательских интерфейсов на основе компонентов. Он позволяет разработчикам независимо визуализировать компоненты в различных состояниях в изолированной от остальных компонентов среде.
6+
Такой "шоурум" идеально подходит для скриншотного тестирования ваших компонентов, т.к. за счет этой изолированной среды такие тесты получаются в разы стабильнее и быстрее, чем вариант с e2e.
7+
8+
С помощью плагина [@testplane/storybook][testplane-storybook] предоставляется возможность автоматически проверять изменения ваших компонентов с помощью скриншотного тестирования.
9+
Вам достаточно описать ваш компонент в `Storybook`, а `testplane` при запуске автоматически сгенерит все необходимые тесты, прогонит их в нужных браузерах и предоставит визуальный отчет для обновления скриншотов.
10+
11+
## Как использовать? {#how_to_use}
12+
13+
### Шаг 1: Установка необходимых зависимостей
14+
15+
Если в Вашем проекте еще нет `Testplane`, то рекомендуем ознакомиться с разделом [quickstart][quickstart] или выполнить в директории Вашего проекта команду ниже:
16+
17+
```bash
18+
npm init testplane@latest
19+
```
20+
21+
Устанавливаем плагин для `testplane`
22+
23+
```bash
24+
npm install @testplane/storybook --save-dev
25+
```
26+
27+
### Шаг 2: Настройка плагина
28+
29+
Для работы плагина достаточно минимальной настройки - нужно просто объявить его в конфиге `testplane` без дополнительных опций:
30+
31+
```typescript
32+
// .testplane.conf.ts
33+
export default {
34+
plugins: {
35+
"@testplane/storybook": {},
36+
37+
// other Testplane plugins...
38+
},
39+
40+
// other Testplane settings...
41+
};
42+
```
43+
44+
### Шаг 3: Запуск тестов
45+
46+
Для запуска storybook-тестов необходимо добавить опцию `--storybook`. Опция `--update-refs` позволяет сохранить/обновить эталонные изображения через CLI:
47+
48+
```bash
49+
npx testplane --storybook --update-refs
50+
```
51+
52+
С помощью GUI-режима вы можете визуально оценить изменения в скриншотах, обновить их или перезапустить тесты:
53+
54+
```bash
55+
npx testplane gui --storybook
56+
```
57+
58+
Если в Вашем проекте используется Storybook версии 6.x, то в настройках Storybook необходимо включить сохранение json-файла с Вашими историями:
59+
60+
```typescript
61+
// .storybook/main.js
62+
export default {
63+
// ...
64+
features: {
65+
// ...
66+
buildStoriesJson: true,
67+
},
68+
};
69+
```
70+
71+
## Кастомные тесты {#custom_tests}
72+
73+
Некоторые компоненты перед скриншотом нужно привести в какое-либо состояние. Для этого у сторибука есть сущность под названием [play-функция][play-function]. Если она определена, мы сначала выполним все action-ы из нее, и только после этого сделаем скриншот.
74+
Если вам не хватает выразительности Storybook, то вы можете в самой "Истории" описать testplane-тест, который будет выполнен как дополнительный тест для компонента.
75+
76+
```typescript
77+
// stories/Primary.stories.ts
78+
import type { StoryObj } from "@storybook/react";
79+
import type { WithTestplane } from "@testplane/storybook";
80+
81+
export const Primary: WithTestplane<StoryObj> = {
82+
args: {
83+
primary: true,
84+
label: "Button",
85+
},
86+
testplane: {
87+
"my test": async ({ browser, expect }) => {
88+
const element = await browser.$(".storybook-button");
89+
90+
await expect(element).toHaveText("Button");
91+
},
92+
},
93+
};
94+
```
95+
96+
Также для теста можно добавить дополнительные настройки
97+
98+
```typescript
99+
// stories/Primary.stories.ts
100+
import type { WithTestplane } from "@testplane/storybook";
101+
import type { Meta, StoryObj } from "@storybook/react";
102+
103+
const meta: WithTestplane<Meta<typeof Button>> = {
104+
title: "Example/Button",
105+
component: Button,
106+
testplane: {
107+
skip: false, // if true, skips all Testplane tests from this story file
108+
autoscreenshotSelector: ".my-selector", // Custom selector to auto-screenshot elements
109+
browserIds: ["chrome"], // Testplane browsers to run tests from this story file
110+
assertViewOpts: {
111+
// override default assertView options for tests from this file
112+
ignoreDiffPixelCount: 5,
113+
},
114+
},
115+
};
116+
117+
export default meta;
118+
```
119+
120+
<Admonition type="warning">
121+
При добавлении testplane-тестов расширение Ваших story-файлов должно быть `.js` или `.ts`.
122+
</Admonition>
123+
124+
## Параметры конфигурации плагина
125+
126+
<table>
127+
<thead>
128+
<tr>
129+
<td>**Параметр**</td>
130+
<td>**Тип**</td>
131+
<td>**По&nbsp;умолчанию**</td>
132+
<td>**Описание**</td>
133+
</tr>
134+
</thead>
135+
<tbody>
136+
<tr>
137+
<td>enabled</td>
138+
<td>`Boolean`</td>
139+
<td>true</td>
140+
<td>Включить / отключить плагин.</td>
141+
</tr>
142+
<tr>
143+
<td>storybookConfigDir</td>
144+
<td>`String`</td>
145+
<td>".storybook"</td>
146+
<td>Путь к директории конфигурационного файла Storybook.</td>
147+
</tr>
148+
<tr>
149+
<td>autoScreenshots</td>
150+
<td>`Boolean`</td>
151+
<td>true</td>
152+
<td>Включить / отключить авто матическое скриншотное тестирование (будут выполняться только вручную описанные tetplane-тесты)</td>
153+
</tr>
154+
<tr>
155+
<td>localport</td>
156+
<td>`Number`</td>
157+
<td>6006</td>
158+
<td>Порт для запуска dev-сервера Storybook.</td>
159+
</tr>
160+
<tr>
161+
<td>remoteStorybookUrl</td>
162+
<td>`String`</td>
163+
<td>""</td>
164+
<td>Урл удаленного Storybook. Если указан, то локальный dev-сервер Storybook не будет запущен.</td>
165+
</tr>
166+
<tr>
167+
<td>browserIds</td>
168+
<td>`Array<String | RegExp>`</td>
169+
<td>[]</td>
170+
<td>Массив id браузеров, в которых будут запущены тесты. По умолчанию тесты будут запущены во всех браузерах, описанных в конфиге testplane</td>
171+
</tr>
172+
</tbody>
173+
</table>
174+
175+
Например, для запуска тестов на Storybook, опубликованном удаленно на `s3`, настройка будет выглядеть следующим образом:
176+
177+
```typescript
178+
// .testplane.conf.ts
179+
export default {
180+
plugins: {
181+
"@testplane/storybook": {
182+
remoteStorybookUrl: "https://yastatic.net/s3/storybook/index.html",
183+
},
184+
185+
// other Testplane plugins...
186+
},
187+
188+
// other Testplane settings...
189+
};
190+
```
191+
192+
## Дополнительные настройки {#extra_config}
193+
194+
В Вашем проекте уже могут быть настроены другие типы тестирования, запускающиеся с помощью `testplane`. Чтобы не смешивать сущности, мы рекомендуем для storybook-тестов использовать отдельный конфиг и указывать его при запуске тестов.
195+
196+
```bash
197+
npx testplane --storybook --config .testplane.storybook.conf.ts
198+
```
199+
200+
Сокращенная версия запуска
201+
202+
```bash
203+
npx testplane --storybook -c .testplane.storybook.conf.ts
204+
```
205+
206+
Отдельный конфиг позволит Вам описать хранение скриншотов сторибуков рядом с Вашим story-файлом:
207+
208+
```typescript
209+
// .testplane.storybook.conf.ts
210+
import path from "path";
211+
import { getStoryFile } from "@testplane/storybook";
212+
213+
export default {
214+
screenshotsDir: test => {
215+
const relativeStoryFilePath = getStoryFile(test);
216+
const relativeStoryFileDirPath = path.dirname(relativeStoryFilePath);
217+
218+
return path.join(relativeStoryFileDirPath, "screens", test.id, test.browserId);
219+
},
220+
// other Testplane settings...
221+
};
222+
```
223+
224+
В данном примере эталонные скриншоты будут сохранены в директории `screens/<testId>/<browserId>` относительно директории Вашего story-файла.
225+
226+
## Оптимизация запуска тестов {#optimize_run}
227+
228+
Storybook-тесты сами по себе довольно быстрые, т.к. для них не нужно сложное окружение, а на странице рендерится только один компонент.
229+
В контексте браузера 1 раз создается окружения для тестирования Storybook и переиспользуется от теста к тесту. Поэтому, для максимальной скорости прохождения тестов мы рекомендуем выставлять опцию [testsPerSession][tests-per-session] со значением не меньше 20, чтобы переиспользовать браузерную сессию как можно дольше:
230+
231+
```typescript
232+
// .testplane.storybook.conf.ts
233+
export default {
234+
testsPerSession: 40, // set value for all browsers
235+
236+
browsers: {
237+
"chrome-desktop": {
238+
testsPerSession: 50, // or set value for current browser
239+
},
240+
firefox: {
241+
// ...
242+
},
243+
},
244+
245+
// other Testplane settings...
246+
};
247+
```
248+
249+
Также, для storybook-тестов будет проигнорирована опция [isolation][isolation], чтобы не пресоздавать окружение на каджый тест (это никак не влияет на стабильность тестов).
250+
251+
[storybook][https://storybook.js.org]
252+
[testplane-storybook][https://github.com/gemini-testing/testplane-storybook]
253+
[play-function][https://storybook.js.org/docs/writing-stories/play-function]
254+
[quickstart]: ./quickstart/index
255+
[tests-per-session]: ./config/browsers/#tests_per_session
256+
[isolation]: ./config/browsers/#isolation

sidebars.ts

+6
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,12 @@ const sidebars: SidebarsConfig = {
2525
items: [{ type: "autogenerated", dirName: "config" }],
2626
link: { type: "doc", id: "config/main" },
2727
},
28+
{
29+
type: "category",
30+
label: "Visual testing",
31+
items: [{ type: "autogenerated", dirName: "visual-testing" }],
32+
link: { type: "doc", id: "visual-testing/visual-testing-intro" },
33+
},
2834
{
2935
type: "category",
3036
label: "Guides",

0 commit comments

Comments
 (0)