Monday, October 15, 2018

use webpack plugin with Mocha tests

Leave a Comment

I've used create-react-app to create an app, and ejected the config. In webpack.config.dev.js and webpack.config.prod.js, I've configured the NormalModuleReplacementPlugin like so:

new webpack.NormalModuleReplacementPlugin(/(.*)CUSTOMER(\.*)/, function(resource) {   const customerName = process.env.REACT_APP_CUSTOMER;   resource.request = resource.request.replace(/CUSTOMER/, customerName); }) 

The purpose of this is to replace imports such as

import config from '../config/customer/CUSTOMER'; 

with

import config from '../config/customer/foo'; 

when the value of the REACT_APP_CUSTOMER variable is set to "foo".

This works fine when the app runs, but I have some Mocha tests that are run via a test-mocha script in package.json

"scripts": {   "test-mocha": "NODE_ENV=test node_modules/.bin/mocha --require babel-register --recursive test" } 

When this test runs, the import replacement doesn't happen. It seems either of the following would solve the problem:

  • configure the NormalModuleReplacementPlugin to be used when the tests are run
  • find a way to provide a mock for config when the tests are run

5 Answers

Answers 1

Take a look at mocha-webpack. As mentioned in the docs, it basically runs webpack test.js output.js && mocha output.js with some optimizations. So, after npm i -D mocha-webpack, your scripts should look like:

"scripts": {   "test-mocha": "NODE_ENV=test node_modules/.bin/mocha-webpack --recursive test" } 

Another option you could try is to make use of mock-require, which is responsible for mocking node.js modules. In your case you'll need to require mock-helper.js:

"test-mocha": "NODE_ENV=test node_modules/.bin/mocha -r babel-register -r ./test/mock-helper.js --recursive test"

And ./test/mock-helper.js should be something like:

const mock = require('mock-require'); const defaultCustomer = require('../config/customer/default'); const fooCustomer = require('../config/customer/foo');  const customerMock = (function () {   switch (process.env.REACT_APP_CUSTOMER) {     case 'foo': return fooCustomer;     default: return defaultCustomer;   } }())  mock('../config/customer/CUSTOMER', customerMock); 

Hope it helps.

Answers 2

I settled on a simple/obvious solution:

Create a dummy file config/customer/CUSTOMER.js that contains the minimum expected configuration, e.g.

export default {   customerName: 'Dummy' } 

when the tests are run, an import such as

import config from '../config/customer/CUSTOMER'; 

will no longer fail because this module now exists.

Answers 3

I would suggest you to use Karmajs

Karmajs is a test runner, so you can configure it to use mocha for running tests, also you can pre-process your tests with webpack, so all the pre-processing (for NormalModuleReplacementPlugin and any other) which was done via webpack configuration is available when you're executing tests with Karma.

Basically, Install Karma and its associated Packages in your Application

yarn add karma karma-chai-plugins karma-chrome-launcher karma-cli karma-coverage karma-mocha karma-mocha-reporter karma-sinon-chai karma-sourcemap-loader karma-webpack 

Create karma.conf.js

const webpackConfig = require('./webpack.config'); const webpack = require('webpack'); webpackConfig.devtool = 'inline-source-map'; webpackConfig.plugins = [   new webpack.ProvidePlugin({     'es6-promise': 'es6-promise',   }), ];  module.exports = function (config) {   config.set({     browsers: [ 'Chrome' ],     // karma only needs to know about the test bundle     files: [       '../node_modules/babel-polyfill/dist/polyfill.js',       'karma.globals.js',       'tests.bundle.js',     ],     frameworks: [ 'chai', 'mocha' ],     // run the bundle through the webpack and sourcemap plugins     preprocessors: {       'tests.bundle.js': [ 'webpack', 'sourcemap' ],     },     // reporters: [ 'mocha', 'coverage' ],     reporters: [ 'mocha' ],     // coverageReporter: {     //   type: 'text-summary',     //   includeAllSources: true     // },     singleRun: false,     autoWatch: true,     // webpack config object     webpack: webpackConfig,     webpackMiddleware: {       noInfo: true,     },   }); }; 

Create tests.bundle.js for running tests for all your test files, in this example, all our tests files have a file extension .spec.js and are located inside ./src directory.

tests.bundle.js

const context = require.context('./src', true, /\.spec\.js$/); context.keys().forEach(context);  export default context; 

For setting up Global variables which need to be available across all your app/tests can be set with karma.globals.js file.

karma.globals.js

const __DEV__ = false;  const INITIAL_STATE = {   name: 'My App',   version: 'v2.5.6' }; 

Once the above is configured, you can run all your tests from the directory where you have created karma.config.js and package.json by executing the following command.

yarn karma start 

Note: Tests can be configured to execute in Headless Browsers (like phantomjs) as well, in this example we are using Chrome Browser to run our tests.

Answers 4

Probably, you would like to use mocha-webpack util

Answers 5

You can add this to your test script:

REACT_APP_CUSTOMER=foo 

So your test script becomes:

"test-mocha": "NODE_ENV=test REACT_APP_CUSTOMER=foo node_modules/.bin/mocha --require babel-register --recursive test" 

This will work because it sets the value you want in your process.env, and I'm not sure but I think this is the only reasonable way because you are mocking your environment when running a test.

If You Enjoyed This, Take 5 Seconds To Share It

0 comments:

Post a Comment