djthoms
djthoms

Reputation: 3106

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.

Upvotes: 5

Views: 2480

Answers (2)

Rahul Gaba
Rahul Gaba

Reputation: 480

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"
  ]
}

Upvotes: 1

aug
aug

Reputation: 11714

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);

Upvotes: 3

Related Questions