🔩
Storybook Test-Runner の Play 関数で Visual Test と Snapshot Test をする
Visual Test と Snapshot Test はフロントエンドで大事なことです。Storybook の Test-Runner が コンポーネントの Story をテストケースとして、作動正確性を確認できるものです。我々は Test-Runner を使って、コンポーネントの状態に基づいて視覚と DOM の変更範囲を確保しています。この文は Storybook Test-Runner で、Play Function の中で Visual Test と Snapshot Test の使い方について紹介しいたします。
問題点
Storybook の文書が Visual Test (Image Snapshot) と Snapshot Test (HTML Snapshot) を触れたが、postVisit
の時点は作動終わった時ですから、状態に基づけませんでした。
解決策
コードがこのリポジトリにあります。
preVisit
で、Window オブジェクトに Snapshot 関数を追加します。
// .storybook/test-runner.ts
import { type TestRunnerConfig } from "@storybook/test-runner";
import { toMatchImageSnapshot } from "jest-image-snapshot";
const config: TestRunnerConfig = {
setup() {
expect.extend({ toMatchImageSnapshot });
},
async preVisit(page) {
if (await page.evaluate(() => !("takeSnapshot" in window))) {
await page.exposeBinding("takeSnapshot", async ({ page }) => {
const elementHandler = await page.$("#storybook-root");
const innerHTML = await elementHandler?.innerHTML();
expect(innerHTML).toMatchSnapshot();
});
}
if (await page.evaluate(() => !("takeScreenshot" in window))) {
await page.exposeBinding("takeScreenshot", async ({ page }) => {
const image = await page.locator("#storybook-root").screenshot();
expect(image).toMatchImageSnapshot();
});
}
},
};
export default config;
そして、Play 関数で Snapshot 関数を呼び出します。
import type { Meta, StoryObj } from "@storybook/react";
import { expect, fn, userEvent, within } from "@storybook/test";
import { Button } from "./Button";
const meta: Meta<typeof Button> = {
title: "Button",
component: Button,
};
export default meta;
type Story = StoryObj<typeof Button>;
export const Primary: Story = {
args: {
onClick: fn(),
},
play: async () => {
await window.takeSnapshot?.();
await window.takeScreenshot?.();
// 何回でも呼び出せます
},
};
Prepare で追加しない理由
Prepare では expect
はまだ注入しませんので、呼び出せません。
...
const config: TestRunnerConfig = {
async prepare({ page, browserContext, testRunnerConfig }) {
...
// default prepare
...
// expose takeSnapshot
await page.exposeBinding("takeSnapshot", async ({ page }) => {
const elementHandler = await page.$("#storybook-root");
const innerHTML = await elementHandler?.innerHTML();
expect(innerHTML).toMatchSnapshot();
});
},
...
expect
関数は setup
から使えます。だか、setup
は引数がない関数です。
終わりに
テスト環境を設定していたとき、コンポーネントの最終状態だけではなく、中間状態も確保してほしいでした。どうやってコンポーネントの中間状態をテストするかを探して、この方法を見つけました。
Discussion