BEサーバーを通さず、FEをテストする方法

# サービスワーカーとは何ですか？
サービスワーカーは、ウェブアプリケーション、ブラウザ、および（利用可能な場合）ネットワーク間のプロキシサーバーとして機能します。サービスワーカーは、ソースとパスについて登録するイベントベースのワーカーであり、JavaScriptファイルの形式を取ります。サービスワーカーは関連するウェブページ/サイトを制御し、ナビゲーションとリソースリクエストを傍受して修正し、リソースを非常に詳細にキャッシュすることができます。これにより、ウェブアプリがどのような状況でどのように動作するかを完全に変更することができます **（最も代表的な状況はネットワークが使用できない場合です)**。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3824062/2fc6e6ea-a381-bc94-c5a8-51cc3fc64558.png)

# サービスワーカーのライフサイクル

1. ダウンロード
2. インストール
3. アクティベーション

ユーザーがサービスワーカーが制御するサイト/ページに初めてアクセスする瞬間、サービスワーカーは即座にダウンロードされます。

サービスワーカーのアップデートは以下の場合に発生します。

範囲内のページへのナビゲーションが発生した場合
サービスワーカーでイベントが発生したが、サービスワーカーが過去24時間以内にダウンロードされていない場合
ダウンロードしたファイルが新しいバージョンである場合、サービスワーカーのインストールが試みられます。バージョンの比較は、既存のサービスワーカーファイルとのバイト単位の比較結果を使用します。このページ/サイトでサービスワーカーが初めて見つかった場合も「新しいバージョン」として扱われます。

既存のサービスワーカーが存在する場合、新しいバージョンはバックグラウンドでインストールされますが、まだアクティブにはなりません。この時点のワーカーを待機中のワーカーと呼びます。待機中のワーカーは、前のバージョンのサービスワーカーを使用しているページがすべて閉じられた場合にアクティブになり、アクティブワーカーになります。

> Reference https://developer.mozilla.org/ko/docs/Web/API/Service_Worker_API

# サービスワーカーの利用例
- バックグラウンドデータの同期。
- 他のソースからのリソースリクエストに応答。
- 位置情報やジャイロセンサーなど、計算コストが高い多数のページで共用できるようにデータ更新を集中管理。
- 開発目的として、CoffeeScript、Less、CJS/AMDモジュールなどの依存関係管理とコンパイル。
- バックグラウンドサービスフック。
- 特定のURLパターンに基づいたカスタムテンプレートの提供。
- パフォーマンスの向上。写真アルバムの次の数枚の写真など、ユーザーが必要とするリソースのプリフェッチなど。
- バックグラウンド同期：サイトにユーザーがいないときにサービスワーカーを稼働させ、キャッシュを更新するなどの作業を実行。
- プッシュメッセージに対応：サービスワーカーを稼働させ、新しいコンテンツが利用可能であることをユーザーに通知するメッセージを送信。
- 特定の時間や日時に反応。
- ジオフェンスへの侵入。（=実際の地形に区画された仮想的な半径）

# Web WorkerとService Worker
## 共通点
- 追加スレッドで実行されるため、メインスレッドをブロックせずに実行できる。
- WindowやDocumentオブジェクトにアクセスできないため、DOMと直接的に対話できず、ブラウザーAPIへのアクセスに限定される。
## 違い
- サービスワーカーは、fetchイベントのようなネットワークリクエストを傍受したり、Push APIのようなpushイベントをリッスンできる。
- ページはいくつかのWeb Workerを生成できるが、単一のサービスワーカーは登録されたスコープ内のすべてのアクティブタブを制御する。
- Web Workerの寿命は所属するタブと密接に結びついているのに対し、サービスワーカーの寿命は独立している。そのため、Web Workerが実行中のタブを閉じるとWorkerが終了するが、サービスワーカーはアクティブタブが開かれていなくてもバックグラウンドで実行され続ける。

# Web Worker
Web Workerは主にUIブロックを避けるために、重い計算が必要な作業（AI、ゲーム、画像エンコーディングなど）を補助スレッドで実行するために使用される。

# Service Worker
サービスワーカーは一般的にネットワークプロキシのような役割やバックグラウンド作業、キャッシュ、オフライン処理に使用される。

