DEV Community

Edielton Dantas
Edielton Dantas

Posted on • Updated on

Testing React components with Jest and Enzyme

Our React application is missing a critical component: Tests. In this section, we will configure Jest and Enzyme step-by-step. At the end of the tutorial, we should be able to run tests against a simple component.

Setting up Jest

Jest is a testing framework that is commonly used for testing React apps.

Note: Actually, you can test pretty much all the major frameworks on the market today with Jest.

Dependencies

$ yarn add jest babel-jest @types/jest -D
Enter fullscreen mode Exit fullscreen mode

Basic example

$ touch src/sample.test.js
$ open src/sample.test.js
Enter fullscreen mode Exit fullscreen mode
describe('Sample test', () => {
  test('should be equal to 1', () => {
    expect(1).toBe(1)
  })
})
Enter fullscreen mode Exit fullscreen mode

Now head on to your package.json file and add a new script for running tests:

$ open package.json
Enter fullscreen mode Exit fullscreen mode
{
  "scripts": {
    "build": "webpack",
    "test": "jest"
  },
  ...
}  
Enter fullscreen mode Exit fullscreen mode
$ yarn test
Enter fullscreen mode Exit fullscreen mode

Alt Text

Adding support to React

The previous setup allows you to run tests against plain javascript objects only. In order to make Jest "understand" React, you need to use Babel.

You can add this configuration in an external file or inside package.json. For the sake of simplicity, I'm using package.json to configure Jest.

$ open package.json
Enter fullscreen mode Exit fullscreen mode
{
  "scripts": {
    "build": "webpack",
    "build:watch": "webpack --watch",
    "test": "jest"
  },
  "babel": {
    "presets": [
      "@babel/env",
      "@babel/react"
    ]
  },
  ...
}  
Enter fullscreen mode Exit fullscreen mode

Enzyme

Enzyme is a testing utility that allows you to manipulate and traverse React components. It really comes in handy when you need to test whether a callback was fired via user interaction or, for instance, whether a component has subcomponents.

Dependencies

$ yarn add enzyme jest-enzyme enzyme-adapter-react-16 -D
Enter fullscreen mode Exit fullscreen mode

Configuration file

$ touch src/setupTests.js
$ open src/setupTests.js
Enter fullscreen mode Exit fullscreen mode
import { configure } from 'enzyme'
import Adapter from 'enzyme-adapter-react-16'

configure({ adapter: new Adapter() })
Enter fullscreen mode Exit fullscreen mode

Note: In order to be fully compatible with React, Enzyme provides an adapter to each React version.

Package.json

Last but not least, we need to configure Jest to run Enzyme's configuration file after the test environment has been installed.

$ open package.json
Enter fullscreen mode Exit fullscreen mode
{
  "scripts": {
    "build": "webpack",
    "build:watch": "webpack --watch",
    "test": "jest"
  },
  "jest": {
    "setupFilesAfterEnv": [
      "<rootDir>/src/setupTests.js"
    ],
    "testPathIgnorePatterns": [
      "<rootDir>/node_modules/"
    ]
  },
  "babel": {
    "presets": [
      "@babel/env",
      "@babel/react"
    ]
  },
  ...
}
Enter fullscreen mode Exit fullscreen mode

Putting it all together

Remember that App component we created in the previous tutorial? We will move it to its own file and run a basic test to check whether or not it's rendering correctly.

Move App component to its own file

$ touch src/App.jsx
$ open src/App.jsx
Enter fullscreen mode Exit fullscreen mode
import React from 'react'

const App = () => (
  <div>
     <h1>App component</h1>
     <p>Hello world!</p>   
  </div>
)

export default App
Enter fullscreen mode Exit fullscreen mode

Update index.js

$ open src/index.js
Enter fullscreen mode Exit fullscreen mode
import React from 'react'
import { render } from 'react-dom'

import './App.scss'
import App from './App.jsx'

render(
  <App />,
  document.getElementById('app')
)
Enter fullscreen mode Exit fullscreen mode

Test drive

$ touch src/App.test.js
$ open src/App.test.js
Enter fullscreen mode Exit fullscreen mode
import React from 'react'
import { shallow } from 'enzyme'

import App from './App'

describe('App', () => {
  test('should render', () => {
    const wrapper = shallow(
      <App />
    )

    expect(wrapper.exists()).toBeTruthy()
  })
})
Enter fullscreen mode Exit fullscreen mode

And finally run the test:

$ yarn test
Enter fullscreen mode Exit fullscreen mode

Alt Text

Module Mappings

Thanks to Loaders, we can import things like style sheets or images from a javascript file as if they were modules.

If you attempt to load such a module from your React component, you'll get an error like the one below:

SyntaxError: Invalid or unexpected token

The recommended approach is to create a folder with two files: one for styles and another for files.

# Create a directory at the root level
$ mkdir __mocks__
Enter fullscreen mode Exit fullscreen mode

Mock module for dealing with files

$ touch __mocks__/fileMock.js
$ open __mocks__/fileMock.js
Enter fullscreen mode Exit fullscreen mode
// __mocks__/fileMock.js

module.exports = {}
Enter fullscreen mode Exit fullscreen mode

Mock module for dealing with styles

$ touch __mocks__/styleMock.js
$ open __mocks__/styleMock.js
Enter fullscreen mode Exit fullscreen mode
// __mocks__/styleMock.js

module.exports = {}
Enter fullscreen mode Exit fullscreen mode

Mapping the file types to their respective mock modules

$ open package.json
Enter fullscreen mode Exit fullscreen mode
{
  "scripts": {
    "build": "webpack",
    "build:watch": "webpack --watch",
    "test": "jest",
    "test:watch": "jest --watchAll"
  },
  "jest": {
    "moduleNameMapper": {
      "\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/__mocks__/fileMock.js",
      "\\.(css|less|scss|sass)$": "<rootDir>/__mocks__/styleMock.js"
    },
    "setupFilesAfterEnv": [
      "<rootDir>/src/setupTests.js"
    ],
    "testPathIgnorePatterns": [
      "<rootDir>/node_modules/"
    ]
  },
  ...
}  
Enter fullscreen mode Exit fullscreen mode

Note: I added a new script called "test:watch" under "scripts". As you might have guessed, this allows us to edit our source code / tests and have Jest re-run them for us.

Conclusion

This tutorial was supposed to be a 3 parts series on how to set up a basic React app without CRA, but due to the lengthy explanations, I'm planning on expanding it to.

In the next section, we will add support to linting and use a few webpack plugins to improve our development experience.

Top comments (0)