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でmockを作って、データを削除するテストをする supabase、React.js、TypeScript

Posted at

はじめに

めちゃくちゃはまったので記事にします。

問題

Jestでmockを作って、データを削除するテストがうまくいかなかった。

そもそもですが、やりたいことが曖昧で、何が分からないのかが分からなかった。
・mockの書き方がわかっていなかった
・何をやりたいのかがわかっていなかった
(どの関数をモック化して、何のデータを得たい(return)したいのか)

解決方法

@Sicut_studyさんにアドバイスいただきながら、以下のように対応しました。

  • App.tsxで、APIコールする部分は、別ファイルに書き出す
    (データ取得するための関数(GetAllRecords)、削除するための関数(RecordDelete)それぞれ)

  • AppComponent.spec.tsx(testファイル)で、それぞれの関数をmock化する
    (GetAllRecordsするためのmock、RecordDeleteするためのmock)

  • 削除するためのモック(RecordDelete)を表現する方法を理解する
    実際にapiをコールしてdeleteメソッドを使う必要はない
    App.tsxのhandleDeleteメソッドの中で、fetchData()があり、再度GetAllRecordsが呼ばれるので、1回目に叩かれる時、2回目に叩かれる時で、データを変更する(1回目「id5, id10」、2回目「id10」のみ、など)
    RecordDeleteのmockは、動いてもGetAllRecordsで上書きされるので、実質なんでも良い

src/App.tsx
import { GetAllRecords } from './lib/record';
import { RecordDelete } from './lib/record_delete';

~~~中略~~~
  const fetchData = async () => {
    const getAllRecordMethod = async () => {
      // GetAllRecords();を外部ファイルに書く
      const todoRecord = await GetAllRecords();
      setData(todoRecord);
      setIsLoading(false);
    };
    getAllRecordMethod();
  };

~~~中略~~~
record.tsx
import { Record } from "../domain/record";
import supabase from "../utils/supabase";

export async function GetAllRecords(): Promise<Record[]> {
        const response = await supabase.from("study-record").select("*");
        if (response.error) {
                throw new Error(response.error.message);
        }

        const data = response.data.map((todo) => {
                return Record.newRecord(todo.id, todo.title, todo.time);
        });
        return data; ;
}
record_delete.ts
import { Record } from '../domain/record';
import supabase from '../utils/supabase';

export async function RecordDelete(id: string): Promise<void> {
  await supabase.from('study-record').delete().eq('id', id);
}
AppComponent.spec.tsx
// testファイル

// mockを使ったテストは、describeを使わないと、global的な扱いとなり、他のテストに影響する
describe('mockを使ったテスト', () => {

// '@/lib/record.ts'のGetAllRecordsをモック化
jest.mock('@/lib/record.ts', () => {
  const { Record } = jest.requireActual('@/domain/record');
  return {
// GetAllRecordsをモック化
    GetAllRecords: jest
      .fn()
// 1回目に呼び出されたときに返すデータ
      .mockImplementationOnce(() =>
        Promise.resolve([
          new Record('5', 'Testtest5', 5),
          new Record('10', 'Testtest10', 10),
        ])
      )
      .mockImplementationOnce(() =>
        Promise.resolve([
// 2回目に呼び出されたときに返すデータ
          // new Record('5', 'Testtest5', 5),
          new Record('10', 'Testtest10', 10),
        ])
      ),
  };


// '@/lib/record_delete.ts'のRecordDeleteをモック化
jest.mock('@/lib/record_delete.ts', () => {
        const { Record } = jest.requireActual('@/domain/record');
  console.log('record_delete.ts--------のテストのモック通過');
  return {
// RecordDeleteをモック化
        RecordDelete:  jest
    .fn()
    .mockImplementationOnce(() =>
      Promise.resolve([
// App.tsxではRecordDeleteの後、再度GetAllRecordsが呼ばれて上書きされるので、実質何でも良い
        // new Record('5', 'Testtest5', 5),
        new Record('10', 'Testtest10', 10),
      ])
    ),
  };
});


  test('削除ができること', async () => {
    render(
      <ChakraProvider value={defaultSystem}>
        <App />
      </ChakraProvider>
    );
    // 確認用出力
    // screen.debug();
    await waitFor(() => {
      const dialogTitle = screen.getByText('登録');
      expect(dialogTitle).toBeInTheDocument();
    });

    // 確認用出力
    // screen.debug();

    const deleteButton = await waitFor(() =>
      screen.getByTestId('delete-button-5')
    );
    // console.log("deleteButton", deleteButton)

    await waitFor(() => {
      fireEvent.click(deleteButton);
    });

    // 確認用出力
    // screen.debug();
    await waitFor(() => {
        //  expect(screen.queryByText('Testtest5 5時間')).toBeInTheDocument();
      expect(screen.queryByText('Testtest5 5時間')).not.toBeInTheDocument();
    });
  });
});

おわりに

分からないことが多すぎると、思考停止になってしまいます。
自分の理解が浅いとChatGPTへの質問も浅くなってしまい、良い回答が得られなかったです。
角度を変えながらエラーの原因を考え、1つ1つ問題をつぶしていけるようにしたいです。

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?