1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Jestを使ってSpabaseをモックしてテストを書く③

Last updated at Posted at 2026-01-28

はじめに

Jestでテストを実行した際に「ReferenceError: fetch is not defined」というエラーが発生しました。これはSupabaseのモックが正しく適用されず、本物のSupabaseクライアントが呼ばれてしまったことが原因です。この記事では、エラーの原因と解決方法を記録します。

エラー内容

エラーメッセージ

ReferenceError: fetch is not defined
    at /Users/.../node_modules/@supabase/supabase-js/src/lib/fetch.ts:7:42
    at fetch (/Users/.../node_modules/@supabase/supabase-js/src/lib/fetch.ts:34:12)

詳細

エラーの原因は、Jestのテスト環境(Node.js)にはブラウザのfetch APIがグローバルに存在しないためです。本来はSupabaseをモックして実際のAPI呼び出しを避けるべきですが、モックが正しく適用されていませんでした。

実際に起きていたこと

テスト実行
    ↓
App コンポーネントをレンダリング
    ↓
本物の supabase.js がインポートされる(モックが適用されていない)
    ↓
Supabaseクライアントが fetch を呼び出そうとする
    ↓
Node.js環境には fetch がない → エラー

根本原因:モックが適用されなかった3つの理由

1. __mocks__ フォルダの配置場所が間違っていた

Jestの自動モック機能を使う場合、__mocks__ フォルダはモック対象のモジュールと同じディレクトリに配置する必要がある。

❌ 間違った配置
src/
  ├── supabase.js
  └── test/
      └── __mocks__/
          └── supabase.js   ← Jestはここを見ない

✅ 正しい配置
src/
  ├── __mocks__/
  │   └── supabase.js       ← src/supabase.js のモックはここ
  └── supabase.js

2. jest.mock() の巻き上げ(hoisting)問題

jest.mock() はJestによって自動的にファイルの先頭に移動される。そのため、外部からインポートした変数を参照できない。

// ❌ 動かない例
import mockSupabase from "./__mocks__/supabase.js";
jest.mock("../supabase", () => mockSupabase);  // mockSupabase は undefined

// ↑ 実際の実行順序はこうなる:
// 1. jest.mock() が先に実行される(mockSupabase はまだ undefined)
// 2. import が実行される

エラー解決

解決方法1:__mocks__ フォルダを正しい場所に移動

  1. src/test/__mocks__/supabase.jssrc/__mocks__/supabase.js に移動
  2. テストファイルで jest.mock() を呼ぶ
// sample.spec.js
import App from "../index.jsx";
import '@testing-library/jest-dom';
import { render, screen, fireEvent, waitFor } from "@testing-library/react";

jest.mock("../supabase");  // これだけで src/__mocks__/supabase.js が使われる

describe("学習記録アプリ", () => {
    // ...
});

なぜ jest.mock() だけでモックできるのか?

jest.mock("../supabase") を書くと、Jestは以下の処理を自動的に行う:

  1. "../supabase" のパスを解決 → src/supabase.js
  2. そのディレクトリに __mocks__ フォルダがあるか探す → src/__mocks__/
  3. 同じ名前のファイルがあるか探す → src/__mocks__/supabase.js が見つかる
  4. テスト実行時、"../supabase" のインポートを自動的に src/__mocks__/supabase.js に置き換える

テストファイルでモックをimportしなくていい理由は、Appコンポーネントが内部でsupabaseをインポートしている部分をJestが横取りしてモックに差し替えるから。

テストファイル                    Appコンポーネント
     │                                │
     │ jest.mock("../supabase")       │ import supabase from "./supabase"
     │         │                      │         │
     │         ▼                      │         ▼
     │    Jestが記憶                   │    Jestが介入
     │                                │         │
     │                                │         ▼
     │                           src/__mocks__/supabase.js を返す

解決方法2:jest.mock() 内でモックを直接定義

__mocks__ フォルダを使わず、テストファイル内で完結させる方法。

jest.mock("../supabase", () => {
    const mockRecords = [
        { id: 1, title: "test", time: 3 }
    ];

    const mockQueryBuilder = {
        select: jest.fn(() => Promise.resolve({ data: mockRecords, error: null })),
        insert: jest.fn((newRecord) => ({
            select: jest.fn(() => Promise.resolve({
                data: { ...newRecord, id: mockRecords.length + 1 },
                error: null
            }))
        })),
        delete: jest.fn(() => ({
            eq: jest.fn(() => Promise.resolve({ error: null }))
        }))
    };

    return {
        __esModule: true,
        default: {
            from: jest.fn(() => mockQueryBuilder)
        }
    };
});

比較表

方法 メリット デメリット
__mocks__ フォルダを使う モックを別ファイルに分離できる、複数のテストで再利用しやすい 配置場所のルールを理解する必要がある
jest.mock() 内で定義 テストファイル内で完結、わかりやすい テストファイルが長くなる、再利用しにくい

おわりに

「fetch is not defined」エラーは、一見Node.js環境の問題に見えますが、実際はモックが正しく適用されていないことを示すサインでした。

学び:

  • Jestの __mocks__ フォルダは、モック対象と同じディレクトリに配置する
  • jest.mock() は巻き上げられる(hoist)ため、外部変数を参照できない
  • エラーメッセージの「場所」を見ると、本物のライブラリが呼ばれているかどうかがわかる
1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?