Testing React Styled Components with Jest & Enzyme

At Fast Web Media we develop a number applications - from small scale, to large scale. React is our tool of choice for many of these builds, due to its blisteringly fast performance, excellent developer tools, React Native for mobile experiences, and the clean abstraction that it encourages. This abstraction allows us to think about our application in smaller, more manageable chunks, which in turn, makes it easier to reuse and more importantly: test.

Why do I need to test my React Components?

Testing can be a developer's best friend and worst enemy; on one hand it can provide a clear set of instructions about what needs to be coded and the confidence that what has been built will actually work correctly, but on the other hand, tests take time to create and must be maintained when code is refactored.

The real strength in testing comes whilst working as part of a team. When Developer B comes to make changes to Developer A’s component further down the line, they are able to quickly see what is currently expected from the component and if any of their new amends have affected the expected behaviour in any way.

Jest & Enzyme

We use Jest as a test runner for our applications. Jest was built by Facebook and, in its own words:

  • Jest is used by Facebook to test all JavaScript code including React applications.
  • One of Jest's philosophies is to provide an integrated "zero-configuration" experience.
  • We observed that when engineers are provided with ready-to-use tools, they end up writing more tests, which in turn results in more stable and healthy code bases.

Enzyme is a JavaScript Testing utility built by Airbnb that makes it easier to assert and manipulate your React Components' output.

Enzyme's API is meant to be intuitive and flexible by mimicking jQuery's API for DOM manipulation and traversal, which makes testing-specific nested components a breeze as we will cover further in this post.

Styled Components

We use Styled Components to apply CSS styles to our individual components for a number of reasons, including the ability to use SCSS nesting, apply conditional styling rules based on passed in props, and the ability to use the same CSS for React Native applications.

How do I get started?

Jest, although packaged with Create React App by default is not specifically designed to be used with React and so can be used to test any javascript code with minimum setup.

Firstly, we use yarn instead of npm, as it is currently faster and has many other improvements.

Create your React Application using the console command:

create-react-app my-app

This will install Jest and the required dependencies that you need to run a basic test.

Install Enzyme and Styled Components

yarn add enzyme jest-enzyme react-test-renderer jest-styled-components --dev
yarn add styled-components

We are now setup to create a styled component and tests.

Writing a basic Test

A good rule of thumb for unit testing in general is to write your tests first; this gives you a clear guide of what needs to be achieved and you get that warm, fuzzy feeling of your tests passing one by one as you complete each step of your component. However, fuzzy feeling aside, one of the main benefits for Jest is Snapshot testing, which encourages you to write your component first and test the difference between the outputs after.

The basic idea is to create a test that automatically generates a JSON file of your component’s rendered output. Each time a new test is run, Jest will check the difference between the stored ‘snapshot’ of your component and the new JSON output and flag any differences. This greatly speeds up writing tests as you do not need to test that each title should equal the same title as before.

Let's start with a basic styled component that loops through passed in props and renders a UL element:

List.js

import React from 'react'
import { array } from 'prop-types'

// Import the styles from a separate file and
// prepend component name with 'Styled' for consistency
import StyledList from './List.styles'

class List extends React.Component {
  render() {
    return (
      <StyledList>
        <ul>
          {this.props.items.map((item, key) =>
            <li key={key}>
              {item.title}
            </li>
          )}
        </ul>  
      </StyledList>
    )
  }
}

List.propTypes = {
  items: array
}

export default List

List.styles.js

import styled from 'styled-components'

const List = styled.div`
  position: relative;
  background-color: #ffffff;
`

export default List

_tests_/List.test.js

import React from 'react'
import renderer from 'react-test-renderer'
import { shallow, mount } from 'enzyme'
import 'jest-enzyme'
import 'jest-styled-components'

// Import component to be tested
import List from '../List'

describe('Component: List', () => {
  const items =
    { title: 'List Item 1' },
    { title: 'List Item 2' },
    { title: 'List Item 3' },
    { title: 'List Item 4' }
  ]

  // Snapshot test
  it('should render', () => {
    const component = <List items={items} />

    const tree = renderer.create(component).toJSON()
    expect(tree).toMatchSnapshot()
  })
})

Run the test

yarn test

or for auto refresh every time you change a file:

yarn test -- --watch

An extra --coverage attribute can be passed that will generate a code coverage report in the console, highlighting which lines are still to be tested. A HTML report is also created by default in the coverage/ folder:

Testing props with mount

Snapshot testing is excellent to test the overall output of the component, but you might be thinking, “what about the nested items inside?” This is where mount from the Enzyme library really shines.

To test that, the List component renders what we expect based on the props we pass in, the mount and find functions allow us to traverse down the DOM until we find the list items and it returns a count that we can test against.

it('should render 4 list items based on props.items', () => {
  const component = mount(<List items={items} />)

  expect(component.find('li')).toHaveLength(4)
})

Testing event handlers

Here is the updated List component with a button and new onClick prop that is called when a user clicks the button:

import React from 'react'
import { array, func } from 'prop-types'

// Import the styles from a separate file and
// prepend component name with 'Styled' for consistency
import StyledList from './List.styles'

class List extends React.Component {
  render() {
    return (
      <StyledList>
        <ul>
          {this.props.items.map((item, key) =>
            <li key={key}>
              {item.title}
            </li>
          )}
        </ul>
        <button type="button" onClick={this.props.onClick}>
          Do Something
        </button>
      </StyledList>
    )
  }
}

List.propTypes = {
  items: array,
  onClick: func
}

export default List

This can be tested using the Enzyme simulate function to simulate user events.

it('should call props.onChange when button is clicked', () => {
  const mockFunction = jest.fn() // In-built Jest function mocker
  const component = mount(<List items={items} onClick={mockFunction} />)

  // Test before event
  expect(mockFunction).not.toHaveBeenCalled()

  // simulate the click event
  component.find('button').simulate('click')

  // Test after event
  expect(mockFunction).toHaveBeenCalled()

  // Can also test inner text of button
  expect(component.find('button').text()).toContain('Do Something')
})

Testing component styling

We have covered how to test the expected functionality of components by using the jest-styled-components library we installed earlier, we can now test the CSS styling of components too.

A simple example would be to test that the background of our component is black (#000000).

it('should render List with the correct styles', () => {
  const component = mount(<List items={items} onClick={jest.fn()} />)

  expect(component).toHaveStyleRule('background-color', '#000000')
})

More Jest Styled Component examples, including media query testing can be found here.

Debugging

Use Enzyme’s debug method to print renderer’s output:

const wrapper = mount(/*~*/)
console.log(wrapper.debug())

Advanced Jest Testing

The next instalment of this Jest testing guide will include some slightly more advanced testing techniques for React Components including:

  • Shallow rendering components.
  • Testing React Lifecycle methods using Sinon.
  • Testing Redux actions and reducers.

And more...

Conclusion

Using Jest testing for our React applications has given us confidence in the code that we write and has forced us to think about our projects in a more modular way. We have found this has helped to validate edge cases with ease, and flatten out bugs that we might have missed otherwise.

Do you have any questions about React applications, Jest testing or Enzyme? Tweet us @FastWebMedia - and let our developers know what you’d like to see in part 2 of this guide!

We hope you enjoyed reading

Related Articles