1
1

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】JestでSupabaseクライアントのモックを共通化する

Last updated at Posted at 2025-06-29

問題

JestでSupabaseクライアントなどのモックを複数のテストで共通化したい。
現状は、App.test.tsx、xxx.test.tsx、yyy.test.tsxそれぞれでsupabaseClient.tsのmockを作っている。

ディレクトリ構成(Before)

your-app/
  src/
    lib/
      supabaseClient.ts
    App.tsx
    xxx.tsx
    yyy.tsx

    // 現状はそれぞれのファイル内でsupabaseのmockを作っている 
    tests/
      App.test.tsx
      xxx.test.tsx
      yyy.test.tsx

エラー内容

supabaseのmockを共通化してテストを実行すると、エラーになる。(ファイルの中身は正しいことが前提)

src/__tests__/App.test.tsx
  ● Test suite failed to run
Jest encountered an unexpected token

Jest failed to parse a file. This happens e.g. when your code or its dependencies use non-standard JavaScript syntax, or when Jest is not configured to support such syntax.

解決策

mocksを作るディレクトリが誤っていた。

// ディレクトリ構成 誤り
your-app/
  __mocks__/       // 間違い
    lib/       // 間違い
      supabaseClient.ts       // 間違い
// ディレクトリ構成 正解
your-app/
  src/
    lib/
      supabaseClient.ts         // 本物
      __mocks__/       // モック
        supabaseClient.ts       // モック
    App.tsx
    xxx.tsx
    yyy.tsx
    
    tests/
      App.test.tsx
      xxx.test.tsx
      yyy.test.tsx

mockしたファイル

src/lib/supabaseClient.ts
import { User } from '@supabase/supabase-js';

// ダミーユーザーを用意
// User型に合わせてダミーユーザーを作成
export const mockDummyUser: User = {
    id: "dummy-id",
    aud: "authenticated",
    created_at: "2024-01-01T00:00:00.000Z",
    app_metadata: {},
    user_metadata: {},
    email: "dummy@example.com",
    phone: "",
    role: "authenticated",
    confirmed_at: "2024-01-01T00:00:00.000Z",
    last_sign_in_at: "2024-01-01T00:00:00.000Z",
    updated_at: "2024-01-01T00:00:00.000Z",
    identities: [],
    factors: [],
};
const result = {
  data: [{ word_name: "hello" }, { word_name: "world" }],
  error: null,
};

const builder = {} as {
  select: jest.Mock;
  eq: jest.Mock;
  is: jest.Mock;
  single: jest.Mock;
  order: jest.Mock;
  updated_at: jest.Mock;
  then?: (resolve: (value: unknown) => unknown) => unknown;
};

builder.select = jest.fn(() => builder);
builder.eq = jest.fn(() => builder);
builder.is = jest.fn(() => builder);
builder.single = jest.fn(() => builder);
builder.updated_at = jest.fn(() => builder);
builder.order = jest.fn(() => builder);
builder.then = (resolve) => resolve(result);

export const supabase = {
  from: jest.fn(() => builder),
  auth: {
    onAuthStateChange: jest.fn(() => ({
      data: {
        subscription: {
          unsubscribe: jest.fn(),
        },
      },
    })),
    getUser: jest.fn(async () => ({
      data: { user: mockDummyUser },
      error: null,
    })),
    signInWithOAuth: jest.fn(async () => ({
      error: null,
    })),
    signOut: jest.fn(async () => ({
      error: null,
    })),
  },
};

呼び出し例

your-app/src/__tests__/App.test.tsx
jest.mock('../lib/supabaseClient');

import { supabase } from '../lib/supabaseClient'; // ← jest.mockの後に入れる

まとめ

  • モックは「本物と同じ階層の__mocks__ディレクトリ」に置く
  • jest.mockとimportのパスは本物と同じにする
  • ルート直下の__mocks__ではなく、モジュール直下の__mocks__が正解

終わりに

かなり時間がかかってしまいました。

最初はCopilotの指示通りにモック用ディレクトリを作っていましたが、
うまく動かず、テストが通りませんでした。

その後、Claudeで確認したところ、正しいディレクトリ構成が分かりました。

今回の経験から、AIの回答を鵜呑みにせず、複数の情報源や公式ドキュメントも必ず確認することが大切だと実感しました。

Jest ドキュメント
https://jestjs.io/docs/manual-mocks

1
1
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
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?