Using '@testing-library/react',
given the following component:
const Home = () => {
const submit = () => console.log('submit clicked');
return (
<div>
Home
<Button
onClick={submit}
>
Submit
</Button>
</div>
)
}
What assertion is necessary to add in order to finish the test below?
it('reacts to a submit event', async () => {
const { getByText } = render(<Home />);
fireEvent.click(getByText(/submit/i));
})
I need to get this out of the way: Testing Library's Guiding Principles consider testing implementation details, like asserting on whether a specific internal function was called or not, to be a bad pattern:
The more your tests resemble the way your software is used, the more confidence they can give you.
As written, your component's submit function is an implementation detail. The consumer doesn't know how the submit button is implemented, but they can expect the button to be rendered and clickable. There's just no indication of what should happen.
I prefer to assert the effect of a button click on the DOM, but if logging to console is all we have, you can spy on console.log:
test('logs something to the console when submit is clicked', () => {
const spy = jest.spyOn(console, 'log');
render(<Home />);
const submitButton = screen.getByRole('button', { name: /submit/i });
fireEvent.click(submitButton);
expect(spy ).toHaveBeenCalledWith('submit clicked');
});
So, we can do this, but I really urge you to think about whether we should. It really feels like testing implementation details, which results in brittle tests. Brittle tests tend to break when implementation details change. Tests that break when the user's experience hasn't is an indication that the test is worthless. A good test should provide confidence that your software works as the user expects.
Now, all of this doesn't mean that you shouldn't test the component's API. If your component was adjusted to accept a function that would be called when the Submit button is clicked, it would be fine to render it with a mock, simulate the button click, and assert that it works as the consumer expects:
test('calls the provided submit function', () => {
const submit = jest.fn();
render(<Home submit={submit} />);
const submitButton = screen.getByRole('button', { name: /submit/i });
fireEvent.click(submitButton);
expect(submit).toHaveBeenCalledTimes(1);
});
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