🍧

Vitest Browser Modeがアツい

2024/07/17に公開

Background

これまでVitestでコンポーネントのテストを行う時は、jsdomhappy-dom を使ってブラウザ環境を偽装していました。しかし、偽のブラウザ環境を使うことは多くの問題があり、また開発者はテスト以外でどこにも存在しない環境を作り上げるという不毛な作業が必要でした。
この問題を解決するために、PlaywrightCypress などのテストフレームワークは Component Test をサポートしています。しかし、UnitテストでPlaywrightやCypressを使うのは少々Fatであり、Reactのhooksなどのテストをすることができません。

Vitest Browser Modeを使用することで、Vitest上でComponent Testが可能となり、これらの問題を解決できます。

Installation

Browser ModeのSetupは以下を参照してください。

https://vitest.dev/guide/browser/

Demo

Radix UIのTooltipを使った以下のコンポーネントに対してテストを書いていきます。

https://github.com/apple-yagi/vitest-browser-mode-example/blob/main/src/TooltipTest.tsx

vitestの設定を以下のようにし、拡張子がbrowser.test.tsxならBrowser Modeで実行し、jsdom.test.tsxならjsdomで実行するようにしています(初めてVitestのWorkspaceを利用しましたが便利)。

https://github.com/apple-yagi/vitest-browser-mode-example/blob/main/vitest.workspace.ts

jsdomを使った従来のテスト

https://github.com/apple-yagi/vitest-browser-mode-example/blob/main/src/TooltipTest.jsdom.test.tsx

注目ポイントは6行目のbeforeAllです。Radix UIのTooltipは内部で ResizeObserver を使用していますが、jsdomにはResizeObserverが実装されていません。そのため、以下のようにResizeObserverを簡単にmockしています。

https://github.com/apple-yagi/vitest-browser-mode-example/blob/09934d6c081ab411563e061b3893ef387b4af154/src/TooltipTest.jsdom.test.tsx#L6-L18

このようにjsdomに実装されていないWeb APIは自分でmockをしたり、polyfillを差し込んだりする必要があります。
また以下のようなsetupFileが必要で、環境構築をする際に大体の人はつまづくポイントだと思います。
https://github.com/apple-yagi/vitest-browser-mode-example/blob/main/setupTest.ts

Browser Modeを使ったテスト

https://github.com/apple-yagi/vitest-browser-mode-example/blob/main/src/TooltipTest.browser.test.tsx

Browser Modeでは上記のコードが何の設定もなしに動作します(手軽!)。
また、テスト実行時にはテスト対象のコンポーネントを実際にブラウザ上で確認することができます。

ブラウザ上でテストを実行すると、StorybookのPlay function のようにブラウザ上で実際にテストを実行している様子が伺えます(かなり高速に動いています)。

Speed

Browser Modeとjsdomでのテストの実行速度の差ですが、今回デモで使ったコンポーネントで20msほど差がありました。

環境 実行速度
Browser Mode 95ms
jsdom 75ms

これを大きいと見るか小さいと見るかは人それぞれだと思いますが、個人的には小さいと思っており、Browser Modeによる実行速度の劣化はあまり心配しなくても良いのではないかと思っています。

Finish

Browser Modeを使用することにより、テスト環境の構築(jsdomの設定など)が不要となり、リアルな環境でコンポーネントのテストをすることができるようになりました。個人的にはRadix UIのようなコンポーネントをテストする際に ResizeObserver など色々と不毛なmockを書くことが多かったので、そこら辺が解決され嬉しいです。

Discussion