第30回/nodejs なしでJSの単体テスト機能を追加する(Ajax通信のモックができるようにする)
Redmine に Hotwire を追加するための準備
Redmine には JavaScript の単体テストがない。一方で、Hotwire 追加時に単体テストが存在しないと移行が困難。
通常のJavaScript と ESモジュールが混在している環境でもテストができるようにした。
グローバルで jQuery を読みこみつつ、ESモジュールも使いたい、という環境に対応(nodejs を使ったテストでは、この辺をうまくやる方法が思い付かなかった)
Redmine の js の中では頻繁に ajax を行っている。単体テストでこうしたコードをテストする場合、sinon というモック用のライブラリを使うのが普通だった。 $.ajax メソッドや fetch 関数を偽装したオブジェクトを作成するためのライブラリ。
これは、ブラウザやnodejsのhttpリクエストをジャックしてあらかじめ決められた返答を返してくれるというもの。
偽装するのがhttpのレスポンスなので、クライアント側を jQueryによるajax から fetch API に変更してもモック側を修正する必要がない。
API の返答を偽装して、フロントエンド開発を進めるために使われている。
turbo stream の返答が返ってきたタイミングで動くJavaScript とかのテストがしやすくなると思う。
問題点
ライブラリをロードする他に、開発サーバのトップディレクトリに、"/mockServiceWorker.js" というファイルを置く必要がある。
"/assets/mockServiceWorker.js" とかに置いても良いけど、そうすると "/assets/" 以下に対するリクエストしか偽装できない。
importmap_mocha-rails を読みこんだときに、routing を追加することで解決。
単純にコントローラで js を返そうとすると ActionController::InvalidCrossOriginRequest が発生する。このケースに限って CSRF 検証をスキップする必要があった。
セットアップが成功すると [MSW] Mocking enabled. というメッセージが表示された。
gem に msw 対応を反映して push した。