🐣

reCAPTCHAを使用した新規登録画面のIntegration Test

2023/06/02に公開

概要

Integration Testの導入を以下の記事を参考に実装しました。

https://note.com/cyberz_cto/n/n3ba47e0dcfd2

しかし、実際にサービスとしてユーザーのアカウントを作成する新規登録画面には、reCAPTCHAを追加で実装する必要が出てきます。reCAPTCHAとは、登録画面などでよく見られる以下の画像のようなもので、botによる不正なアクセスを防ぐために用いられます。(詳しくはこちら

reCAPTCHA

そうした中で、reCAPTCHAを追加した状態だと、テストがうまく通らない問題が発生しました。そのため、その解決方法を記事として残しておこうと思います。

使用技術
- Next.js
- Jest
- React Testing Library
- react-google-recaptcha

reCAPTCHAの実装

https://www.npmjs.com/package/react-google-recaptcha

npm install --save react-google-recaptcha

実装方法はライブラリにそのまま乗っかっただけなのであまり詳しく説明はしません。今回のテストで使用した形だけざっくり記載しておきます。

import ReCAPTCHA from 'react-google-recaptcha';
import { useCallback, useRef } from 'react';

const Signup = () => {
  const recaptchaRef = useRef<ReCAPTCHA | null>(null);
  
  const onSubmit = useCallback(async (e: ChangeEvent<HTMLFormElement>) => {
    e.preventDefault();
    // reCAPTCHAのtokenを取得
    const token = await recaptchaRef.current?.executeAsync();
    
    if (!token) { return; }
    
    // ここで新規登録の処理
    router.push('/');
  }, [router]);
  
  return (
    <>
      <form onSubmit={ onSubmit }>
        {/* メールアドレスやパスワードの入力項目 */}
      </form>
      <ReCAPTCHA
        ref={ recaptchaRef }
        sitekey={ recaptchaKey } // 各自googleから作成してください
        size="invisible"
        badge='inline'
      />
    <>
  )
}

課題と解決

上記した実装方法でテストを実行した場合、reCAPTCHAから取得しているtokenが取得できず、新規登録の処理まで辿り着けないことでテストが失敗で返されてしまいます。
そのため、この課題を解決するためには、tokenをrecaptchaRefに格納しているReCAPTCHAコンポーネントをモックする必要があります。

そして、その方法が以下のようになります。

import { forwardRef, useImperativeHandle } from 'react';

// react-google-recaptcha の mock
jest.mock('react-google-recaptcha', () => {
  const ReCAPTCHA = forwardRef(function Components(props, ref) {
    useImperativeHandle(ref, () => ({
      executeAsync: jest.fn(() => 'token'),
    }));

    return null;
  });

  return ReCAPTCHA;
});

test pass
参考にした記事と同じように、jest.mockでモックを生成し、tokenを取得しているexecuteAsyncという関数に対して、tokenに値する文字列を返しています。このように、reCAPTCHAに対してもモックを実装してあげることで、テストを問題なく通すことができます。

Discussion