Storybook 8.xのStorybookファイルをTesting Libraryで使用する

UIコンポーネントのカタログツールStorybookを使い、コンポーネントをセットアップする方法もある。StorybookはStoriesというファイルに「どのようなコンポーネントをStorybookに描画するか」を記載する。propsに応じて描画内容を出し分けることもできる1

このStoriesは次のように記載する。

import type { Meta, StoryObj } from "@storybook/react";
import BlogList from "./BlogList";

// Story自体の設定
const meta: Meta<typeof BlogList> = {
  title: "Table/BlogList", // Storyの区分け / Story名
  component: BlogList, // 使うコンポーネント名
  parameters: {
    layout: "centered", // 真ん中に配置
  },
  tags: ["autodocs"], // ドキュメンテーションあり
};

export default meta;
type Story = StoryObj<typeof BlogList>;

// DefaultがStory名
export const Default: Story = {
  args: { // 与えたいprops
    userList: [
        {
          id: 1,
          name: "user1",
        },
      ]
    }
  }

ポイントはargsの部分である2。このargsStory(UIコンポーネントを状態に応じてレンダリング仕分けたもの)ごとに「どのようなprops」を設定するか?記載する。

Storyで場面に応じたpropsを設定しているのだから、Storyを直接インポートしてテストを書けば二度手間にならずに済む。

また、開発初期段階でUIコンポーネントから先に準備したいときにも役立つ。テストが失敗した場合、Storybookを使えばUIコンポーネントの見た目や動作を実際確認できるためである。これはページを作る前にUIコンポーネントだけテストできるので、「残りはページのみ」という気持ちで取り組みやすくなる。

Testing Library側のインポート方法

StorybookはバージョンアップでダイナミックにAPIが変わる。そのため最新の情報は常にStorybookの公式ドキュメントを参照いただきたい。ここではStorybook 8.xのインポート方法を載せる。

StorybookのAPIcomposeStories()3を使うとStorybookからStoryをインポートできる。

// Reactのインポート
import React from "react";
// render関数のインポート
import { render } from "@testing-library/react";
// StoryをレンダリングするcomposeStories APIのインポート
import { composeStories } from '@storybook/react';
// StorybookのStoriesファイルからStoryを全部インポート
import * as Stories from './BlogList.stories';
// DefaultというStoryをデストラクチャリングで取り出して使えるようにする
const { Default } = composeStories(Stories);

it("Storyをインポートしてテストを動かす例", () => {
  // itブロック外でインポートしたStoryでレンダリングする
  const content = render(<Default />);
  // テキストが存在するか確認
  expect(content.getByText("記事ID")).toBeInTheDocument();
});

まず初めに、テスト対象のStoriesファイルからStoryをインポートする。インポート方法はいくつかあるが、本格的にテストを書く場合は全てインポートする方法が使いやすい。パターン分けしている分は何かしらテストを書いた方が良い場合がほとんどだからである。

インポートした後、composeStoriesAPIを使い、Storyを取り出す。すると、Testing Libraryがテストランナー上でコンポーネントをレンダリングする際Storyを指定できるようになる。propsはStoryのargsで設定しているため、その内容を使ってテストが動く。

Storyを状態に応じて分割しておくと、テストとStory名でどのような場面のどんな内容を検証したいのかを伝えやすくなる。デバッグもしやすい。

メリットが多いので基本的にはStoryを使って状態を表現しておきたい。ただ、StorybookのバージョンアップでAPIの破壊的な変更が入ることも多い。npx storybook migrateである程度機械的に作業すること・GitHub Copilotなども駆使して移植作業は半自動化してやると少しは楽になる。スケジュールが佳境な時にはバージョンアップしない方が良い。

また、過度に依存するとバージョンアップで疲弊するため、Storybook上で動作するテストは書かないようにしている。