編集

Storybook 8.2

Storybook 8.2 がリリースされた。テスト機能の改善や、ポータブルストーリーの正式なサポートなどが行われた。 また Storybook 8.3 では、Vitest との統合や互換性の向上が予定されている。

https://storybook.js.org/blog/storybook-8-2/

#Portable stories

ポータブルストーリーを介することで、Story をネイティブコンポーネントとして Jest や Vitest、Playwright などで再利用が出来るようになった。

tsx
// Button.test.js
import { test, expect } from "vitest";
import { screen } from "@testing-library/react";
import { composeStories } from "@storybook/react";
import * as stories from "./Button.stories";

const { Primary, Secondary } = composeStories(stories);

test("renders primary button with default args", async () => {
  await Primary.play();
});

Vitest や Jest でポータブルストーリーを利用する方法についてドキュメントが公開されている。

https://storybook.js.org/docs/api/portable-stories/portable-stories-jest?ref=storybookblog.ghost.io

https://storybook.js.org/docs/api/portable-stories/portable-stories-vitest?ref=storybookblog.ghost.io

Storybook にテストの責務を持たせたくない場合や、Vitest や Jest の資産を利用したい場合など、非常に便利な機能である。

#New test hooks

Jest や Vitest、Playwright、Cypress などとより互換性のあるテストの記述が可能になった。

今まではcanvasオブジェクトを通してのみ Story のテストが可能であったが、mount メソッドが追加され他のテストフレームワークと比較的近い記述が出来るようになった。

tsx
// example.stories.tsx
import { fn, expect } from "@storybook/test";
// ...
export const Disabled = {
  args: { disabled: true, onSelected: fn() },
  play: async ({ mount, args }) => {
    // Arrange
    const user = useEvent.setup();
    const items = await loadItems(10);
    const canvas = await mount(<ToolbarMenu items={items} />);

    // Act
    await user.click(canvas.getByRole("button"));

    // Assert
    expect(canvas.getAllByRole("button").length).toBe(items.length);
    expect(args.onSelected).not.toHaveBeenCalled();
  },
};

beforeEachafterEachなどは、Story ファイルの meta に記述する。

jsx
// example.stories.tsx
const meta = {
  // ...
  async beforeEach() {
    MockDate.set("2024-02-14");

    // Reset the Date after each story
    return () => {
      MockDate.reset();
    };
  },
};

beforeAllafterAllは、.storybook/preview.tsに記述する。

tsx
// .storybook/preview.ts
import { Preview } from "@storybook/react";

import { init } from "../project-bootstrap";

const preview: Preview = {
  async beforeAll() {
    await init();
  },
};

export default preview;

https://storybook.js.org/docs/writing-tests/interaction-testing?ref=storybookblog.ghost.io#run-code-before-the-component-gets-rendered

個人的な感想としては、確かに名前が同じフックは生えたが、利用方法にはズレがあり、テストを CSF に変換するための学習曲線は変わらずあるように思う。

編集