javascriptbabeljstestem

Testem receiving imports compiled to `require` when using ES2015/React presets to Babel


I have a project which is set up so that it builds with and . It works fine to build it using node_modules/webpack/bin/webpack.js --config webpack.config.js and I can run the result in the browser with no problems. However, when I run npm test and view the test runner in the browser, I get the error: "Uncaught ReferenceError: require is not defined at dashboard-tests.js:3". It seems that webpack is compiling my tests (but not my normal code) into a version of that can't be run in browsers.

Here are the relevant files:

.babelrc:

{
   "presets": ["es2015", "react"]
}

testem.json:

{
  "framework": [
    "jasmine"
  ],
  "launch_in_dev": [
    "PhantomJS"
  ],
  "launch_in_ci": [
    "PhantomJS"
  ],
  "serve_files": [
    "tmp/**/*-test{,s}.js"
  ],
  "on_start": "babel static_source --out-dir tmp",
  "on_exit": "yes | rm -r tmp"
}

package.json:

{
  "main": "index.js",
  "scripts": {
    "test": "testem"
  },
  "dependencies": {
    "jquery": "^3.2.1",
    "prop-types": "^15.6.0",
    "react": "^16.0.0",
    "react-dom": "^16.0.0",
    "react-feather": "^1.0.7"
  },
  "devDependencies": {
    "babel-cli": "^6.26.0",
    "babel-core": "^6.26.0",
    "babel-loader": "^7.1.2",
    "babel-preset-env": "^1.6.1",
    "babel-preset-react": "^6.24.1",
    "jasmine-es6": "^0.4.3",
    "testem": "^1.18.4",
    "webpack": "^3.6.0"
  }
}

webpack.config.js:

var path = require("path");
var webpack = require('webpack');

module.exports = {
  context: __dirname,
  entry: './static_source/js/index.js', 
  output: {
    path: path.resolve('./app/static/js/'),
    filename: "compiled.js"
  },
  plugins: [],
  module: {
    loaders: [
      { test: /\.js$/, loader: 'babel-loader', exclude: /node_modules/ },
      { test: /\.jsx$/, loader: 'babel-loader', exclude: /node_modules/ }
    ],
  }
}

dashboard-tests:

import React from 'react';
import ReactDOM from "react-dom";
import TestUtils from "react-dom/test-utils";

import Dashboard from './dashboard';

describe('Dashboard', function() {
  it('exists', function() {
    expect(Dashboard).not.toBe(undefined);
  });

  it('renders arrows', function() {
    var dashboard = <Dashboard />;
    var renderedDashboard = TestUtils.renderIntoDocument(dashboard);

    var arrowsDiv = TestUtils.findRenderedComponentWithClass('arrows');

    expect(arrowsDiv).not.toBe(undefined);
  });
});

Solution

  • You are using Babel to compile your test source files. Babel is just a transpiler, it takes ES+ files and translates them to ES5 files. Because import does not exist in ES5 Babel replaces them with require().

    To fix the problem you need to bundle your source file into one, using Webpack.

    You will need a separate Webpack configuration file, let's call it webpack.config.test.js. In this file we need to instruct Webpack to fetch all your static_source/**/*-test{,s}.js files as entry-points. You will need the glob module : npm install glob --save-dev. Then add the webpack.config.test.js file with this content :

    var path = require("path");
    var glob = require('glob');
    var webpack = require('webpack');
    
    module.exports = {
      context: __dirname,
      // we look for all file ending with -test(s?).js and return the absolute path
      entry: glob
          .sync('./static_source/js/**/*-test{,s}.js')
          .map(function(file) { return path.resolve(__dirname, file) }),
      output: {
        // save the resulting bundle in the ./tmp/ directory
        path: path.resolve('./tmp/'),
        filename: "compiled.js"
      },
      plugins: [],
      module: {
        loaders: [
          { test: /\.js$/, loader: 'babel-loader', exclude: /node_modules/ },
          { test: /\.jsx$/, loader: 'babel-loader', exclude: /node_modules/ }
        ],
      }
    }
    

    On the testem.json file replace the on_start with a before_test to Webpack, and the serve_files to map to the bundled file.

    "before_tests": "webpack --config webpack.config.test.js ",
    "serve_files": [
        "tmp/compiled.js"
    ],
    

    When testem will be launched it will trigger the Webpack test compilation. Now you should have a tmp/compiled.js file with all your test files bundled. You may need to do some tweaking but it should basically works.