Setting Up Tests for React using Mocha, Expect and Enzyme

Kayode Adeniyi
5 min readFeb 11, 2017

--

EDIT: The latest version of jsdom has some breaking changes, so might want to make sure that the version is not higher than `9.11.0`. Basically, go to your package.json file and change the line for jsdom to "jsdom": "9.11.0" .

I really wish all React developers knew that setting up tests for React is the easiest thing to do in life!

We will be using a sample app that I created in one of my previous posts. Click here to get the sample app or read Simplest React App Setup to do it yourself.

Introduction

If you already have a good understanding of what these modules (Mocha, Expect and Enzyme) are, you can skip to the next section (The Real Deal)

For the sake of newbies (even oldies) that are not familiar with these modules, I will like to give an overview. Mocha is a Javascript test framework. Test frameworks are used to organise and execute tests. Below is an example of what a test framework allows you to do.

describe('my code must work', () => {
it ('should work', () => {

})
it ('should not work', () => {

})
})

Alternatives to using Mocha are Jest, Jasmine, AVA, QUnit, Tape etc. Mocha like some other test frameworks does not have an assertion library out of the box, this is why we need one. Assertion libraries are tools that are used to verify that things are correct. For this tutorial, I will use Expect. Other assertion libraries include Chai, assert, should, YUIPort, JShould etc. Below is an example of what an assertion library does (Expect in this case).

user = {firstName: 'Kayode', lastName: 'Adeniyi'}
expect(user.firstName).toEqual('Kayode')
=> true

In order to test React, we also need a helper library. Facebook’s helper library for testing react is React Test Utils, but it is too verbose. I’ve decided to use Enzyme, which is an open source project by Airbnb. Enzyme is simply an abstraction. It uses React Test Utils, JSDOM and Cheerio behind the scene.

Also, I will be using an In-Memory test environment JSDOM. Other options are to test in the browser or a headless browser.

As a summary, the plan is stated below

What to test: React Components

How: Mocha + Expect + Enzyme

Where: In-memory DOM via JSDOM

The Real Deal

If you followed the instruction above, you should have a sample app set up that we can test. Below is a screenshot of what your folder structure should look like.

Please note that we need react-addons-test-utils because enzyme uses it under the hood.

Let’s start the adventure by running

npm install --save-dev mocha expect enzyme jsdom react-addons-test-utils

Create a test configuration file by running

touch testSetup.js

then copy and paste the code below. I’ve added comments that makes it easy to understand what is going on

// This file is written in ES5 since it's not transpiled by Babel./* This file does the following:
1. Sets Node environment variable
2. Registers babel for transpiling our code for testing
3. Disables Webpack-specific features that Mocha doesn't understand.
4. Requires jsdom so we can test via an in-memory DOM in Node
5. Sets up global vars that mimic a browser.
This setting assures the .babelrc dev config (which includes
hot module reloading code) doesn't apply for tests.
But also, we don't want to set it to production here for
two reasons:
1. You won't see any PropType validation warnings when
code is running in prod mode.
2. Tests will not display detailed error messages
when running against production version code
*/
process.env.NODE_ENV = 'test'// Register babel so that it will transpile ES6 to ES5 before our tests run.
require('babel-register')()
// Disable webpack-specific features for tests since
// Mocha doesn't know what to do with them.
require.extensions['.css'] = function () {return null}
// Configure JSDOM and set global variables
// to simulate a browser environment for tests.
var jsdom = require('jsdom').jsdom
var exposedProperties = ['window', 'navigator', 'document']global.document = jsdom('')
global.navigator = { userAgent: 'node.js' }
global.window = document.defaultView
Object.keys(document.defaultView).forEach((property) => {
if (typeof global[property] === 'undefined') {
exposedProperties.push(property)
global[property] = document.defaultView[property]
}
})
documentRef = document

Next, let’s update the npm script that will run our test. Open your package.json file and replace the test script with the code below

"test": "mocha --reporter spec testSetup.js \"components/*.spec.js\""

The format for writing our test will be to create the test file in the same folder as the component we want to test.

Let’s create our HelloWorld.spec.js file in the folder where we have HelloWorld.js. Run the code below to create it

touch components/HelloWorld.spec.js

You can decide to name your file HelloWorld.test.js but remember to change it in test script of your package.json.

Next, copy and paste the code below

import React from 'react'
import expect from 'expect'
import { shallow, mount } from 'enzyme'
import HelloWorld from './HelloWorld'
const wrapper = shallow(<HelloWorld />)describe('HelloWorld Component', () => { it('renders h1', () => {
expect(wrapper.find('h1').text()).toEqual('Hello World')
})
it('renders p', () => {
expect(wrapper.find('p').text()).toEqual('Welcome to my world')
})
})

Please note, shallow should be used when the children of a component are not needed to be rendered or when a component does not have a child, while mount should be used when the children of a component needs to be rendered alongside the component. Refer to Enzyme docs for more info.

After the above steps have been completed, the next thing to do is to run our test.

Run

npm test

If all went well, the two tests above should pass.

If you liked this, click the 💚 below so other people will see this here on Medium. Also, if you have any questions or observations, use the comment section to share your thoughts/questions.

#3

--

--