In my React Signup component is a form where the user inputs their email, password, and password confirmation. I am trying to write tests using jest/react-testing-library, however I keep getting a test failed as the received number of function calls is 0 with an expected number of calls being 1.
I have tried variations of the Jest matcher such as .toHaveBeenCalled(), .toHaveBeenCalledWith(arg1, arg2, ...), toBeCalled() all of which still expect a value of 1 or greater but fail because the received number is 0. I have tried both fireEvent.click and fireEvent.submit both of which still fail.
Signup.js
export const Signup = ({ history }) => {
const classes = useStyles();
const [signup, setSignup] = useState({
email: null,
password: null,
passwordConfirmation: null,
});
const [signupError, setSignupError] = useState('');
const handleInputChange = e => {
const { name, value } = e.target;
setSignup({ ...signup, [name]: value });
console.log(signup);
};
const submitSignup = e => {
e.preventDefault();
console.log(
`Email: ${signup.email}, Pass: ${signup.password}, Conf: ${signup.passwordConfirmation}, Err: ${signupError}`
);
};
return (
<main>
<form onSubmit={e => submitSignup(e)} className={classes.form}>
<TextField onChange={handleInputChange}/>
<TextField onChange={handleInputChange}/>
<TextField onChange={handleInputChange}/>
<Button
type="submit">
Submit
</Button>
Signup.test.js
import React from 'react';
import { BrowserRouter } from 'react-router-dom';
import { render, cleanup, fireEvent } from '@testing-library/react';
import { Signup } from '../Components/Signup';
afterEach(cleanup);
const exampleSignup = {
email: '[email protected]',
password: 'test123',
passwordConfirm: 'test123',
};
describe('<Signup />', () => {
test('account creation form', () => {
const onSubmit = jest.fn();
const { getByLabelText, getByText } = render(
<BrowserRouter>
<Signup onSubmit={onSubmit} />
</BrowserRouter>
);
const emailInput = getByLabelText(/Enter your Email */i);
fireEvent.change(emailInput, { target: { value: exampleSignup.email } });
const passInput = getByLabelText(/Create a Password */i);
fireEvent.change(passInput, { target: { value: exampleSignup.password } });
const passCInput = getByLabelText(/Confirm Password */i);
fireEvent.change(passCInput, {
target: { value: exampleSignup.passwordConfirm },
});
fireEvent.submit(getByText(/Submit/i));
expect(onSubmit).toHaveBeenCalledTimes(1);
});
});
Results from test run account creation form
expect(jest.fn()).toHaveBeenCalledTimes(expected)
Expected number of calls: 1
Received number of calls: 0
in your SignUp.test.js you are passing your onSubmit function as a prop however that prop is never used in your SignUp component. That is why your onSubmit function is never called.
Now regarding the answer to your question, the react testing library discourages testing implementation details (like testing a function has been called) therefor there is no way to test that using the react testing library (although you can do that with other frameworks like using jest.spyOn on your function so that would be a way to do it)
What is recommended though is testing the outcome of your submit function. For example let's say you want to display (Thank you for signing up) after clicking the submit button, in that case you would test that using expect(screen.getByText("Thank you for signing up")).toBeInTheDocument()
after running fireEvent.submit(getByText(/Submit/i))
FYI : Since you are using jest, you don't need to call the cleanup function afterEach test.
I have previously answered a similar question here: https://stackoverflow.com/a/61869203/8879071
Your submit action is not doing any side effect really here (except for logging it).
You can assert console.log
called with something. NOT A GOOD IDEA!
Usually, on form submissions, we do some side-effect as follows:
Prop: pass a jest.fn() as a prop and can be asserted.
API util: axios/fetch can be mocked and asserted.
Only the dependencies can be mocked.
example, errors/success messages etc. Assert on the elements being toBeInTheDocument()
Form contents can be asserted, if you're very interested. e.g toHaveFormValues()
Summarising, internal functions (which have no reference outside) can't be mocked. AND SHOULD NOT BE!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With