Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

use webpack plugin with Mocha tests

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
like image 552
Dónal Avatar asked Oct 05 '18 11:10

Dónal


3 Answers

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.

like image 79
Dónal Avatar answered Nov 13 '22 07:11

Dónal


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.

like image 28
streletss Avatar answered Nov 13 '22 07:11

streletss


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.

like image 2
Ayushya Avatar answered Nov 13 '22 06:11

Ayushya