t49tran / react-google-recaptcha-v3

Google Recaptcha V3 integration for React
MIT License
427 stars 91 forks source link

Cannot mock useGoogleReCaptcha #123

Open afternoon2 opened 2 years ago

afternoon2 commented 2 years ago

Hello and thanks for developing this library!

I have a problem with mocking the useGoogleReCaptcha hook. It seems that the original implementation is called from the component although jest doesn't log any errors about the mock being done in a bad way.

Usage in the app

Custom hook that wraps the library hook:

import { useCallback } from 'react';
import { useGoogleReCaptcha } from 'react-google-recaptcha-v3';

export type UseRecaptcha = {
  getRecaptchaToken: () => Promise<string>;
};

const useRecaptcha = (): UseRecaptcha => {
  const { executeRecaptcha } = useGoogleReCaptcha();

  const getRecaptchaToken = useCallback(async () => {
    if (executeRecaptcha) {
      const token = await executeRecaptcha();
      return token;
    }
    return '';
  }, [executeRecaptcha]);

  return { getRecaptchaToken };
};

export default useRecaptcha;

And then I use it inside the component:

const { getRecaptchaToken } = useRecaptcha();

const token = await getRecaptchaToken();

Mock

const mockExecuteRecaptcha = jest.fn((_?: string) => Promise.resolve(
  'some_token'
));

beforeEach(() => {
    MockAxiosInstance.resetHandlers();
    jest.resetAllMocks();
    jest.clearAllMocks();
    jest.mock('react-google-recaptcha-v3', () => {
      return {
        useGoogleReCaptcha: () => ({
          executeRecaptcha: mockExecuteRecaptcha
        })
      };
    });
});

For now, I've no idea why is this happening. Could this have something to do with the RecaptchaProvider?

afternoon2 commented 2 years ago

Ok, I have at least a partial resolution - I moved jest mock outside of the describe block and removed mock resets + I mocked the provider as well.


jest.mock('react-google-recaptcha-v3', () => {
  return {
    GoogleReCaptchaProvider: ({ reCaptchaKey, useEnterprise, useRecaptchaNet, scriptProps, language, children }: any): JSX.Element => {
      return <>{children}</>
    },
    useGoogleReCaptcha: () => ({
      executeRecaptcha: mockExecuteRecaptcha
    })
  };
});

describe('<OnlineOnboarding />', () => {
  beforeEach(() => {
    MockAxiosInstance.resetHandlers();
    // jest.resetAllMocks();
    // jest.clearAllMocks();
  });
// tests
});

but still it doesn't look good to me 🙂

timothyk0908 commented 1 year ago

+1 I'm using playwright to test a register process, and I can't manage to mock the useGoogleRecaptcha hook action

jothinayagan-psi commented 1 year ago

Ok, I have at least a partial resolution - I moved jest mock outside of the describe block and removed mock resets + I mocked the provider as well.

jest.mock('react-google-recaptcha-v3', () => {
  return {
    GoogleReCaptchaProvider: ({ reCaptchaKey, useEnterprise, useRecaptchaNet, scriptProps, language, children }: any): JSX.Element => {
      return <>{children}</>
    },
    useGoogleReCaptcha: () => ({
      executeRecaptcha: mockExecuteRecaptcha
    })
  };
});

describe('<OnlineOnboarding />', () => {
  beforeEach(() => {
    MockAxiosInstance.resetHandlers();
    // jest.resetAllMocks();
    // jest.clearAllMocks();
  });
// tests
});

but still it doesn't look good to me slightly_smiling_face

As you mentioned, I have moved outside the describe. it works perfectly. Many thanks.