🦁

Jestを使ってReact Hook Form + Yupのテストをする

2022/04/13に公開

React Hook FormとYupを使ったフォームのテストをJestで書いてみました。

  • Reactを使ったフォームのレンダリングは行わずに、フォームのロジックのみをテストします。
  • フォームに値をセットして、フォーム送信時に使われる handleSubmit で出力される最終データをチェックします。
  • スキーマ定義によって出力データが意図しない結果になるバグがあり、コンパクトに検証するために作成したテストです。

testing-libraryのrenderHookを使って React Hook Form のフォームへのアクセスを得る

今回は Testing Libraryを使って React Hook のテストを行います。
https://github.com/testing-library/react-hooks-testing-library

React Hook Formはフォームの状態管理を行う useForm というカスタム・フックを提供しています。
https://react-hook-form.com/api/useform

renderHookでuseFormをレンダリングします。

import { renderHook } from '@testing-library/react-hooks';
import { useForm } from 'react-hook-form';

const reactHookFormResult = renderHook(() =>
  useForm({
    resolver: yupResolver(CowSchema),
      mode: 'onChange',
    })
  );
);

こちらの記事を参考にしました。
https://zenn.dev/bom_shibuya/articles/5c3ae7745c5e94

setValue を使ってフォームに値をセットする

React Hook Formで値をセットするのには setValue を使います。
setValueはuseStateの更新関数なのでTesting Libraryが提供する act の中で呼び出します。

const { setValue, handleSubmit } = reactHookFormResult.result.current;

act(() => {
  setValue('cowGroupId', '1');
  setValue('motherCowUid', '0249452288');
});

handleSubmitでフォーム・データを取り出す

フォームのデータを handleSubmit を使って読み出します。
handleSubmitはコールバックを呼び出すインターフェースになっているので、Jestのコールバック呼び出しテストの書き方を使っています。

https://jestjs.io/ja/docs/asynchronous#コールバック

it('母牛の個体識別番号', (done) => {
  handleSubmit((data) => {
    expect(data.cowGroupId).toBe('1');
    expect(data.motherCowUid).toBe('0249452288');
    done();
  })();
});

コールバックの終わりで done を呼び出します。

完成したコード

import { renderHook, act } from '@testing-library/react-hooks';
import { useForm } from 'react-hook-form';
import { yupResolver } from '@hookform/resolvers/yup';

describe('個体識別番号', () => {
  const CowSchema = yup.object().shape({
    cowGroupId: yup.number().umSelectNumber().label('群番号(群名称)').required(),
    motherCowUid: yup
      .string()
      .umNumberString()
      .label('母牛の個体識別番号')
      .maxLength(10)
      .test('motherCowUid', '10桁入力してください', function (value) {
        return String(value).length === 10;
      }),
  });
  const reactHookFormResult = renderHook(() =>
    useForm({
      resolver: yupResolver(CowSchema),
      mode: 'onChange',
    })
  );
  const { setValue, handleSubmit } = reactHookFormResult.result.current;it('母牛の個体識別番号', (done) => {
    act(() => {
      setValue('cowGroupId', '1');
      setValue('motherCowUid', '0249452288');
    });handleSubmit((data) => {
      expect(data.cowGroupId).toBe('1');
      expect(data.motherCowUid).toBe('0249452288');
      done();
    })();
  });
});

まとめ

React Hook FormのテストをJestで書いてみました。
React Hooksのレンダリングなど複雑な構成になりますが、一度書いてしまうと今後は同じ書き方で異なるパターンのテストができそうです。

Discussion