When I started writing frontend tests, I often found myself thinking:
What should I even test here?
My early tests were testing the wrong things:
And like many engineers, I once equated high coverage with high quality.
Spoiler: I was wrong.
This shift really clicked for me during a pull request review.
A teammate had written several tests, but most of them focused on superficial things, like checking the copy of instructional text we didn’t really care about. What they missed was much more important: the behaviour of the submit button during form submission.
In the actual feature, once the user submits the form, the button should become disabled and show a loading spinner, this is a button functionally we have backed-in into our design system. This gives the user feedback that something is happening, preventing uncertainty, repeated clicks and users submitting more than once.
But that logic wasn’t tested. The backend wasn’t protected against double submission, the endpoint worked intentionally like this and it was the responsibility of the frontend to submit only once. A user clicking the button twice could trigger two POST requests, one succeeding and one failing, which could result in duplicated data. A nasty and avoidable scenario.
I suggested we rewrite the tests from the user’s point of view. Instead of checking static copy, we should:
That one conversation changed how I think about testing. It is not about asserting DOM text or ticking a coverage box. It is about safeguarding real-world behaviours that affect user experience and backend integrity.
Instead of testing the function that sets isFormValid, test the actual form submission as a user would:
render(<MyForm />);
await user.type(screen.getByLabelText('Email'), 'test@example.com');
await user.click(screen.getByRole('button', { name: 'Submit' }));
expect(await screen.findByText('Success!')).toBeVisible();This confirms:
Avoid testing implementation details like state updates or individual handlers. If a user cannot observe it, it probably should not be in your test. Test what a user can see or do on the page.
Good testing comes from threat modelling, not from tools or frameworks.
Before writing a test, I now ask:
This leads to more relevant tests, that brings you more confidence in your code.
Example: If you have a component that loads data on mount, test these scenarios:
Mocks are seductive. They make tests predictable and fast. But they often strip away the very behaviours you need to validate. Mocks are also time consuming to write and maintain.
Over-mocking leads to tests that pass regardless of real behaviour. It’s the opposite of what you really want to test.
Instead, use:
@testing-library/reactmsw) to simulate real HTTP responsesThis helps you catch integration issues and edge cases earlier.
Well-written tests do not just prevent regressions, they tell future developers (including you) how the app is meant to behave.
Instead of writing a wiki page or having a storybooks on how a complex component behaves under different conditions and frontend states.
The test reads like a spec. It communicates the business logic. And it does not rely on internal component structure.
If you are not sure what to test:
If you are not sure how to test:
@testing-library/react, it is good for accessibility and enhances best practicesmsw to simulate the real worldIf you are drowning in complexity:
Writing good frontend tests is not about satisfying a coverage metric.
It is about confidence:
So test like your users matter, because they do.
Tue, 22 April 2025
Testing Strategies for Modern React Apps: Unit, Integration, and Visual Regression
Testing React apps doesn't have to be scary. Learn the basics of unit, integration, and visual regression testing with popular tools.
Thu, 17 April 2025
Why I Stopped Obsessing Over 100% Unit Test Coverage
Our CI pipelines required 100% coverage. Here's how it backfired and what I now focus on instead.
Fri, 6 June 2025
Frontend Security: A Practical Guide
Frontend developers are often the first line of defence against cyberattacks. Here's a practical guide to the most common threats and how to prevent them
Subscribe to get updates on new blog posts, useful frontend tips and ideas you can apply in your own work.