Integration testing in React
Unit testing tests a unit of your code but integration testing tests how your entire app functions with all different components together. Often, integration tests catch important bugs that are result of interplay between different components.
In this guide we give you a comprehensive overview of what different tools you can use to do integration tests for your react app.
Integration testing is a testing methodology that tests behaviour of a system comprising of different components and specifically testing how these components behave together.
In React, we often design web applications as component tree. There might be an Add To Cart button somewhere that updates the Cart component with a count of products in the cart. This involves inter component communication.
While you can use unit testing to test both components independently, you might want to test how they behave together. Such testing might require setting up the whole app, set the initial state and then run specific flows to test different types of interactions.
To achieve this there is a wide variety of tooling available for the react ecosystem.
Unit testing tests one component or just one api at a time. It makes no assumptions about who is going to use the component and how. Unit testing as the name suggests is the most basic level of testing.
Integration tests are always done to test the interaction between one or two components. A real world example would be that you might design a perfect car and you know works and you also design the perfect tire that ever existed yet the tire needs to fit the car. We need to make sure that future engineers who work on the car and tire do not change the specs in a way that the tire does not fit the car.
While integration tests are a bit high level tests compared to unit tests they are still pretty low level compared to the end to end tests. End to end tests work as if the end user is using your front end. So we think more like user.
End to end tests are a bit like taking a car you just created on a test drive.
The following graphics tells you the relationship between unit tests, integration tests and end to end tests.
There are some broad principles you should remember when writing your integration tests. They are:
- Always test behaviour. Not implementation.
- Always keep unit tets and integration tests separate.
- When designing integration test think in terms of critical user journeys instead of exotic use cases.
- Keep integration tests as small as possible.
Jest is a testing framework originally created by Meta. The same company that is behind React. Jest however is very powerful and can work with any other JS library such as Vue or Angular beside React. It can be used to write both unit tests as well as integration tests and following a "zero config" philosophy.
Pros of Jest:
- Jest works with most major frameworks like Vue, Angular, React and many more.
- It was originally based on Jasmine, retains all good features of it.
- It supports Typescript.
- Can mock hard to mock timing apis like setTimeout() setInterval().
- It can help you do unit tests as well as end to end tests with puppeteer.
- Allows snapshot testing.
- Really none.
Enzyme gives you jQuery like API to check output of a specific React component or combination of multiple components. Enzyme must be used with other testing and assertion libraries like Mocha or Chai.
React Testing Library might have a very generic name but it is extremely powerful and intuitive testing library you can use for integration testing your react apps.
For more complex example refer to their official documentation.
Cypress is also very popular but is a paid product. Cypress has everything you need to test your React and other framework based applications along with clear dashboards that tell you the state of health of your code.
Cypress can also run end to end tests for you in all the major browsers. This makes it easier to adopt as part of your development process. Many large companies hence prefer Cypress over Jest.
Remember to write minimal integration tests that test real world integrations and do not write integration tests for 100% coverage unless it is critical to your project. Do not try to test integrations that are unlikely to happen in real world.
Whenever you encounter bugs in your apps ask yourself if you could have written an integration test to detect it during development phase.
One principle to adopt is that if you have fewer public apis you have fewer unit tests to write. If you have fewer inter-component communication then you have fewer integration tests to write. This means you have to be extremely careful whenever you create a component that either depends on external input or provides input to another component, as you might have to cover those cases with integration tests now.
React integration testing has a very good ecosystem of testing frameworks out of which Jest appears to offer the best of all worlds. If I were to pick one of these, I would have picked Jest.