# MSW
MSW(Mock Service Worker)は、サービスワーカー（Service Worker）を使用してネットワーク呼び出しを傍受するAPIモックライブラリです。

https://mswjs.io/

比較的新しく導入されたWeb標準技術であるサービスワーカーを使用すると、ブラウザからのリクエストやレスポンスを途中で監視、改変、キャッシュするなど、従来のWebではできなかった追加作業が可能になります。

MSWはこのサービスワーカーの能力を最大限に活用し、Web開発におけるAPIモックのレベルを一段階引き上げたと評価され、発売直後から大きな反響を呼びました。

## MSWを利用した開発事例
バックエンド開発とフロントエンド開発が同時に行われる場合。
テスト実行時に実際のバックエンドAPIにネットワーク呼び出しを行う代わりに、より高速で安定した偽のAPIサーバーを構築するため。

つまり、偽のAPIを実際のAPIに置き換えることが容易であり、それだけフロントエンドプロジェクトの開発生産性が向上することを意味します。

ライブラリは非常に柔軟に設計されているため、開発用にブラウザ環境でサービスワーカーとして動かす場合でも、テスト用にNode.js環境でJestやCypressなどのテストランナーで動かす場合でも、同じリクエストハンドラーコードを共有して使用できます。

REST APIモックとGraphQL APIモックの両方をサポートしています。

## MSW Development (feat vue)

1. vueプロジェクト作成


    ``` bash
    $ vue create my-app
    ```

2. axiosライブラリのインストール

    ``` bash
    $ npm install axios
    ```

3. mswライブラリのインストール

    ``` bash
    $ npm install msw
    ```

4. モーキングサーバーを除いたまま作成
    ここまで進めるとmessageapiが存在しないため、例外処理にかかります。
    
    /src/services/fetchers.js
    ``` js
    import axios from 'axios'
    
    export const fetchMessage = async function (){
      const response = await axios.get('/message');
      return response.data.message;
    }
    ```

    /src/App.vue
    ``` vue
    <template>
      <p></p>
    </template>
    
    <script>
    import { fetchMessage } from './services/fetchers'
    export default {
      data(){
        return {
          message: "",
        }
      },
      created(){
        this.fetchData();
      },
      methods : {
        async fetchData(){
          try{
            this.message = await fetchMessage();
          }catch(e){
            this.message = "server error";
          }
        }
      }
    }
    </script>
    
    <style>
    
    </style>
    ```
5. mocking関連ファイルの作成
    /src/mocks/handlers.js
    ``` js
    import { rest } from 'msw'

    export default [
      rest.get('/message', (req, res, ctx) => {
        return res(
          ctx.json({
            message: 'it works and todo second things'
          })
        )
      })
    ]
    ```

    /src/mocks/browser.js
    ``` js
    import { setupWorker } from "msw";
    import handlers from "./handlers";
    
    export const worker = setupWorker(...handlers);
    ```

    | Files    | Description                                         |
    |----------|-----------------------------------------------------|
    | handlers.js       | mocking API 動作定義                        |
    | browser.js | handlers.jsのコードを利用し、サービスワーカーを初期化 |

    
    brower.jsで初期化過程を経ると、クライアントの要請をサーバーではなくサービスワーカーに送り、Mock APIに指定したリターン値を受け取ることができるようにすることができます。（要請を途中で横にして模擬api応答値を使用するように操作）
    
6. サービスワーカーの初期化

    ``` js
    console.log(process.env.NODE_ENV);
    if(process.env.NODE_ENV === 'development'){
        const { worker } = require('./mocks/browser');
        worker.start();
    }
    ```

7. publicディレクトリにworkerスクリプトを生成する
    このscriptはhttp要請を横取りし、模擬サーバーで動作するようにしてくれます。

    ``` bash
    $ npx msw init public/
    ```

    Directory Structure
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3824062/dfa4dec9-72e6-1d56-246c-b11c0db5d854.png)

    
# 実行結果
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3824062/9f9bc447-1cad-7d6e-143f-4f8fcee9e92a.png)

さらに、上記のmockingサーバーの場合、postmanで実行すると結果が出ません。 なぜなら、サービスワーカー領域でのみ実行できるからです。

# Summary
私はフロントエンドで画面別機能を早く作らなければならない時は、上記のような方式を活用して開発をしています。 今回のポスティングがお役に立てば幸いです。