Storybookを用いてテストの可視化を進めた話

  • URLをコピーしました!

こんにちは、「PR TIMES Webクリッピング」の開発リーダーをしている小張です。

Storybookをユニットテストで活用している取り組みについて、紹介したいと思います。

目次

テスト文化と現状の課題

半年ほど前から社内にテストを書く文化が根づき始め、フロントエンドのユニットテストも増えてきました。

あわせて読みたい
t-wadaさん直伝・TDDワークショップを開催して、社内にテスト文化が芽生え始めた! こんにちは、バックエンドエンジニアの江間です。 先日、テスト駆動開発(TDD)の日本での第一人者として知られる和田卓人(@t_wada)さんをお招きして、オンラインでテス...

それに伴い他のメンバーが書いたテストを修正する機会が増えたのですが、修正が難しい場合には一時的にtest.todoとしたり、テストを書いた人に修正を依頼するなどの現象が発生していました。

テストの修正が難しい一因として、testing-libraryが行った画面操作を視覚で確認できないことがありました。そこで昨年導入したStorybookを使って、動作を画面で確認しながらテストを書いていく取り組みをはじめました。

Storybook導入当初の目的についてはこちらに詳しくまとめています。

あわせて読みたい
Storybookを導入した話 こんにちは。開発本部でインターンをしている桐澤です。インターンの業務では主にReactにリプレイスされたページのリファクタリングやコンポーネント修正を行ってきまし...

Storybookの活用

play function

Storybookには play function というinteractionをテストするための機能が備わっており、この関数にユーザーの操作を書くことで動作の確認ができます。

下記のようなStoryを作成して、play functionにテストしたい動作を記述します。

export const UncheckAll = {
  name: '全てのチェックを外せること',
  play: async ({ canvasElement }) => {
    const canvas = within(canvasElement);
    // 全てのチェックを外す
    await userEvent.click(
      canvas.getByRole('checkbox', { name: 'パブリシティ' }),
    );
    await userEvent.click(
      canvas.getByRole('checkbox', { name: 'パブリシティ転載' }),
    );
    await userEvent.click(
      canvas.getByRole('checkbox', { name: 'リリース原文転載' }),
    );
  },
} satisfies Story;

このStoryを表示するとInteractionsタブでplay functionの動作を確認できます!

さらにplay functionはUnitテストでも実行することができます。ここではPR TIMESでテストランナーとして採用しているvitestを使います。

具体的には、下記のようにcomposeStoriesで上記のStoryをテストファイルに読み込み、play functionの実行とアサーションを行います。

const { UncheckAll } = composeStories(stories);

it('全てのチェックを外せること', async () => {
  const { container, getByRole } = render(<UncheckAll />);
  await UncheckAll.play({ canvasElement: container });
  expect(getByRole('checkbox', { name: 'パブリシティ' })).not.toBeChe
  expect(
    getByRole('checkbox', { name: 'パブリシティ転載' }),
  ).not.toBeChecked();
  expect(
    getByRole('checkbox', { name: 'リリース原文転載' }),
  ).not.toBeChecked();
});

より詳細な書き方については以下の記事が非常に参考になります。

test-runnerとの比較

上記ではvitestの実行環境でテストを回していますが、Storybook公式からも @storybook/test-runner というjestベースの実行環境が提供されています。@storybook/jest と組み合わせることでアサーションまでplay function上で完結することが出来ます。

mock回りのサポートが弱いので採用は見送っていますが、今後のアップデートでmock関係の機能追加が入る可能性もあるようなので、注視していきたいです。

Storybook Blog
Storybook 7.0 Next-level component development and testing

We have a long list of quality of life improvements here that we’ll be rolling out in 7.x, especially around better mocking, full page testing, and compatibility.

https://storybook.js.org/blog/storybook-7-0/

デプロイ環境

当初mainブランチに対してGitHub Actionsを構築し、自動でStorybookがデプロイされる運用を行っていました。さらに現在ではPull RequestごとにStorybookのプレビュー環境を作成し、こちらもpushされたタイミングで自動デプロイが行われるようになっています。

デプロイが完了すると、Pull RequestにURLがコメントされるようになっています。

Storybookをテストで活用してみて

普段のプロジェクトでStorybookが書かれるようになった

Story fileの数が10 files(2023年1月)から、168 files(2023年4月)に増加しました。

これは今までデザインシステムに対してしか書かれていなかったStorybookが、プロジェクトごとのコンポーネントに対しても書かれるようになったためです。

単純な数だけでなく、Pull Requestに実装した箇所のStoryリンクを貼ったり、プロジェクトの進捗報告に使うなど、エンジニアを中心にStorybookを活用する場面が増えてきたと感じています。

コンポーネント駆動開発について

前述と関連するのですが、Storybookによってコンポーネント単位で進捗が把握できるようになりました。

コンポーネント実装を1チケットとして切りやすくなり、ご覧のようにPull Requestの単位がわかりやすくなっています。また、Storybookと一緒にテストも書かれることも増え、コンポーネント単位のUnitテストも増加しつつあります。

まとめ

play functionを使って、テストが可視化されデバッグが容易になりました。またStorybookを活用してコンポーネントにフォーカスした開発も行う動きが出てきました。

PR TIMESではフロントエンドはもちろんのこと様々な改善活動が行われているので、もしご興味ある方は、ぜひカジュアル面談でお話しできると嬉しいです。

株式会社PR TIMES
カジュアル面談申し込みフォーム - 株式会社PR TIMES 株式会社PR TIMESでは現在00-0. カジュアル面談(全職種OK)を募集しています。
  • URLをコピーしました!

この記事を書いた人

2021卒でフロントエンド開発を担当しています。

目次