Testing a React component that uses Google reCAPTCHA V3

Viewed 283

I have a react component that is a basic form in which onSubmit, a function send is called, which checks for a few things before making an API call. The component works fine but I'm having a bit of trouble testing it. The API call itself is wrapped inside grecaptcha.ready and grecaptcha.execute as shown below. I've also made a sandbox here.

  async function send(e) {
    e.preventDefault();
    const to = e.target.elements.to.value;
    const message = e.target.elements.message.value;

    // Set in a higher level component that wraps our SendEmail component
    const grecaptcha = window.grecaptcha;

    grecaptcha.ready(() => {
      grecaptcha
        .execute(process.env.RECAPTCHA_V3_KEY, { action: "action" })
        .then(async (token) => {
          await sendIt(to, message, token)
            .then(() => {
              setIsLoading(false);
              setTimeout(() => {
                history.goBack();
              }, 1000);
            })
            .catch(() => {
              setIsLoading(false);
            });
        });
    });
  }

My test file looks like the following.

import React from "react";
import { render, screen, waitFor } from "@testing-library/react";
import user from "@testing-library/user-event";
import sendIt from "./api";
import SendEmail from "./App";

let token = "test-token";
const originalEnv = process.env;
let history;

beforeEach(() => {
  global.grecaptcha = {
    ready: jest.fn(),
    execute: jest.fn()
  };
  global.grecaptcha.execute.mockResolvedValueOnce(token);

  process.env = {
    ...originalEnv,
    RECAPTCHA_V3_KEY: "fake-key"
  };

  history = {
    goBack: jest.fn(() => "go back")
  };
});

afterEach(() => {
  process.env = originalEnv;
});

test("successfully sends message", async () => {
  sendIt.mockResolvedValueOnce({ data: "data" });
  render(<SendEmail history={history} />);

  const toInput = screen.getByLabelText("to");
  const messageTextArea = screen.getByLabelText("message");
  const sendButton = screen.getByRole("button");

  user.type(toInput, "me@mail.com");
  user.type(messageTextArea, "Hello there!");

  user.click(sendButton);

  const grecaptcha = global.grecaptcha;

  expect(grecaptcha.ready).toHaveBeenCalled();
  // Fails at this point here
  expect(grecaptcha.execute).toHaveBeenCalled();

  await waitFor(() => expect(sendIt).toHaveBeenCalled());
  expect(sendIt).toHaveBeenCalledWith("me@mail.com", "Hello there!", token);

  await waitFor(() => expect(history.goBack()).toHaveBeenCalled());
});

The expect(grecaptcha.execute).toHaveBeenCalled() assertion fails and the api call doesn't get called. What am I missing? Your help would be greatly appreciated.

0 Answers
Related