Setting up React Jest and Enzyme

Jest is a popular JS framework for testing React js applications. By itself, it may need additional functionality to test React capabilities. Enzyme is a tool used to facilitate component testing.

In this quick overview, we will setup a React 16 CRA application with Jest & Enzyme using NPM.

Assuming we have our application created from

npx create-react-app my-app

Hop into our app directory “my-app” and notice the “node_modules” folder. By itself, there are many existing capabilities that our provided out of the box, one of which being jest

Node_modules containing jest

 

 

 

 

 

 

So according to the Jest documentation for getting started, we can specify a “test” command for NPM to run jest. By default test will look for in a few places  one of them being the existing “App.test.js” file created from CRA. Lets edit it with a pure Jest test and run “npm test”.

package.json

{
  "name": "test-app",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "@material-ui/core": "^3.8.3",
    "react": "^16.7.0",
    "react-dom": "^16.7.0",
    "react-router-dom": "^4.3.1",
    "react-scripts": "2.1.3"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "jest",
    "eject": "react-scripts eject"
  },
  "eslintConfig": {
    "extends": "react-app"
  },
  "babel"
  "browserslist": [
    ">0.2%",
    "not dead",
    "not ie <= 11",
    "not op_mini all"
  ]
}

App.test.js

import React from 'react';

test('renders without crashing', () => {
  expect(1).toBe(1);
});

Running “npm test” we get the error

({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,global,jest){import React from 'react';
^^^^^

SyntaxError: Unexpected identifier

Based on the error, (first line of our test file) it looks like the compiler is complaining about the React and ES6 syntax. Reading more in Jest, getting started, it states that we have should also specify a .babelrc file in order to use ES6 and react features in  Jest.  Lets go ahead and add that file in the CRA root.

.babelrc

{
"presets": ["@babel/env", "@babel/react"]
}

Now if we rerun the test again “npm test” we should see a pass. Great!

Passing Jest test

The test we have at the moment does not test anything specific to React, i.e. component rendering. To get this working we want to use Enzyme — It is not provided from CRA. Here’s the guide.

$ npm install --save-dev enzyme enzyme-adapter-react-16

We also need to add a setup file before using Enzymes features. The following helper file is added in the CRA root folder

enzyme.js

// setup file
import Enzyme, { configure, shallow, mount, render } from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';

configure({ adapter: new Adapter() });
export { shallow, mount, render };
export default Enzyme;

Back in our App.test.js we can edit the test to check if our js component will render.

import React from 'react';
import App from './App';
import { shallow } from './enzyme';

test('renders without crashing', () => {
	const app = shallow(<App/>);
	expect(app.containsAnyMatchingElements([<a>
        Learn React
      </a>
    ])
  ).toBe(true);
});

Here’s what we see.

Jest encountered an unexpected token

The error is from an import inside our test component “App.js” stating ” Jest encountered an unexpected token”. From the output, it looks like the svg file is being parsed incorrectly. This error has been noted elsewhere.

We start by adding the assetTransformer.js file in the root

assetTransformer.js

const path = require('path');

module.exports = {
  process(src, filename, config, options) {
    return 'module.exports = ' + JSON.stringify(path.basename(filename)) + ';';
  },
};

And allow Jest to perform this transformation on assets during module mapping. This is done by adding an attribute in the “jest” property of package.json

{
  "name": "test-app",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "@material-ui/core": "^3.8.3",
    "react": "^16.7.0",
    "react-dom": "^16.7.0",
    "react-router-dom": "^4.3.1",
    "react-scripts": "2.1.3"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "jest",
    "eject": "react-scripts eject"
  },
  "eslintConfig": {
    "extends": "react-app"
  },
  "browserslist": [
    ">0.2%",
    "not dead",
    "not ie <= 11",
    "not op_mini all"
  ],
  "jest": { 
    "moduleNameMapper": { 
      "\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/assetTransformer.js", 
      "\\.(css|less)$": "<rootDir>/assetTransformer.js" 
    } 
  },
  "devDependencies": {
    "enzyme": "^3.8.0",
    "enzyme-adapter-react-16": "^1.7.1"
  }
}

Here’s what we get from “npm test” this time:

Passing Jest + Enzyme test

Perfect!