Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unit testing ES7 React components with Jest

How do you make Jest play nicely with ES7 initializers? I've searched far a wide on here and other sources, but didn't find anything conclusive.

.babelrc.js

{
    "env": {
        "development": {
            "presets": [["es2015", { "modules": false }], "react", "react-hmre"],
            "plugins": [
                "transform-class-properties",
                "react-hot-loader/babel"
            ]
        },
        "test": {
            "presets": ["env", "react"],
            "plugins": ["transform-class-properties"]
        },
        "production": {
            "presets": [["es2015", { "modules": false }], "react"],
            "plugins": ["transform-class-properties"]
        }
    }
}

package.json

    {
    "name": "demo",
    "version": "1.0.0",
    "main": "index.js",
    "license": "MIT",
    "private": true,
    "dependencies": {
        "react": "^15.5.4",
        "react-dom": "^15.5.4",
    },
    "devDependencies": {
        "babel-cli": "^6.24.1",
        "babel-core": "^6.24.1",
        "babel-jest": "^20.0.3",
        "babel-plugin-transform-class-properties": "^6.24.1",
        "babel-polyfill": "^6.23.0",
        "babel-preset-env": "^1.5.2",
        "babel-preset-es2015": "^6.24.1",
        "babel-preset-react": "^6.24.1",
        "babel-preset-react-hmre": "^1.1.1",
        "enzyme": "^2.8.2",
        "react-hot-loader": "next",
        "babel-plugin-import": "^1.2.1",
        "enzyme": "^2.9.1",
        "enzyme-to-json": "^1.5.1"
    },
    "scripts": {
        "test": "export NODE_ENV=test && ./node_modules/.bin/jest --no-cache"
    },
    "engines": {
        "node": ">= 7.8.0"
    },
    "jest": {
        "verbose": true,
        "collectCoverage": true,
        "coverageDirectory": "__coverage__",
        "mapCoverage": true,
        "setupFiles": [
            "./tests/setup.js"
        ],
        "testPathIgnorePatterns": [
            "/node_modules/"
        ],
        "transform": {
            "\\.js$": "../node_modules/babel-jest"
        },
        "testRegex": ".*\\.test\\.js$",
        "snapshotSerializers": [
            "enzyme-to-json/serializer"
        ]
    }
}

Demo.jsx

import React from 'react';
import PropTypes from 'prop-types';

export class Demo extends React.Component {

    static props = { name: PropTypes.string.isRequired };

    constructor(props) {
        super(props);
    }

    render() {
        return (
            <div className='demo'>{this.props.name}</div>
        );
    }

}

Demo.test.js

import React from 'react';
import { Demo } from '..';
import { render } from 'enzyme';


describe('Demo', () => {
    it('renders correctly', () => {
        const wrapper = render(<Demo name="foo" />);
        expect(wrapper).toMatchSnapshot();
    });
});

After running yarn test or export NODE_ENV=test && ../node_modules/.bin/jest --no-cache, Jest will complain that it sees an unexpected character

 8 |     props = {
   |           ^
 9 |         name: PropTypes.string.isRequired

From my understanding, the environment variable set when we run the tests should automatically transform the initializers to something which can be used by Jest, but this doesn't appear to be happening.

I am also using webpack 2.x, but the configuration overhead to get that to work seems daunting. Is there another way?

Update 1

I modified my Jest settings as follows:

 "transform": {
      "\\.js$": "./node_modules/babel-plugin-transform-class-properties"
 }

This failed immediately with:

TypeError: Jest: a transform must export a process function.

Removing transform altogether yields a slightly different issue:

TypeError: Cannot read property 'props' of null

I also added the constructor to the Demo component.

like image 603
djthoms Avatar asked Jun 28 '17 05:06

djthoms


2 Answers

I believe if you are trying to add propTypes, with ES7 initializers and using the transform-class-properties you need to do

static propTypes = {
    name: PropTypes.string.isRequired
};

So it would be

import React from 'react';
import PropTypes from 'prop-types';

export class Demo extends React.Component {

    static propTypes = {
        name: PropTypes.string.isRequired
    };

    render() {
        return (
            <div className='demo'>{this.props.name}</div>
        );
    }

} 

Pretty sure you do not have to explicitly define props as it is part of the React.Component when you extends from it. That or you may need to declare constructor and then call super(props);

like image 177
aug Avatar answered Oct 13 '22 19:10

aug


Jest uses babel to transpile JS code. You need to add support for ES7 features in .babelrc file.

Here are the steps:

  1. Do npm install --save-dev babel-preset-stage-0 babel-jest
  2. In your package.json, add babel-jest for transforming all the js files.
  3. In your .babelrc file, add "stage-0" preset.

Here is how my package.json looks like:

...
"jest": {
    "transform": {
      "^.+\\.js$": "babel-jest"
    }
}
...

And here is how my .babelrc file looks like:

{
  "presets": [
    "es2015",
    "react",
    "stage-0"
  ]
}
like image 28
Rahul Gaba Avatar answered Oct 13 '22 18:10

Rahul Gaba