2

I have a submit handler in a React form component that does the following onSubmit: registerForm/index.js

import { loginFunction, registerFunction } from "../../actions";
//within registerform function
const handleSubmit = async(e) => {
        e.preventDefault();
        setErrorMessage('')
        await registerFunction(e);
        await loginFunction(e);
        ...
}

I have mocked the two functions in a test file and tested them with the code below: registerForm/registerForm.test.js

import RegisterForm from ".";
import { registerFunction, loginFunction } from "../../actions";
import 'react-router-dom'
import { fireEvent } from "@testing-library/react";

jest.mock('../../actions', () => ({
    loginFunction:jest.fn(),
    registerFunction:jest.fn(),
}))

describe('Unit test of registration form', function() {
    it('should register', () => {
        const {container} = render(< RegisterForm/>)
        fireEvent.submit(container.querySelector('.submit')) 
        expect(registerFunction).toBeCalledTimes(1) // this passes 
        expect(loginFunction).toBeCalledTimes(1) // this fails
    })
})

I have removed the second line and the test passes so I know the submit handler is called but I was wondering why the second function doesn't get called.

I have also tested the loginFunction on a different react form component with a submit handler and the mocked function gets called for that test

loginForm/index.js

import { loginFunction } from "../../actions";
//within loginform function
const handleSubmit = async(e) => {
        e.preventDefault();
        setErrorMessage('')
        await registerFunction(e);
        await loginFunction(e);
        ...
}

loginForm.tes.js

import LoginForm from ".";
import { loginFunction } from "../../actions"
import { fireEvent } from "@testing-library/react";

jest.mock('../../actions', () => ({
    loginFunction:jest.fn()
}))

describe('Unit test of login form', function() {
    it('should login', () => {
        const {container} = render(<LoginForm />)
        fireEvent.submit(container.querySelector('.submit'))
        expect(loginFunction).toBeCalledTimes(1) //this passes 
    })
})
  • 1
    The reason the second function never executes is because the first never resolves. Victor was on the right track with the (now deleted) answer, but missed the idea that the mocked functions _must_ resolve as a Promise. – Randy Casburn Mar 17 '23 at 14:15
  • Just wanted to make sure I had the right answer – Victor Santizo Mar 17 '23 at 14:20

1 Answers1

1

Use waitFor in order to let the asynchronous operations finish and make the mocks return a Promise

jest.mock('../../actions', () => ({
    loginFunction:jest.fn(() => Promise.resolve({data: 'data'}),
    registerFunction:jest.fn(() => Promise.resolve({ hello: "world" }),
}))



describe('Unit test of registration form', function() {
    it('should register', async () => {
        const {container} = render(< RegisterForm/>)
        fireEvent.submit(container.querySelector('.submit')) 
        await waitFor(() => {
          expect(registerFunction).toBeCalledTimes(1) 
          expect(loginFunction).toBeCalledTimes(1) 
        })
    })
})
Victor Santizo
  • 1,145
  • 2
  • 7
  • 16
  • Thank you Victor, this seems to work for me. Although I had to remove the await before the waitFor function to avoid syntax errors. – Franklyn Asafo-Adjei Mar 17 '23 at 19:59
  • Forgot to add the `async` keyword when defining the function. Just edited the answer and please consider checking the answer as accepted, only if you want to. @FranklynAsafo-Adjei – Victor Santizo Mar 17 '23 at 21:17
  • When I run this I get the following error: Returning a Promise from "describe" is not supported. Tests must be defined synchronously. The solution you suggested works fine for me without the async await however. – Franklyn Asafo-Adjei Mar 20 '23 at 12:29