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
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!
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.
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:
Perfect!
I’ve been banging my head all over the web just to fix this issue. Three days later, i find this article. Worked like a charm. Thanks. 🙂
Very well explained. Saved my day.