Vue3 のプロジェクトで Mock Service Worker を利用してみた

[Mock Service Worker](https://mswjs.io/)はネットワークレベルでリクエストを傍受するライブラリ。

モックについて意識せずに実装したりテストを書いたりすることができる。

以下のネイティブモジュールを拡張したりパッチを当てたりして[実現されている](https://github.com/mswjs/interceptors#what-this-library-does)。

- `http.get/http.request`
- `https.get/https.request`
- `XMLHttpRequest`
- `fetch`

## 導入してみる

以下の構成の プロジェクトに導入してみる。

-   Vue3（VueCLI + Webpack）

### 準備

```sh
yarn add -D msw
```

public ディレクトリにモックを利用するための自動生成のコードを入れる

```
npx msw init public/ --save
```

※ `public/mockServiceWorker.js` というファイルが自動生成される。

### モックするためのコードを書いていく

各リクエストに対してレスポンスの値を定義していく。

- リクエストに応じて異なった値を返すことができる
- ステータスコードを変更することができる（異常系の動作確認ができる）

```ts
import { rest, setupWorker } from "msw";

const handlers = [
    rest.post("/api/insert/:campaignUuid", (_req, res, ctx) => {
        return res(
            ctx.status(200),
            ctx.json({
                resultCode: "00101",
                entryUuid: "6875afab-82d4-4e31-88c6-60201c037b45",
            })
        );
    }),
    rest.get("/api/users/:campaignUuid", (_req, res, ctx) => {
        return res(
            ctx.status(200),
            ctx.json({
                resultCode: "00101",
                dataJson: {
                    isFriend: true,
                },
            })
        );
    }),
    ...
];

export const worker = setupWorker(...handlers);
```

ローカル環境のときに `worker.start()` を呼び出すようにする。

```ts
if (process.env.NODE_ENV === 'development') {
    const { worker } = require("./utils/mock_api_handler");
    worker.start();
}
```

### 動作確認

ブラウザの検証ツールに、実際に API サーバにリクエストされているかのように表示される。

![スクリーンショット 2023-01-24 21.27.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/676183/9b34fc1c-38a4-f26b-89aa-219242237faf.png)

レスポンスの値も確認できる。

![スクリーンショット 2023-01-24 21.27.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/676183/9ea8ed53-daa5-e53f-6858-b83106e166c4.png)

### 導入で苦戦したところ

`yarn serve` したときに以下のようなエラーが発生した。

```log
 ERROR  Failed to compile with 2 errors                                                                                                                                                                                     1:13:17

 error  in ./node_modules/strict-event-emitter/lib/Emitter.js

Module parse failed: Unexpected token (14:10)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
|  */
| class Emitter {
>     events;
|     maxListeners;
|     hasWarnedAboutPotentialMemortyLeak;

 @ ./node_modules/strict-event-emitter/lib/index.js 17:13-33
 @ ./node_modules/msw/lib/index.js
 @ ./src/utils/mock_api_handler.ts
 @ ./src/main.ts
 @ multi (webpack)-dev-server/client?http://192.168.2.102:8080&sockPath=/sockjs-node (webpack)/hot/dev-server.js ./src/main.ts

 error  in ./node_modules/strict-event-emitter/lib/MemoryLeakError.js

Module parse failed: Unexpected token (5:11)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
| exports.MemoryLeakError = void 0;
| class MemoryLeakError extends Error {
>     emitter;
|     type;
|     count;

 @ ./node_modules/strict-event-emitter/lib/index.js 18:13-41
 @ ./node_modules/msw/lib/index.js
 @ ./src/utils/mock_api_handler.ts
 @ ./src/main.ts
 @ multi (webpack)-dev-server/client?http://192.168.2.102:8080&sockPath=/sockjs-node (webpack)/hot/dev-server.js ./src/main.ts
```

Mock Service Worker が利用している `strict-event-emitter` というライブラリの読み込みがうまくいっていなかった。

（適切な修正方法かわからないが）自分の環境では `vue.config.js` に以下を追記することで解消できた。

```js
module.exports = {

  ...

  transpileDependencies: ['strict-event-emitter'],
}
```



## Mock Service Worker を利用してみてよさそうだと思ったところ

-   **簡単に導入できる**
    -   ほとんどモックされる API の情報を書くだけで利用できるようになる
    -   モックを導入するための準備がないプロジェクトにも簡単に導入できる
-   **動作確認できる範囲（モックされない範囲）が広がる**
    -   axios でリクエストされるところまで動作確認できる（たとえば、axios の使い方が間違っていたときにそれに気づくことができる）
    -   リクエストでエラーになったときの動作を確認できる
    -   検証ツールでリクエストの様子を確認できる
- OpenAPI からのコードも自動生成しやすそう
- [さまざまなケース](https://mswjs.io/docs/recipes)で利用できそう