Karma setup for Webpacker v5

Reposting here since this got deleted for v6.
Contents copied from Reinstate testing docs for Karma by eriknygren · Pull Request #3244 · rails/webpacker · GitHub.

Testing

Karma setup

Webpacker does not setup Karma by default, so you have to manually install it along with its dependencies as per your need.

// package.json
"scripts": {
  "test": "NODE_ENV=test karma start"
},
"devDependencies": {
  "karma": "^6.3.4",
  "karma-chrome-launcher": "^3.1.0",
  "karma-mocha": "^2.0.1",
  "karma-sinon": "^1.0.5",
  "karma-spec-reporter": "^0.0.32",
  "karma-webpack": "^5.0.0",
}

It is beneficial to use the same webpack configuration file (generated by webpacker) in Karma configuration to avoid redundancy.

We have to remove some keys from the default config to get rid of Karma warnings and make use of the EnvironmentPlugin to get it to run.

// config/webpack/test.js
const webpack = require('webpack');
const { merge } = require('@rails/webpacker')
process.env.NODE_ENV = 'development'

const webpackConfig = require('./base')

webpackConfig.mode = 'development';

const processConf = {
  plugins: [
    new webpack.EnvironmentPlugin({
      NODE_DEBUG: JSON.stringify(false),
      TARGET: JSON.stringify('browser'),
      NODE_ENV: JSON.stringify(process.env.NODE_ENV)
    }),
  ],
  resolve: {
    fallback: { util: require.resolve("util/") },
  },
}

// Get rid of unsupported karma config entries
delete webpackConfig.output.filename
delete webpackConfig.entry
module.exports = merge(webpackConfig, processConf)

Finally, update karma.conf.js to read the same test.js file.

In the following example, the JS tests are stored in /webpack_tests/**/*.js.

// karma.conf.js
const webpackConfig = require('./config/webpack/test.js')
module.exports = function(config) {
  config.set({
    basePath: '',
    plugins: [
      'karma-webpack',
      'karma-mocha',
      'karma-sinon',
      'karma-chrome-launcher',
      'karma-spec-reporter',
    ],
    files: [
      'webpack_tests/**/*.js',
    ],
    reporters: ['spec'],
    specReporter: {
      maxLogLines: 5,         // limit number of lines logged per test
      suppressErrorSummary: false,  // print error summary
      suppressFailed: false,  // print information about failed tests
      suppressPassed: false,  // print information about passed tests
      suppressSkipped: false,  // print information about skipped tests
      showSpecTiming: true // print the time elapsed for each spec
    },
    exclude: [],
    webpack: webpackConfig,
    preprocessors: {
      'webpack_tests/**/*.js': ['webpack'],
    },
    frameworks: ['mocha', 'sinon', 'webpack'],
    port: 9876,
    colors: true,
    logLevel: config.LOG_INFO,
    autoWatch: true,
    browsers: ['ChromeHeadless'],
    singleRun: true,
  });
};