📘

MSW+Storybookを使った際のconsole.warnの適切な消し方

2023/01/18に公開

背景

最近はMSWとStorybookを使ってフロントエンド開発をしている人をちらほら見かけます。かくいう僕も採用して開発を進めています。とても便利で素晴らしいライブラリです。一方、

このようにStorybookを開いた際、コンソールがwarningで埋め尽くされてしまうことがあります。これはMSWが「ハンドラに登録されていないURLへのアクセスしてるけど大丈夫?」って教えてくれてます。ただ、node_modulesへのアクセスとかをintercept & mockしなければいけないユースケースなんてあんま思いつきませんし、大半が必要ないwarningになります。
一方、warningの消し方について検索してみると、

browser.ts
worker.start({
  onUnhandledRequest: 'bypass',
})

のように設定すればwarningが消えると書いてある記事がいくつかありました。MSWの公式には

https://mswjs.io/docs/api/setup-worker/start#onunhandledrequest

Performs an unhandled request as-is.

このように書いてあります。つまり、unhandled requestをそのまま通すということです。

僕はおっちょこちょい

これで十分な方はいいのですが、実は僕おっちょこちょいで、関数をMSWのhandlerに登録するのを忘れたままコンポーネントをStorybook上で確認するも、mockデータが返ってこなかった経験があります(あたりまえ)。この時、コンソールに表示されていたwarningを見ると、MSW君が「お前、登録してないURLにpostしてるけど、大丈夫?」って教えてくれ(先ほどのwarning)、助けてもらった経験があります。

要件

何が言いたいかというと、

  • こちらが意図してmockしていないリクエストはwarningを出さずに、
  • 意図していないものに関してはwarningは継続して出してほしい
    を実現したかったです。このためには、bypassでは不十分なことが分かります。

調査結果

先ほどのMSWの公式Documentの少し下に、Custom callbackというものがあります。

When passed a function as a value of this option, the library executes that function whenever an unhandled request occurs. The behavior of such unhandled request won't be affected, but can be prevented if the custom callback function throws an exception.

まず先ほどのonUnhandledRequestの型を確認すると、

onUnhandledRequest?: UnhandledRequestStrategy;

また、UnhandledRequestStrategy及びUnhandledRequestCallback

declare type UnhandledRequestStrategy = 'bypass' | 'warn' | 'error' | UnhandledRequestCallback;
declare type UnhandledRequestCallback = (request: MockedRequest, print: UnhandledRequestPrint) => void;

と定義されています。(もっと詳しく知りたい方は自分で見てください。)
UnhandledRequestCallbackは、第一引数にリクエストの詳細情報、第二引数にコンソールへの表示方法を選べる関数を持つオブジェクト(?)を受け取ります。
つまり、リクエストの中身を見ながらwarningを出すかどうかを決めれます。

コード

browser.ts
worker.start({
  onUnhandledRequest(req, p) {
    const hiddenWarningPattern = new RegExp('/node_modules/', 'g');
    if (hiddenWarningPattern.test(req.url.href)) {
      return;
    }
    p.warning();
  },
})

のように書き換えることが出来ます。今回はnode_modulesに関してはwarningを出さないようにしました。正規表現に関しては自分で好きな形を選んでください。また、Storybook上では、preview.jsからMSWをinitializeしていることが多く、initializeはworker.startと同じ引数を取るため、

preview.js
initialize({
  onUnhandledRequest(req, p) {
    const hiddenWarningPattern = new RegExp('/node_modules/', 'g');
    if (hiddenWarningPattern.test(req.url.href)) {
      return;
    }
    p.warning();
  },
});

このような形に書き換えられます。

Discussion