Mock Service Workerのドキュメントをざっくり眺めてみる

[Mock Service Worker(MSW)](https://mswjs.io/)が気になったので、ドキュメントを全体的にざっくり眺めてみます。
気になったところをピックアップします。

最新のドキュメント(ver2.0)はこちらですね。
https://mswjs.io

ver1.0の場合はこちら。
https://v1.mswjs.io/

GitHubのリポジトリはこちら。
https://github.com/mswjs/msw

# Introduction
対象のページはこちら。
https://mswjs.io/docs/

概要はこういったものでした。
* MSWはブラウザとNode.js向けのAPIモッキングライブラリ
* MSWはリクエストをインターセプト（傍受・観察）し、レスポンスを返却する
* 3つの特徴をもつ
    * 環境非依存 (Agnostic)
        * 環境、フレームワーク、ツールに依存しない設計
        * ブラウザやNode.jsで追加設定やプラグインなしで動作
        * `window.fetch()`やAxios、React Query、Apolloなど、どのリクエストクライアントとも互換性あり
    * シームレス (Seamless)
        * [Service Worker API](https://developer.mozilla.org/ja/docs/Web/API/Service_Worker_API)を使用し、ネットワークレベルでリクエストをインターセプト
        * `fetch`の上書きではなく、標準ブラウザAPIを活用してアプリケーションの整合性を保持
        * Node.jsではクラスの拡張を使用し、プロダクション環境に近いテスト環境を実現
    * 再利用可能 (Reusable)
        * APIモックをスタンドアロンレイヤーとして扱い、開発全体で再利用可能
        * 開発、統合テスト、エンドツーエンドテスト、Storybook、ライブデモなど、あらゆる場面で同じモックを使用可能
        * ネットワーク動作をカスタマイズして柔軟に対応できる

ブラウザ向け？というのに最初ピンと来ませんでしたが、Service Workerに関する理解とドキュメントを読み進めるにつれ、腑に落ちました。


https://developer.mozilla.org/ja/docs/Web/API/Service_Worker_API

https://developer.mozilla.org/ja/docs/Web/API/Service_Worker_API/Using_Service_Workers



# Getting started
https://mswjs.io/docs/getting-started

つぎはGetting started。ここではNode.jsのアプリケーションにMSWを統合するチュートリアルを示しています。

まずはライブラリのインストール。
```sh
npm install msw@latest --save-dev
```

次にリクエストを受け取れるようにハンドラーを書きます。
```js

// src/mocks/handlers.js
import { http, HttpResponse } from 'msw'

export const handlers = [
  http.get('https://example.com/user', () => {
    return HttpResponse.json({
      id: 'c7b3d8e0-5e0b-4b0f-8b3a-3b9f4b3d3b3d',
      name: 'John',
    })
  }),
]
```

handlersの配列にはREST or GraphQLなどの実装がかけると。
あとwebsocketもサポートしている。
記述はここから見ればいいですね。
| 種類 | ドキュメントリンク                                                |
|--------------------|------------------------------------------------------------------|
| REST              | https://mswjs.io/docs/network-behavior/rest             |
| GraphQL           | https://mswjs.io/docs/network-behavior/graphql       |
| WebSocket         | https://mswjs.io/docs/network-behavior/websocket   |




最後にIntegrate。
https://mswjs.io/docs/getting-started#step-3-integrate


```js
// src/mocks/node.js
import { setupServer } from 'msw/node'
import { handlers } from './handlers'
 
export const server = setupServer(...handlers)
```


```js
// src/index.js
import { server } from './mocks/node'
 
server.listen()
 
// This is a simple Node.js application that
// does a network request and prints the response.
async function app() {
  const response = await fetch('https://example.com/user')
  const user = await response.json()
  console.log(user)
}
 
app()
```

先に書いたハンドラーを`setupServer()`に渡します。
`server.listen()`をクライアントアプリの方に書いてますね。

これでチュートリアルは以上。

モヤッとしたのが、どうしてクライアントアプリ側に書くのでしょうか。

setupServerの振る舞いを示したドキュメントにヒントがありました。
https://mswjs.io/docs/api/setup-server

>The setupServer function acts as a bridge to apply the same request handlers in Node.js, where Service Workers cannot run. Instead, it augments the standard request modules like http in order to react to outgoing requests and respond to them from your mock definitions.

setupServer関数は、標準のリクエストモジュール（例: http）を拡張し、送信されるリクエストに反応するそうです。

今回の例はNode.jsアプリのIntegration exampleでしたが、ブラウザ、ReactNativeの例もあります。

| 対応環境         | リンク                                                         |
|------------------|----------------------------------------------------------------|
| Node.js          | https://mswjs.io/docs/integrations/node                       |
| Browser          | https://mswjs.io/docs/integrations/browser                    |
| React Native     | https://mswjs.io/docs/integrations/react-native               |


つぎはPhilosophy。

# Philosophy

ページはこちらですね。
https://mswjs.io/docs/philosophy

大きく4つのテーマについて書かれています。
* スタンドアロンレイヤーとしてのモッキング
* モックとネットワークの挙動
* プラットフォームの利用
* サーバーの視点

## スタンドアロンレイヤーとしてのモッキング

> We are convinced that API mocking deserves a layer of its own in your application. Being able to control the network any time and anywhere may come in handy in various situations, such as testing network-related code or reproducing and debugging a particular network scenario. Such level of control is simply impossible when using API mocking as a feature of any other tooling because you will always be limited by that tooling. There are no limits with MSW.


「APIモックはアプリケーション内で独立したレイヤーであるべき」だと主張しています。
この主張はチュートリアルにも反映されているなと気づきました。
さっきのチュートリアルでは、クライアントアプリの実行時に`server.listen()`が呼び出されていました。(=アプリケーション内で完結)
そしてモックの処理はディレクトリを新たにつくり、モジュール化していましたね。(＝独立したレイヤー)


また、ネットワークをコントロールできることにより、
ネットワーク関連のコードをテストしたり、特定のネットワークシナリオを再現してデバッグしたりといった様々な場面で便利になるだろう、といっています。

これほどまでにコントロールしているツールは他にないと。
ふむ。

## モックとネットワークの挙動

ドキュメントではMockという用語をあまりつかっていません、と。
歴史的に強い否定的イメージがあるらしい。
Network behaviorという用語を新たにつくったそう。


## プラットフォームの利用

モックツールを利用する際に、固有の書き方（構文や実装方法）を習得する必要がありましたが、MSWは最小限に抑えるように努力されているそうです。

MSWはWHATWG(Web Hypertext Application Technology Working Group) Fetch API 仕様を採用しています。

いわゆるFetch API。

これにより、インターセプトされたリクエストは実際のRequestインスタンスであり、モックレスポンスも実際のResponseインスタンスです。

## サーバーの視点

>When working with MSW, you will be writing request handlers to intercept and respond to requests. It’s important to approach those handlers from the server’s perspective since, effectively, you are describing how the server should behave in a particlar scenario.


サーバサイドの振る舞いを考慮して記述しましょう、という理解。以上。


つぎはComparisonへ。

# Comparison

ページはこちらです。
https://mswjs.io/docs/comparison

ここでは他のOSSモックツールとMSWを比較しています。

次の比較基準で記載されています。
* **対応しているAPIの種類**
  * このライブラリを使用して、どのような種類のAPIをモックできるのか？
  * （例：REST API、GraphQL、WebSocketなど）

* **対応環境**
  * ライブラリはどの環境で使用できるのか？
  * （例：ブラウザ、Node.js、React Nativeなど）

* **実装方法**
  * リクエストのインターセプトはどのように実装されているのか？
  * （例：Service Worker、モジュールのオーバーライド、プロキシなど）

* **統合の容易さ**
  * このライブラリをプロジェクトに統合するにはどれだけの労力が必要か？
  * （簡単にセットアップできるか、特定のツールやフレームワークが必要か）

* **モックの定義方法**
  * モックの定義はどのように行うのか？
  * （例：コードベース、JSONファイル、GUIなど）


個々の内容は必要になればみておくとします。

つぎはlimitationsです。

# limitations
ページはここ。
https://mswjs.io/docs/limitations

ブラウザの仕様によりMSWの機能が制限されることについて書かれています。

前述でも言及していますが、MSWはService Worker APIを使用することにより、リクエストをインターセプトしています。

Service Workerの挙動はブラウザ側にあり、JavaScriptによって回避することはできません。

これにより、Firefoxでは、ページ上で発生するXMLHttpRequestをService Workerに通知せず、インターセプトできないことがわかっています。

また、すべてのモダンブラウザとの互換性を100％保証することはできないので注意が必要であると。

各ブラウザでのService Worker APIの実装が異なる場合があり、これらについても考慮できないと。

# 所感

以上ということで、ざっと眺めてみましたが、

さらにちょっとコードもみてみました。
サービスワーカーを使用しているコードがこれですね。
https://github.com/mswjs/msw/blob/main/src/mockServiceWorker.js#L97C1-L121C3

[ServiceWorkerGlobalScopeのfetchイベント](https://developer.mozilla.org/ja/docs/Web/API/ServiceWorkerGlobalScope/fetch_event)などを使っていますね。
これらによりネットワークリクエストを傍受し、独自のレスポンスを送信できるようになると。なるほどー。

サーバ起動のモックだとCORSとか環境に関わる設定を実装する場合がありますが、いまみた感じだとそういった実装がなくなりますね。
それは恩恵の一つかも。

さて、↑でとりあげていないところは 大体Basics、Concepts、APIのところ。
詳細に書くことになりそうなので割愛。


実は配下の新人さんに触ってもらい、ちょっとした手助けになればと思い~~雑に~~かきました。



おわり :lemon: