I recently started testing with Jest and react-testing-library. But I ran into a little problem. I am testing my component which looks like this:
import React, { useState } from 'react';
const Login = () => {
const [username, setUsername] = useState<string>('');
const [password, setPassword] = useState<string>('');
const handleSubmit = (event: React.FormEvent<HTMLFormElement>) => {
event.preventDefault();
};
return (
<div>
<form onSubmit={handleSubmit} data-testid="loginForm">
<label>
Username:
<input
required
type="text"
data-testid="usernameText"
placeholder="e.g. JohnLukeThe3rd"
value={username}
onChange={(event) => setUsername(event.target.value)}
autoFocus
/>
</label>
<label>
Password:
<input
required
type="password"
data-testid="passwordText"
placeholder="e.g. ••••••••••"
value={password}
onChange={(event) => setPassword(event.target.value)}
/>
</label>
<input type="submit" data-testid="loginButton" value="Login" />
</form>
</div>
);
};
export default Login;
As far as I understand onSubmit is not called when form is submitted but form's required input fields are empty. I checked this behavior by inserting a console.log('Hey') in handleSubmit but nothing got printed. So, I thought that in my test the same should happen. When I check if submit handler doesn't get called when input is empty it should succeed. But it doesn't. It fails.
Here's the testing code:
import React from 'react';
import {
render,
fireEvent,
cleanup,
RenderResult,
} from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import Login from '../components/Login';
describe('<Login />', () => {
let screen: RenderResult;
beforeEach(() => {
screen = render(<Login />);
});
afterEach(cleanup);
describe('typing user info', () => {
it('shows username and password', async () => {
expect(screen.queryByDisplayValue('JohnLukeThe3rd')).toBeNull();
await userEvent.type(
screen.getByLabelText(/username/i),
'JohnLukeThe3rd',
);
await userEvent.type(screen.getByLabelText(/password/i), 'Password123');
expect(screen.queryByDisplayValue('JohnLukeThe3rd')).toBeInTheDocument();
expect(screen.queryByDisplayValue('Password123')).toBeInTheDocument();
});
});
describe('clicking login button', () => {
let loginButton: HTMLElement;
let submitHandler: jest.Mock;
let form: HTMLElement;
beforeEach(() => {
loginButton = screen.getByText(/login/i);
submitHandler = jest.fn((e) => e.preventDefault());
form = screen.getByTestId(/loginForm/i);
form.onsubmit = submitHandler;
});
// problem area here
it('does not call submit handler if fields empty', () => {
expect(submitHandler).not.toHaveBeenCalled();
userEvent.click(loginButton);
expect(submitHandler).not.toHaveBeenCalled();
});
// problem area ends
it('calls submit handler if fields non-empty', async () => {
expect(submitHandler).not.toHaveBeenCalled();
const usernameField = screen.getByTestId('usernameText');
const passwordField = screen.getByTestId('passwordText');
await userEvent.type(usernameField, 'JohnLukeThe3rd');
await userEvent.type(passwordField, 'Password123');
await userEvent.click(loginButton);
expect(submitHandler).toHaveBeenCalledTimes(1);
});
});
});
The test 'does not call submit handler if fields empty' fails. What am I doing wrong? I couldn't find any information on testing form with required input fields anywhere. Am I doing it wrong? Thanks.
Also, just so you know: I did screen.debug() in the test and both input's value was 'value=""'