Next.jsにnext/testmodeという概念が出現しMSW x Playwrightのテストがやりやすくなりそう
2023年8月15日にリリースされた Next.js v13.4.16から
next/experimental/playwright
next/experimental/playwright/msw
が登場してテストがしやすくなりそう。というお話です!
前提条件
今回お話するのは、Next.js の開発サーバーに対してMSWによりAPI通信をモックしてPlaywrightで行うブラウザテストのことをお話します
これまでは?
Page RouterかつCSRに関して言えば、MSWでモックすることは可能でした。exampleとしてすでに公式が提供しているので、これをベースにセットアップすれば可能です
現状の課題
Page Router
CSRの場合はブラウザ上のservice worker経由でmswが実行されています。なのでmswのserver.useを使うにはそこそこ工夫が必要です。
有志が作成したリポジトリの実装を見ると色々頑張ってるのがわかります
自分はPlaywrightの手動クッキー追加機能を工夫してmswで読み取っていい感じにハンドリングさせるようにしています
ただ単にjestでやってるような脳死でtestケースごとにserver.useを使うだけ、ということは難しいです
App Router
App Routerに関してはもっと根深い問題があります。詳しくは以下のMSWのIssueにありますが、超絶意訳すると、Next.jsの内部実装によってMSW側からじゃどうやってもモックできねぇ!!みたいなことを言っています。
何が起きたか
上記のissueを受けてv13.4.16から next.js側がmswを使っていい感じにモックしてくれる機能を提供するようになりました!!
next/experimental/testmode/playwright
および
next/experimental/testmode/playwright/msw
からimportし、利用可能です
個人的にここらへんのモックを今後どうしていこうかとうんうん悩んでいたのでこういった機能を提供してくれたのは非常に嬉しいです😭
実装されたPRは以下になります
まだExperimentalなのですが以下のような感じでmswを使ったモックサーバー経由でPlaywrightテストが実行可能です。以下は早速遊んでみたときのコードなのですが、確かにちゃんとモックされていました
※ただ、テストケースを回していると前のtestでオーバーライドしたresponseがリセットされていない?みたいな状態になったりしてて、ちょっと上手く動かせなかったです。単にコードがだめだったからなのかもしれないですが・・・まぁexperimentalですので長い目で見守りましょう!
これによってRSCでもtestケースごとにmsw.useを使ってresponseを変更し、エラーレスポンスの場合だったり、意図しないresponseだった場合のテストも行うことが可能になります!
※現在(2023年8月15日)のReact Testing LibraryではRSCでテストを行うことはできません(多分、react本家のreact-dom/test-utilsパッケージをいじくり回したらできそうだなとは思います)
つまり実質jestなどではRSCのコンポーネントをテストすることができず、コンポーネント実装を工夫する必要などがあります。
参考: RSCでのテストの考え方について良い解説がありました!
終わりに
個人的にPlaywrightのテストが大好きでこんな記事を書いちゃうくらいjest-domが嫌いなのですが、Next.jsがmswとplaywrightとの連携を考えてくれてて良かったなって思っています。Playwright大好き!!!ブラウザテスト最高!!!!
RSC時代のtest runnerについてのdiscussionがnext.jsリポジトリに上がっているので、ご意見がある人は是非コメントしてみてください
Next.jsは今後testmodeという概念を出してテストutilな機能をたくさん出していくんですかね?まだまだ始まったばかりなので今後の動向に注目ですね!
では!
参考: next/experimental/testmode/playwrightのドキュメント
Discussion
ついにApp RouterでもMSWが使えるように…。
「ただ、テストケースを回していると前のtestでオーバーライドしたresponseがリセットされていない?みたいな状態になったり」
環境は違いますが、Next.js+Vitestの環境で、手動でMockした関数の戻値がリセットされない、という現象に私も出くわしたので、何か上手く動いてない部分があるかもしれませんね…。