Blog

Why you might not need unit tests in React

Many teams rely on unit tests for React components, but do you need them?

Jordan Burnett
By Jordan Burnett

With the popularity of libraries like react-testing-library, it's never been easier to test your frontend components alongside the rest of your codebase.   

But while unit tests have their place, I've found they're often overused. What's worse, they can slow down your development cycle while giving you a false sense of security.

Let's challenge the idea that unit testing is a requirement for your React components, and whether other approaches may save you time in the long run.

Why unit tests often fall short in React

When I first started working on frontend React apps, I was like many others: writing unit tests for everything. Testing every component, every function, and every piece of logic seemed like the right thing to do. After all, this is what testing best practices recommend, right?

Well, not quite.

The more we tested, the more we started to notice something: we were writing redundant tests. These unit tests often ended up testing the same things we already covered in our E2E tests. We were spending hours maintaining these unit tests, mocking services, and ensuring they were green but with diminishing returns.

Worse still, when they failed, they often pointed to issues in the test environment rather than actual bugs in the app.

Here's the hard truth I've learned: unit tests can be misleading. They make you feel like you've got everything under control, but that's not always the case. Unit tests mock out real services, real APIs, and often end up testing pieces of an app in isolation that don't provide meaningful value.

You're testing in a bubble, without the real-world context of how users interact with your app.

E2E tests: the real value

A team I worked with made the bold decision to eliminate unit tests for frontend components altogether. Instead, we shifted to focusing on E2E tests for key flows in the app. The result? We moved much faster.

Here's why E2E tests worked better for us:

  1. They test the user's perspective. E2E tests simulate the full journey of a user. Whether it's filling out a form, navigating through the app, or making an API request, these tests ensure that the app works as expected from start to finish.

  2. No more mocking. Unlike unit tests that mock services, E2E tests use real services and APIs. This means they reflect the actual user experience, and they catch issues that unit tests often miss.
    Reduced test maintenance. By eliminating unit tests, we reduced the time spent maintaining flaky or redundant tests. E2E tests focus on real-world scenarios, and when they fail, it's usually due to a genuine bug that needs fixing.

  3. You can focus on key flows. E2E testing allowed us to concentrate on what really matters: ensuring that core user flows work smoothly. We tested login, checkout, profile updates, and other critical paths. By focusing on these flows, we covered the majority of real-world use cases without drowning in test coverage.

Here's an example of an E2E test using Cypress:

describe('Login flow', () => {
  it('logs in a user and redirects to the dashboard', () => {
    cy.visit('/login');
    cy.get('input[name="username"]').type('testuser');
    cy.get('input[name="password"]').type('password123');
    cy.get('button[type="submit"]').click();

    cy.url().should('include', '/dashboard');
    cy.contains('Welcome back, testuser').should('be.visible');
  });
});

This simple test covers the full login flow, including real interactions with the backend API. No mocks, no fake services—just a real-world scenario that mirrors what a user experiences.

When unit tests might still be useful

I'm not suggesting that unit tests are useless in every situation. There are cases where unit tests make sense, especially when testing complex logic that doesn't depend on external services or when you have pure utility functions that need to behave a certain way.

For example, if you have a custom hook that transforms data or some complex business logic in a function, unit tests can help ensure these isolated pieces work as expected. But in most cases, for React components and frontend logic, E2E tests can provide far more value.

Be intentional about where you apply testing. Just because unit tests are a default practice doesn't mean they're always the best solution.

Finding the Balance

If you're questioning your current testing strategy, you're already on the right path.

Finding the balance between unit tests, integration tests, and E2E tests is crucial. In my experience, teams often lean too heavily on unit tests without realizing how much coverage their E2E tests are already providing.

To summarize:

  • Unit tests: Useful for testing isolated logic or functions, but less effective for testing user interactions in React apps.

  • E2E tests: Best for testing key flows and user journeys, providing real-world feedback on how your app behaves in production

If you'd like to reduce the amount of time spent manual testing your app, you may be interested in capture.dev - a bug reporting tool that automates the creation of bug reports and turns user errors into plain english.