//

TESTING REACT COMPONENTS WITH ENZYME

React has become the framework of choice recently within the JavaScript community. And the tools for testing React components has also gained lot of attention.

Enzyme by Airbnb has been one of the popular choices for testing React components. In this article, we will look at how write tests with Enzyme and Mocha.

Installation

We need Node.js installed to begin with. Follow the link, download Node.js for installation instructions.

Now create a folder for your project and then run the following command in command line.

npm init

Babel

We need Babel to compile JSX code.

npm install babel-cli ––save
npm install babel-preset-react babel-preset-es2015 ––save

Webpack

We are going to use Webpack to build our project.

npm install webpack webpack-dev-server babel-loader ––save–dev

React

npm install react react-dom ––save

Mocha

We need to install testing tools:

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

Setting Up

Create .babelrc

In order to create a preset to use Babel, we have to create a .babelrc file.

{
  "presets": ["airbnb", "es2015", "stage-0"]
}

We need to install the presets:

npm install babel-preset-stage-0 babel-preset-stage-airbnb ––save–dev

Create a webpack.config.js

var path = require('path');
var webpack = require('webpack');
 
// env
var buildDirectory = './dist/';
 
module.exports = {
  entry: './lib/main.jsx',
  devServer: {
    hot: true,
    inline: true,
    port: 7700,
    historyApiFallback: true,
  },
  resolve: {
    extensions: ['', '.js', '.jsx'],
  },
  output: {
    path: path.resolve(buildDirectory),
    filename: 'app.js',
    publicPath: 'http://localhost:7700/dist',
  },
  externals: {
    'cheerio': 'window',
    'react/lib/ExecutionEnvironment': true,
    'react/lib/ReactContext': true,
  },
  module: {
    loaders: [{
      test: /\.jsx?$/,
      exclude: /(node_modules|bower_components)/,
      loader: 'babel',
      query: {
        presets: ['react', 'es2015', 'stage-0'],
      },
    }],
  },
  plugins: [],
};

The configuration for externals will help enable enzyme to work properly.

Create browser.js

We create a setup file in order to provide a realistic browser environement using jsdom.

require('babel-register')();
 
var jsdom = require('jsdom').jsdom;
 
var exposedProperties = ['window', 'navigator', 'document'];
 
global.document = jsdom('');
global.window = document.defaultView;
Object.keys(document.defaultView).forEach((property) => {
  if (typeof global[property] === 'undefined') {
    exposedProperties.push(property);
    global[property] = document.defaultView[property];
  }
});
 
global.navigator = {
  userAgent: 'node.js'
};
 
documentRef = document;

The package.json Scripts

Add the following to the scripts sections of the package.json file.

   "test": "mocha -w test/helpers/browser.js test/*.spec.js",
   "dev:hot": "webpack-dev-server --hot --inline --progress --colors --watch --display-error-details --display-cached --content-base ./"
 },

Creating Components

Create a containers folder and a LoginForm.js file.

import React from 'react';
import FormField from '../components/FormField';
 
class LoginForm extends React.Component {
  render() {
    return (
      <form>
        <FormField model="user.username" label="Username" type="text" />
        <FormField model="user.password" label="Password" type="password"/>
        <button>Log in</button>
      </form>
    );
  }
}
 
export default LoginForm;

Create a components folder and a FormField.js file.

import React from 'react';
 
const FormField = ({ label, type }) => {
  return (
    <field>
      <label>{label}</label>
      <input type={type} />
    </field>
  );
};
 
export default FormField;

Testing Components.

Create a test folder and create a LoginForm.spec.js file in it.

import React from 'react';
import { mount, shallow } from 'enzyme';
import { expect } from 'chai';
 
import LoginForm from '../containers/LoginForm';
import FormField from '../components/FormField';
 
describe('<LoginForm/>', function () {
  it('should have a button to submit the form', function () {
    const wrapper = shallow(<LoginForm/>); // highlight
    expect(wrapper.find('button')).to.have.length(1);
  });
 
  it('should have props for model, label and type', function () {
    const wrapper = shallow(<LoginForm/>);
    expect(wrapper.props().model).to.be.defined;
    expect(wrapper.props().label).to.be.defined;
    expect(wrapper.props().type).to.be.defined;
  });
 
  it('contains an <FormField/> component', function () {
    const wrapper = mount(<FormField/>);
    expect(wrapper.find(FormField)).to.have.length(1);
  });
});

Not the highlighted line: The shallow method from enzyme will allow us to “shallowly” render a component. This type of rendering is used to isolate one component for testing and ensure child components do not affect assertions.

mount

The mount method helps real rendering that will actually render your component into a browser environment. If you are creating full React components (and not just stateless components), you will want to use mount to do testing on the lifecycle methods of your component.

Now run the tests in the command line:

npm test

Conclusion

We have worked through creating a simple React component, installing test tools and running actual tests. I hope this tutorial will help you to kick start testing with React.