Open3
React + Jestでちょっと複雑なことしたい時の備忘録
あれ、このテストどうやるんだっけ。というときの備忘録として残しておく
特定のモジュールをMockにすげ替えるテスト。通信結果に応じた処理を変更する、環境変数に応じた処理を変更する等に使える。テストするモジュールの実装を知ってないとできないじゃん?ってなるのが問題ではある
// foo.ts
import { bar } from './bar';
export function foo() {
return bar() ? 'bar' : 'baz';
}
// bar.ts
export function bar() {
return false;
}
// foo.test.ts
import { bar } from './bar';
import { foo } from './foo';
// fromの部分と合わせる。pathを@とかにしてる時もそれに合わせる
jest.mock('./bar');
const mockBar = bar as jest.MockedFunction<typeof bar>;
mockBar.mockReturnValue(true);
describe(foo, () => {
beforeEach(() => {
mockBar.mockClear();
});
it('should be bar', () => {
// bar()の返却値をtrueにする
mockBar.mockReturnValueOnce(true);
expect(foo()).toBe('bar');
});
it('should be baz', () => {
// bar()の返却値をfalseにする
mockBar.mockReturnValueOnce(false);
expect(foo()).toBe('baz');
});
});
Reactで、検索欄の入力の候補を非同期で引っ張りたいが、debounceを使って少しディレイをかけたい…
そんなときのテスト
import { act, renderHook } from '@testing-library/react-hooks';
import { useAutoComplete, UseAutoCompleteProps } from './useAutoComplete';
const mockFetcher = jest.fn((query: string) =>
Promise.resolve(['入力候補A', '入力候補B']),
);
describe(useAutoComplete, () => {
beforeEach(() => {
mockFetcher.mockClear();
// jest.runTimersToTimeで時間経過を再現するために必要
jest.useFakeTimers('modern');
});
it('入力値が変わった後, 200ms待ってからfetchを行う', () => {
const { rerender, result } = renderHook((props) => useAutoComplete(props), {
initialProps: {
keyword: '',
fetcher: mockFetcher,
debounceDelayTime: 200,
} as UseAutoCompleteProps,
});
expect(mockFetcher).toHaveBeenCalledTimes(0);
rerender({
keyword: 'あ',
fetcher: mockFetcher,
debounceDelayTime: 200,
});
// 入力が変わった直後に呼ばれていないことを確認する
expect(mockFetcher).toHaveBeenCalledTimes(0);
// act & jest.runTimersToTimeで時間経過を再現できる
act(() => jest.runTimersToTime(200 - 1));
expect(mockFetcher).toHaveBeenCalledTimes(0);
act(() => jest.runTimersToTime(1));
// ディレイ時間経過後、入力欄の値をもとにFetchが動くことを確認する
expect(mockFetcher).toHaveBeenCalledTimes(1);
expect(mockFetcher).toHaveBeenCalledWith('あ');
});
});