1 はじめに
supabaseと連携したReactアプリにおいて、
Jestとreact-testing-libraryを用いた自動テストで躓いたことが複数個あったため、
それぞれ別記事としてまとめていく
今回は第1弾、ReferenceError: fetch is not definedについて
2 事象
今回、supabaseと連携したReactアプリとして
学習記録アプリを開発した。このアプリは画面を立ち上げた際、
supabaseに登録しているレコードを全件取得したのち、
一覧を表示するといったものである。
タイトル「学習記録一覧」が
表示されるかを確認しようとし、下記のようなプログラムを作成したところ
Error fetching todos: { message: 'ReferenceError: fetch is not defined', details: 'ReferenceError: fetch is not defined }
が発生
この原因について調査した
import { LearningRecord } from "../LearningRecord";
import React from "react";
import "@testing-library/jest-dom"
import { render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
describe("Title Test", () => {
it("タイトルが学習記録一覧であること", async () => {
render(<LearningRecord />);
const title = screen.findByTestId("title");
expect(title).toHaveTextContent("学習記録一覧");
});
});
3 原因と解決法
調査したところ、Supabase JSが内部で使用しているfetchを
Jestのテスト実行環境には存在しないからである模様
よって、supabaseを利用したアプリをテストする際は対策を考える方法がある。
そこで今回採用した手法はsupabase関係のプログラムをmockした。
ここでmockとは一言で言うと本物の代わりに使う「ニセモノ」。
今回のようなテスト対象外のロジック部分(特に外部依存)を考慮せずに、
テスト対象の箇所だけに着目できるようにするための手法である。
mockを用いて以下のようにプログラムを修正したところ動いた。
TestIdを探すためにはsupabaseから全件取得→描写という動作を待つ必要がある為、
await で待ってあげる必要がある。(これをしないとTestIdが見つからないと怒られる)
jest.mock("../supabaseClients.jsx", () => {
let data = [ {id: 1, title: "dummy", time: 1}, {id: 2, title: "dummy2", time: 2} ];
return {
supabase: {
from: jest.fn(() => ({
select: jest.fn(() => {
return Promise.resolve({
data: data,
error: null,
})
}),
insert: jest.fn((newItem) => {
newItem.id = 2;
data = [...data, newItem];
return Promise.resolve({
data: newItem,
error: null,
});
}),
delete: jest.fn(() => {
return {
eq: jest.fn((key, value) => {
data = data.filter(item => item[key] !== value);
return Promise.resolve({
data: data,
error: null,
});
}),}
}),
})),
},
};
});
import { LearningRecord } from "../LearningRecord";
import React from "react";
import "@testing-library/jest-dom"
import { render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
describe("Title Test", () => {
it("タイトルが学習記録一覧であること", async () => {
render(<LearningRecord />);
const title = await screen.findByTestId("title");
expect(title).toHaveTextContent("学習記録一覧");
});
});
(補足)
import { createClient } from "@supabase/supabase-js";
//本番用
//const supabaseURL = import.meta.env.VITE_SUPABASE_URL;
//const supabaseKey = import.meta.env.VITE_SUPABASE_ANON_KEY;
//Jest テスト用
const supabaseURL = process.env.VITE_SUPABASE_URL;
const supabaseKey = process.env.VITE_SUPABASE_ANON_KEY;
export const supabase = createClient(supabaseURL, supabaseKey);
※import.metaはvite上の機能なので、下記記事を参考にしてvite.config.jsを次のように編集してJest上で.envファイルを読み取るようにした
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import env from "vite-plugin-env-compatible"
// https://vite.dev/config/
export default defineConfig({
plugins: [
react(),
env({ prefix: "VITE", mountedPath: "process.env" })
],
base: "",
})
4 まとめ
supabaseや外部と通信する必要がある、テスト対象外の機能のに関してはmockを利用することが
必要である。
それぞれがどういった機能なのか、テスト対象は何かという事を考慮してあげるのが必要である。
JISOUのメンバー募集中!
プログラミングコーチングJISOUでは、新たなメンバーを募集しています。
日本一のアウトプットコミュニティでキャリアアップしませんか?
興味のある方は、ぜひホームページをのぞいてみてくださ!
▼▼▼
