Integration testing in React

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.

Table of contents

  1. What is integration testing ?

  2. What is the difference between unit testing and integration testing ?

  3. What is the difference between integration testing and end to end testing ?

  4. Principles of Integration testing

  5. Tools available for integration testing React apps

    1. Jest
    2. Enzyme
    3. React Testing Library
    4. Cypress Component and End2End testin tool
  6. Writing useful integration tests

  7. Conclusion

What is integration testing ?

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.

What is the difference between unit testing and integration testing ?

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.

What is the difference between integration testing and end to end testing ?

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.

pyramid of javascript testing, unit, integration and end to end

Principles of Integration testing

There are some broad principles you should remember when writing your integration tests. They are:

  1. Always test behaviour. Not implementation.
  2. Always keep unit tets and integration tests separate.
  3. When designing integration test think in terms of critical user journeys instead of exotic use cases.
  4. Keep integration tests as small as possible.

Tools available for integration testing React apps

React apps are javascript apps and hence they can use the wide variety of pure javascript or web integration testing tools. But there are also react specific tools available to achieve integration testing.

Jest

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.

Cons:

  • Really none.

Enzyme

Enzyme is a JavaScript Testing utility for React that makes it easier to test your React Components' output. You can also manipulate, traverse, and in some ways simulate runtime given the output.

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.


import React from 'react';
import { expect } from 'chai';
import { shallow } from 'enzyme';
import sinon from 'sinon';

import MyComponent from './MyComponent';
import Foo from './Foo';

describe('<MyComponent />', () => {
it('renders three <Foo /> components', () => {
const wrapper = shallow(<MyComponent />);
expect(wrapper.find(Foo)).to.have.lengthOf(3);
});

it('renders an `.icon-star`', () => {
const wrapper = shallow(<MyComponent />);
expect(wrapper.find('.icon-star')).to.have.lengthOf(1);
});

it('renders children when passed in', () => {
const wrapper = shallow((
<MyComponent>
<div className="unique" />
</MyComponent>
));
expect(wrapper.contains(<div className="unique" />)).to.equal(true);
});

it('simulates click events', () => {
const onButtonClick = sinon.spy();
const wrapper = shallow(<Foo onButtonClick={onButtonClick} />);
wrapper.find('button').simulate('click');
expect(onButtonClick).to.have.property('callCount', 1);
});
});

React Testing Library

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.


import {render, screen} from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import '@testing-library/jest-dom'
import Fetch from './fetch'

test('loads and displays greeting', async () => {
// ARRANGE
render(<Fetch url="/greeting" />)

// ACT
await userEvent.click(screen.getByText('Load Greeting'))
await screen.findByRole('heading')

// ASSERT
expect(screen.getByRole('heading')).toHaveTextContent('hello there')
expect(screen.getByRole('button')).toBeDisabled()
})


For more complex example refer to their official documentation.

Cypress Component and End2End testin tool

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.

Writing useful integration tests

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.

Conclusion

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.