👻

Nuxt3にVItestとMSWを入れてAPIモックでのテストに詰まった点のメモ

2024/02/28に公開

はじめに

Nuxt3環境でAPI(RestAPI)のテストを行おうとした際にMock Service Worker(MSW)とVitestで対応していたがその際に詰まった点を記録しておく。
そのため環境設定周りは省略する。

最初に今回行いたいテストについて

piniaでトークンを保有しているストアがあり、内部は下記のようになっている。
今回テストしたい内容は下記である。
APIモックを使用し、fetchToken()をした際にgetToken()でトークンが保有されているかをテスト

トークンのpinia構成
store:  トークン
methods:
    getToken(): トークン取得する
        setToken(): トークンを設定する
    fetchToken(): トークンをAPIからGETし、setToken()を使い、storeにトークンを設定する

詰まった点

MSWへのリクエストした際にCaused by: TypeError: Cannot read properties of undefined (reading 'status')と出力される

mswのAPIモック構成は以下。

mock
│  handlers.ts(api配下のレスポンスそれぞれをハンドルする)
│  setup.ts (setupSeverの記述)
│
└─api (APIそれぞれのダミーレスポンスを格納する)
        dummy.ts 

構成としては問題なかったが、原因としては、公式ドキュメントをしっかりと読んでいなかったためのものであった。

原因

MSWでのRESTAPIの記述が変更されていたため。
rest記述からhttp記述からに変更されていた。

rest.get()http.get()
それによってレスポンスも以下に変更。

before
res(
    ctx.status(200),
    ctx.json([
      {
        id: 1,
        name: 'foo',
      },
      {
        id: 2,
        name: 'bar',
      }
    ]),
)
after
HttpResponse.json(
    { status: 200 },
    {[
      {
        id: 1,
        name: 'foo',
      },
      {
        id: 2,
        name: 'bar',
      }
    ]},
)

store側での$fetchができない点

こちらは以下順序で対応した。

1. unplugin-auto-importにてofetch/$fetchに紐付け

結果としては紐付け自体はできたが、fetch時にタイムアウトとなった。
おそらくofetchがnitroサーバー上でしか機能しないためうまく動かなかった。
nitroサーバーをsetup時に起動させれば良いとは思うが少し手間なので、別方法で調査。

2. @nuxt/test-utilsから$fetchをimportし使用

試してみたが、同事象が発生し、うまく解決できなかった。
拡張子を.mtsに変更しても解決しなかった。
https://github.com/nuxt/test-utils/issues/704

3. ofetch/$fetchをglobalThis.fetchにスパイ

結果これでMSWのAPIにアクセスできテストできた。
setup時に下記のようスパイした。

globalThis.fetchのイメージ
 // 最初にofetchのmockを作成
 vi.mock("ofetch", () => ({ $fetch: vi.fn() }));

  // 一旦getのみなのでoptionsは処理しない
 const nodeFetch = async(url,options) => {
    const data = await globalThis.fetch(url);
    return data.json()
  }
  // ofetchの$fetchをglobaltThis.fetchを使用したnode側でのfetch関数へスパイ
  vi.spyOn(await import('ofetch'), '$fetch').mockImplementation(nodeFetch)

最後に

@nuxt/test-utilsが使えればもう少し使いやすいかな?とは思う。
今回は$fetchの対応ですが、次はuseFetchの対応をどのように入れるかを考えなければならない。。。
やはりフロントのテストが難しい。。

Discussion