問題
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