LoginSignup
22
5

MSW 2.0 に更新した話

Last updated at Posted at 2023-12-24

この記事は、LITALICO Engineers Advent Calender 2023 シリーズ2の9日目の記事です。ただし、12月23日に投稿しています。

はじめに

LITALICO プロダクトエンジニアリング(PE)部の片桐英人(かたぎり えいと)です。

最近、仕事ナビのフロントエンドのテストや Storybook で使用している Mock Service Worker(msw)を 1.x から 2.0 に更新しました。仕事ナビのメンバーにそのことを伝えるために書いています。

image.png

この記事を記載している時点で、最新は、2.0.11 になっていますね…

Mock Service Worker (msw) とは?

Mock Service Worker(msw)1 は、Service Worker 2 を使って、HTTP リクエストとそのレスポンスをモックするための JavaScript のライブラリ(npm パッケージ)です。

MSW 2.0

MSW 2.0 は、2023年10月末にリリースされました 3。このリリースで、モックの定義方法など多くの破壊的な変更がありました。今回の更新で変更した変更点は、以下になります。記載していない変更方法については、1.x → 2.x を参照してください。

変更内容

import 内容の変更

MSW 1.x では、REST API のモックの定義に rest を使用していましたが、 MSW 2.0 では、http に変更されました。また、レスポンスを作成するための HttpResponse というクラスが必要になります。

変更前

import { rest } from 'msw';

変更後

import { http, HttpResponse } from 'msw';

handler の定義の変更

MSW 1.x から 2.0 では、REST API のモックする handler の定義方法が大きく変わりました。変更されて、簡単に定義できるようになっています。

変更前

(req, res, ctx) => {
  return res(ctx.json({ userId: 1 });
}

変更後

() => {
  return HttpResponse.json({ userId: 1 });
}

handler 内でクエリパラメータの取得

MSW 2.0 では、クエリパラメータを取得する場合は、handler のパラメータの info オブジェクトから params 要素を展開して取得するようになっています。

変更前

(req, res, ctx) => {
  const { user_id } = req.params;
  ...
}

変更後

({ params }) => {
  const { user_id } = params;
  ...
}

handler 内でリクエストボディの取得

MSW 2.0 では、リクエストボディを取得する場合は、handler のパラメータの info オブジェクトから request 要素を展開して取得するようになっています。

変更前

async (req, res, ctx) => {
  const body = await req.json();
  ...
}

変更後

async ({ request }) => {
  const body = await request.json();
  ...
}

レスポンスの HTTP ステータスの変更

レスポンスの HTTP ステータスを 200 以外にしたい場合は、HttpResponse の第2引数のオブジェクト内の status で指定します。

変更前

async (req, res, ctx) => {
  return res(ctx.status(500));
}

変更後

async () => {
  return new HttpResponse('Internal Server Error', { status: 500 });
}

更新時につまずいた点

更新中に色々なエラーが発生しました。いくつかは、「1.x から 2.x への移行ガイド」の "Frequent issues" に記載されているようにすれば、解決できました。

自分で試行錯誤して解決した点を説明します。

undici

移行ガイドで、ポリフィルを追加する際、"Make sure to install undici." なので、undici を追加する必要があります。今回の更新作業で msw 2.0.9 にする場合は、undici のバージョンが 5.28.2 にする必要がありました。undici の最新のバージョンは、6.2.1 なので、インストール時に注意が必要です。

$ yarn add -D undici@5.28.2

この時、undici というパッケージを追加する必要がありました。バージョンを 5.28.2 に固定する必要がありました。

$ yarn add -D undici@5.28.2

モックへのリクエストが止まる

jest を使ったテスト内で、MSW を使って API リクエストをモックしている箇所で、MSW 2.0 へ更新した後、止まってしまうようになってしまいました。

日時を固定するために以下のようにしている部分がありました。

jest.useFakeTimers({
   now: new Date('2023-12-09'),
});

ここの箇所をコメントアウトして、テストを実行すると失敗しますが成功するので、この辺りの部分が問題だろうということがわかりました。最終的には、

jest.useFakeTimers({
    doNotFake: ['queueMicrotask'],
    now: new Date('2023-12-09'),
});

とすることでテストの実行が止まることがなくなりました。理由が良くわかっていないので、機会がある時に調査したいと思います。

TypeError: Invalid base URL

MSW 2.0 に更新後、実行すると "TypeError: Invalid base URL:" というエラーが発生するテストがいくつかありました。バックトレースが以下のようになっていました。

TypeError: Invalid base URL:
  at new URLImpl (/.../node_modules/whatwg-url/lib/URL-impl.js:15:15)                           
  at Object.exports.setup (/.../node_modules/whatwg-url/lib/URL.js:54:12)                       
  at new URL (/.../node_modules/whatwg-url/lib/URL.js:115:22)
  at toAbsoluteUrl (/.../node_modules/@mswjs/interceptors/lib/node/chunk-5OKLCEIP.js:631:10)

このバックトレースを参考に辿っていくと@mswjs/interceptors/lib/node/chunk-5OKLCEIP.js の631行めの以下の箇所で location.href が空文字のためにエラーが発生していることがわかりました。

function toAbsoluteUrl(url) {
  if (typeof location === "undefined") {
    return new URL(url);
  }
  return new URL(url.toString(), location.href); // ここ
}

テストのコードを見直してみると以下のように location オブジェクトをモックしていました。

Object.defineProperty(window, 'location', {
  writable: true,
  value: {
     host: 'example.com',
     hostname: 'example.com',
     href: '',
     port: '',
     protocol: 'https:',
  },
});

この部分の href の箇所を https://localhost:3000/ などのように URL として正しい文字列を入れることで、更新前のようにテストが成功するようになりました。

ここでは、明示的に href を空にしていましたが、location オブジェクトをモックしている場合は、同様に href に正しい URL 文字列を入れる必要がありました。

さいごに

MSW 2.0 への更新には、 MSW の API の変更があり、多くの書き換えが必要あり、大変でしたが、新しい API の方が、書きやすくなり、MSW を使ったテストを書く効率が少し上がるのかなぁと思っています。これからも、本番だけでなく、開発やテスト使用するライブラリも積極的に更新していき、良いサービスの迅速に提供できる開発やテスト環境を整備していきたいと思います。

  1. https://mswjs.io/

  2. https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorker

  3. https://mswjs.io/blog/introducing-msw-2.0/

22
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
22
5