Jestで「ReferenceError: fetch is not defined」エラーが出る原因と対処法

Jest を使ってテストを書いていると、次のようなエラーに遭遇することがあります。

ReferenceError: fetch is not defined

これは、Node.js 環境で実行される Jest が ブラウザの fetch API を持っていない ために発生するエラーです。React や Next.js などフロントエンド開発で fetch を使う機会は多いですが、そのままではテスト環境に fetch が存在せず落ちてしまいます。

本記事では、このエラーの原因を解説し、モックライブラリや設定で解決する方法を紹介します。

1. エラーが発生する背景

Jest はデフォルトで Node.js 環境で動作します。つまり、ブラウザのグローバル API(window, fetch, localStorage など)は存在しません。次のようなシンプルなコンポーネントをテストしようとするとエラーになります。

// src/apiClient.js
export async function getData() {
  const res = await fetch('/api/data')
  return res.json()
}
// src/apiClient.test.js
import { getData } from './apiClient'

test('fetches data', async () => {
  const data = await getData()
  expect(data).toEqual({ foo: 'bar' })
})

実行結果:

ReferenceError: fetch is not defined

ブラウザでは当たり前に存在する fetch が、Node.js では未定義であるためテストが失敗します。

2. 対処法1: whatwg-fetchを利用する

最もシンプルな解決策は、ポリフィルを追加して fetch を定義することです。

  1. パッケージをインストール
npm install --save-dev whatwg-fetch
  1. Jest のセットアップファイルでポリフィルを読み込む
// jest.setup.js
import 'whatwg-fetch'
  1. Jest 設定に setupFilesAfterEnv を追加
// jest.config.json
{
  "setupFilesAfterEnv": ["<rootDir>/jest.setup.js"]
}

これでテスト実行時に fetch が定義され、API 呼び出しが実行可能になります。ただし、この方法では実際のリクエストがネットワークに飛ぶため、テストが遅くなったり外部依存が発生する可能性があります。

3. 対処法2: fetchをモックする

テストでは本物の API 通信を行わず、モックレスポンスを返す方が安定します。jest.fn() や msw (Mock Service Worker) を使う方法があります。

// apiClient.test.js
import { getData } from './apiClient'

beforeAll(() => {
  global.fetch = jest.fn(() =>
    Promise.resolve({
      json: () => Promise.resolve({ foo: 'bar' })
    })
  )
})

test('fetches data', async () => {
  const data = await getData()
  expect(data).toEqual({ foo: 'bar' })
})

この方法なら、ネットワークに依存せず高速にテストできます。

msw を使った本格的モック

大規模プロジェクトでは msw を使うとより現実的なモックが可能です。

npm install msw --save-dev
// src/mocks/handlers.js
import { rest } from 'msw'

export const handlers = [
  rest.get('/api/data', (req, res, ctx) => {
    return res(ctx.json({ foo: 'bar' }))
  })
]
// jest.setup.js
import { setupServer } from 'msw/node'
import { handlers } from './src/mocks/handlers'

const server = setupServer(...handlers)
beforeAll(() => server.listen())
afterEach(() => server.resetHandlers())
afterAll(() => server.close())

これにより、API レイヤーを完全にモックしつつ、fetch を使ったコードも透過的にテストできます。

4. 対処法3: Node.js v18以降のfetchサポートを利用

Node.js v18 以降では fetch が標準実装されています。プロジェクトが v18+ で動作する場合は、ポリフィルを追加せずともテストが通ることがあります。

node -v
# v18.12.0 以上なら標準で fetch 利用可

ただし、CI/CD 環境の Node.js バージョンが古いと再現しない可能性があるため、.nvmrc や Volta でバージョン固定しておくことが推奨されます。

5. 実運用上の落とし穴とベストプラクティス

  • ローカルでは動くがCIで落ちる問題
    CI サーバーが Node.js v16 以下だと fetch がないため失敗します。バージョン統一が重要です。
  • 実際のAPIを叩いてしまう問題
    テスト環境が外部 API に依存すると不安定になります。msw などでモック化しましょう。
  • global.fetch のリーク
    テスト間で fetch のモックが残ると副作用が発生します。afterEach(() => jest.resetAllMocks()) でクリアしましょう。
afterEach(() => {
  jest.resetAllMocks()
})

6. まとめ

Jest で「ReferenceError: fetch is not defined」エラーが出るのは、テスト環境で fetch が存在しないためです。解決するには:

  • whatwg-fetch などでポリフィルを追加
  • jest.fn() や msw を用いたモックで安定したテストを実現
  • Node.js v18 以降なら標準 fetch を活用
  • CI/CD 環境の Node.js バージョンを固定して再現性を担保

このエラーは初心者がよくハマるポイントですが、設定とモック戦略を整理すれば安定したテストが可能になります。

参考

タイトルとURLをコピーしました