本セッションの登壇者
セッション動画
スライド
よろしくお願いします。
Reactコンポーネントにおけるテスト手法のコンポーネントテスト手法の選択肢についてLTをさせていただきます。
まず自己紹介になります。サイボウズ株式会社のkintone Design TeamというチームでDesign Systemを作っているSakitoといいます。

今日話すことと話さないことなんですが、話すことは、React周辺ライブラリの最新情報とか交えたりとか、コンポーネントテストができるライブラリに触れつつ、コンポーネントテスト手法のあれこれについて話させていただきます。
話さないことについては、ユニットテストやインテグレーションテスト、E2Eテストなどの区分についての説明や、どう分けるかなど、そういったテスト設計の方法や詳しい実装方法、テクニックみたいなテストについての込み入った設計などには触れない予定です。

React Testing Library
さっそくですが、まずはReact Testing Libraryから紹介します。

React Testing LibraryはReactでテストを書いたことがある人は見たことがあると思うんですけど、Reactコンポーネントテストを書くライブラリです。JestとかVitestとかそういったテストランナーを使って、その中でjsdom上で動くっていう形になっています。
jsdomはNode.js上で動くものです。テストランナーを使用しなくても動きます。jsdomをグローバルに入れて動かすこともできます。jsdomを使ってNode.js上でエミュレートするので、ブラウザ上で再現するよりも実行速度が速いものになってます。
あとeslint-plugin-testing-libraryというのもあります。React Testing LibraryにはいろいろなAPIがあるんですけど、「こういう場合はこう使うべき」などお作法みたいなところもあって、docsを読めばだいたいわかるのですが、eslint-plugin-testing-libraryを使っておくとそのへんを怒ってくれるのでオススメです。
a11yを担保する
React Testing Libraryを使うと、a11yについても担保するような書き方ができます。DOMを取得する方法をgetByRole優先にすることで、a11yの担保をしつつテストを書くことができます。
なので、ロールが変わったりしてしまったらテストが落ちるというテストが書けます。ただし、すべての場合に当てはまるわけではなくて、いろいろなDOMを取得する方法があり、公式ドキュメントには「こういう場合はこれがオススメだよ」というPriorityの項があるので、それを見るのがオススメです。

React Testing Library v13
ここから最新の情報なんですけども、React Testing Libraryのv13は、React v18に合わせて3月ごろにリリースされました。
React 17以前のサポートが切れたんですよね。これを使うことで、React 18はできるんですけど、React 17以降のサポートが切れているので、インストールするときにPeerDependenciesのほうで怒られると思うので、気を付けてください。
あとReact Hooks単体をテストするReact Testing Library Hooksがあります。Render Hookという関数を使って、コンポーネントがなくても、React Hooksの関数自体を単体でテストできるものが、React Testing Libraryに入っています。
React Testing LibraryのNativeで使う方にもRender Hookが追加されてて、React Hooks Testing Libraryはなくなる可能性(=Deprecate)が高いと言われています。

CypressとPlaywright
続いて、CypressとPlaywrightです。
Cypress、Playwrightは、ブラウザ上で動かすテストツールになります。コンポーネント単体でのテストができるようになってきています。
Cypressは2022年6月にリリースされました。v10でベータとして使用できます。Playwrightは2022年5月にリリースされ、v1.22.0以降でExperimentalな機能として使用できます。

両方とも「まだ正式に使える状態ではないよ」という状態です、Cypressはけっこう前からExperimentalで入ってて最近ベータになって、APIがいろいろ変わったりするので、使う場合は気を付けた方がいいです。こういうことができるようになってきているということを覚えておくといいと思います。
サーバサイドと合わせたテストをするE2Eフレームワークとして覚えられるものなんですけど、E2Eはどこまでできるかというと単にブラウザ上で実行できるフレームワークという役割になってきているのかなと思っています。
こんな感じ(下図)でCypressなどを使うと、コンポーネントのテストができます。詳しくは解説ページを見てください。

jsdomとブラウザ上で実行する違い
jsdomとブラウザで実行する違いは実行環境です。
jsdomはレイアウトに関するAPIが使えないので、基本的なコンポーネントの機能テストはReact Testing Libraryで担保して、レイアウトや、ファイルの送信系/表示系などをテストしたい場合は、CypressやPlaywrightを使うようにすると、スクロールしたときに何か表示するといったことができます。
なので、使い分けが大事だと思います。ブラウザのネイティブ機能に対するモックの必要もなくなるので、テストの信頼度が上がったりコードの簡略化になると思います。

Storybook
次は、Storybookの活用になります。
Storybookの概要は、だいたいコンポーネントカタログとして覚えている人が多いと思うんですけど、最近はテストができるようになってきています。

@storybook/testing-react
@storybook/testing-reactというものを使うと、Storybook上に定義したひとつひとつのストーリーを使用してコンポーネントのテストができるようになっています。ストーリーで状態が見えるようにしているので、それに対してテストができるということです。
あとは、@storybook/testing-libraryというものが出てて、ストーリーひとつひとつに対して、testing-libraryを混ぜ合わせるというラップされたものになってます。

こんなふうに書けます。

左にストーリーがあって、たとえばコンポーネントのdisabled状態を表現しているのと、普通に表現しているのがあって、それをそのままストーリーに使うことによって、クリックできるかクリックできないかをストーリーに対してテストできます。
Interaction Testing
次はInteraction Testingです。Storybook上で動作を再現できるテストになります。@storybook/testing-libraryと@storybook/addon-interactionsを使用してplay関数を使うとできます。FocusやActive状態の確認や複雑なコンポーネントの動作を再現することで、コンポーネントの仕様がわかるようになります。

Interaction Testingはこういう感じにplay関数で囲んであげると「これが通ったよ」「この動作が通ったよ」というのを再現してくれます。なので、ストーリーを開いた瞬間にフォーカスが当たっている状態を確認することができます。

こういったものを使って、ログインフォームやページ丸ごとをレンダリングして使っている人もいるので、そういったページのUX動作やコンポーネント仕様などハッピーパスみたいなものを担保することができます。

@storybook/test-runner
@storybook/test-runnerを使うことで、Storybook上のコンポーネントテストをnpm scriptで全部動かすことができます。これはCIでももちろん動きます。中ではJestとPlaywrightが使われてます。

Interaction Testがあるものは、Interaction Testが通らなければ落ちるようになっていて、Storybookに対する一種のブラウザ上のコンポーネントテストができます。Interaction Testがないものは、ストーリーがレンダリングできるか検証されるので、Smoke Test、いわゆる起動が確認できるテストになります。
まとめ
今回は時間がないので、割愛したものを以下に挙げておきます。

こういった武器を使って、コンポーネント設計の観点を増やして、コンポーネントやアプリケーションの性質・状況に合わせて使っていくのがいいと思います。

終わります。ありがとうございました。