Skip to content

Commit b2d2b2e

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

File tree

4 files changed

+344
-0
lines changed

4 files changed

+344
-0
lines changed

blog/storybook-testing.mdx

Lines changed: 26 additions & 0 deletions
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
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
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+
```typescript
19+
await browser.assertView(state, options);
20+
await browser.assertView(state, selector, options);
21+
await element.assertView(state, options);
22+
```
23+
24+
Команда `assertView` доступна как в контексте браузера, так и в контексте найденного элемента. Набор аргументов при этом отличается:
25+
26+
```typescript
27+
it("check search view", async ({browser}) => {
28+
// ...
29+
30+
// taking screenshot of the current viewport
31+
await browser.assertView("viewport-screen");
32+
33+
// taking screenshot of a specific element (from the browser context)
34+
await browser.assertView("any-state-name", ".DocSearch", opts);
35+
36+
const searchInput = await browser.$(".DocSearch");
37+
await searchInput.click();
38+
39+
// taking screenshot of a previously found item (from the element context)
40+
await searchInput.assertView("any-state-name");
41+
});
42+
```
43+
44+
Подробнее о возможностях команды `assertView` читайте в соответствующих разделах.
45+
46+
### Связанные команды
47+
- [browser.assertView][browser-command]
48+
- [element.assertView][element-command]
49+
50+
51+
[html-reporter]: ./html-reporter/html-reporter-setup
52+
[looks-same]:[https://github.com/gemini-testing/looks-same]
53+
[browser-command]: https://testplane.io/docs/v8/commands/browser/assertView/
54+
[element-command]: https://testplane.io/docs/v8/commands/element/assertView/
Lines changed: 258 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,258 @@
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+
12+
## Как использовать? {#how_to_use}
13+
14+
### Шаг 1: Установка необходимых зависимостей
15+
16+
Если в Вашем проекте еще нет `Testplane`, то рекомендуем ознакомиться с разделом [quickstart][quickstart] или выполнить в директории Вашего проекта команду ниже:
17+
18+
```bash
19+
npm init testplane@latest
20+
```
21+
22+
Устанавливаем плагин для `testplane`
23+
24+
```bash
25+
npm install @testplane/storybook --save-dev
26+
```
27+
28+
### Шаг 2: Настройка плагина
29+
30+
Для работы плагина достаточно минимальной настройки - нужно просто объявить его в конфиге `testplane` без дополнительных опций:
31+
32+
```typescript
33+
// .testplane.conf.ts
34+
export default {
35+
plugins: {
36+
'@testplane/storybook': {},
37+
38+
// other Testplane plugins...
39+
},
40+
41+
// other Testplane settings...
42+
}
43+
```
44+
45+
### Шаг 3: Запуск тестов
46+
47+
Для запуска storybook-тестов необходимо добавить опцию `--storybook`. Опция `--update-refs` позволяет сохранить/обновить эталонные изображения через CLI:
48+
49+
```bash
50+
npx testplane --storybook --update-refs
51+
```
52+
53+
С помощью GUI-режима вы можете визуально оценить изменения в скриншотах, обновить их или перезапустить тесты:
54+
55+
```bash
56+
npx testplane gui --storybook
57+
```
58+
59+
Если в Вашем проекте используется Storybook версии 6.x, то в настройках Storybook необходимо включить сохранение json-файла с Вашими историями:
60+
61+
```typescript
62+
// .storybook/main.js
63+
export default {
64+
// ...
65+
features: {
66+
// ...
67+
buildStoriesJson: true
68+
}
69+
}
70+
```
71+
72+
## Кастомные тесты {#custom_tests}
73+
74+
Некоторые компоненты перед скриншотом нужно привести в какое-либо состояние. Для этого у сторибука есть сущность под названием [play-функция][play-function]. Если она определена, мы сначала выполним все action-ы из нее, и только после этого сделаем скриншот.
75+
Если вам не хватает выразительности Storybook, то вы можете в самой "Истории" описать testplane-тест, который будет выполнен как дополнительный тест для компонента.
76+
77+
```typescript
78+
// stories/Primary.stories.ts
79+
import type { StoryObj } from "@storybook/react";
80+
import type { WithTestplane } from "@testplane/storybook"
81+
82+
export const Primary: WithTestplane<StoryObj> = {
83+
args: {
84+
primary: true,
85+
label: "Button",
86+
},
87+
testplane: {
88+
"my test": async ({browser, expect}) => {
89+
const element = await browser.$(".storybook-button");
90+
91+
await expect(element).toHaveText("Button");
92+
}
93+
}
94+
};
95+
```
96+
97+
Также для теста можно добавить дополнительные настройки
98+
99+
```typescript
100+
// stories/Primary.stories.ts
101+
import type { WithTestplane } from "@testplane/storybook"
102+
import type { Meta, StoryObj } from "@storybook/react";
103+
104+
const meta: WithTestplane<Meta<typeof Button>> = {
105+
title: "Example/Button",
106+
component: Button,
107+
testplane: {
108+
skip: false, // if true, skips all Testplane tests from this story file
109+
autoscreenshotSelector: ".my-selector", // Custom selector to auto-screenshot elements
110+
browserIds: ["chrome"], // Testplane browsers to run tests from this story file
111+
assertViewOpts: { // 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+
## Полезные ссылки {#useful_links}
252+
253+
[storybook][https://storybook.js.org]
254+
[testplane-storybook][https://github.com/gemini-testing/testplane-storybook]
255+
[play-function][https://storybook.js.org/docs/writing-stories/play-function]
256+
[quickstart]: ./quickstart/index
257+
[tests-per-session]: ./config/browsers/#tests_per_session
258+
[isolation]: ./config/browsers/#isolation

sidebars.ts

Lines changed: 6 additions & 0 deletions
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)