🥲

React×Jestの基礎知識

2024/02/07に公開

前述:Jestとは

・実行対象ファイル
ファイル名が.test.tsまたは.spec.tsで終わるもの

・jest実行コマンド
全てのテストを実行→ yarn test
差分のあるファイルのみ実行→  yarn test -o

基礎概念

describe

JestにおいてTest Suite(テストスイート)を作成するための関数。
テストスイートとは、テストケースをまとめた単位。
describe(テストスイートの説明, テストスイートの実行するコールバック関数)

test

単一のTest Case(テストケース)を定義するための関数

test(テストケースの説明, テストケースの実行するコールバック関数)

describe('足し算引き算のテスト', () => { 

  test('足し算', () => {
    const result = add(2, 3);
    // 期待値(result)は「5」になるよねって意味
    expect(result).toBe(5);
  })

  test('引き算', () => {
    const result = subtract(5, 2);
    expect(result).toBe(3);
  })

})

セットアップ

beforeEach

各テストケースが動く前に実行されるコードブロックを定義
各テストケースが動く前に新しいインスタンスが初期化され、テスト間で状態が共有されないようになる

describe('合計が正しいこと', () => {

  let calculator;

  beforeEach(() => {
    calculator = new Calculator();
  });

  it('足し算', () => {
    expect(calculator.add(2, 3)).toBe(5);
  });

afterEach

各テストケースが動いた後に実行されるコードブロックを定義
これにより、各テストケースは独立して実行され、カウンターの初期状態が保持されることが保証

describe('カウント', () => {

  let counter;

  beforeEach(() => {
    counter = new Counter();
  });
  afterEach(() => {
    counter.reset();
  });

結果比較:Matcher(マッチャー)

マッチャーを使用することでテストの結果を期待値と比較し、テストの成功または失敗を判断する。

使用方法

expect(2 + 2).toBe(4);

種類

関数 説明
toBe 厳密な等値性を検証
toEqual 値の内容を比較。(オブジェクトなどで用いられる)
toBeTruthy 値が真の値(truthy)であることを検証
toBeFalsy 値が偽の値(falsy)であることを検証
toBeNull 値がnullであることを検証
toBeUndefined 値がundefinedであることを検証
toBeDefined 値がundefinedでないことを検証
toContain 配列や文字列が特定の要素を含んでいることを検証
toBeLessThan 値が指定した値より小さいことを検証
toBeGreaterThan 値が指定した値より大きいことを検証
toHaveBeenCalledTimes 引数の数分関数が呼ばれたか確認
toHaveBeenCalledWith 引数が期待値通りの引数か確認

他にもあるお。
https://jestjs.io/ja/docs/expect

Mock(モック)

テスト中に関数やモジュールの振る舞いを模擬するために使用

流れ

モジュールをimport  → モック → モック関数の返す値を設定 → 呼び出し確認

// calculate.test.js
import { calculate } from './calculate';
import * as math from './math';

// mathモジュールをモックする
jest.mock('./math');

test('calculate関数のテスト', () => {

  // add関数をモックする
  // モック関数が返す値を10に設定
  math.add.mockReturnValue(10);

  // subtract関数をモックする
  math.subtract.mockReturnValue(5);

  // calculate関数を呼び出す
  const result = calculate(3, 2);

  // 期待する結果は (10 * 5) = 50
  expect(result).toBe(50);

  // add関数が呼び出されたかを検証
  expect(math.add).toHaveBeenCalledWith(3, 2);

  // subtract関数が呼び出されたかを検証
  expect(math.subtract).toHaveBeenCalledWith(3, 2);

});

実際にやってみて引っかかったところ

値を変更する処理はact内で行う

問題

下記エラー発生orz

console.error
 Warning: An update to TestComponent inside a test was not wrapped in act(...).

 When testing, code that causes React state updates should be wrapped into act(...):

解決

割と基礎的なことでした。ユーザの操作イベントは、act内で実行しないとエラーが出ます。
以下が公式ドキュメントに記載されていたものです。

act(...) 関数はテスト中にユーザーインターフェースを更新するイベント(ユーザーのクリックや入力など)をシミュレートする際に使用すべき

    // Act:検索リセット
    act(() => {
      xxx.onChangeSearch({
        ...condition,
      });
    });

API実行処理がある場合は、更新を待たないといけない

問題

API通信を含んだカスタムフックのテスト時、全然期待値通りにならない・・・????

解決

waitForNextUpdate関数で更新を待ちましょう。そしたら更新(または取得後)の値が 反映されるはずです。

const {result, waitForNextUpdate} = renderHook(() => useCounter())

 if ('APIテスト', async() => {
  省略・・・・・・
  
    act(() => {
      result.current.onSubmit();
    });
    await waitForNextUpdate(); // ここで更新を待つ

  省略・・・・・

参考記事

https://ja.legacy.reactjs.org/docs/testing-recipes.html#act
https://www.crunchtimer.jp/blog/18851
https://zenn.dev/bom_shibuya/articles/5c3ae7745c5e94

Discussion