Skip to content

Karma with Webpack

Modern codebases rarely use plain global scripts — they use ES modules, TypeScript, and bundler-specific features. This lesson covers karma-webpack, the standard way to bundle that code before Karma serves it to the browser.

Why Karma Needs a Bundler for Modern Code

Karma's files array simply injects <script> tags — it has no built-in understanding of import/export syntax, TypeScript, or module resolution. karma-webpack solves this by registering as both a framework and a preprocessor: it runs your webpack configuration against matched files, producing browser-ready bundles Karma can serve normally.

npm install --save-dev karma-webpack webpack

// karma.conf.js
config.set({
  frameworks: ['jasmine', 'webpack'],
  files: ['src/**/*.spec.js'],
  preprocessors: {
    'src/**/*.spec.js': ['webpack']
  },
  webpack: require('./webpack.test.config.js')
});

karma-webpack needs both a frameworks entry and a matching preprocessors entry to activate correctly.

A Minimal webpack.test.config.js

module.exports = {
  mode: 'development',
  devtool: 'inline-source-map',
  module: {
    rules: [
      { test: /\.ts$/, use: 'ts-loader' },
      { test: /\.css$/, use: ['style-loader', 'css-loader'] }
    ]
  },
  resolve: {
    extensions: ['.ts', '.js']
  }
};
  • devtool: 'inline-source-map' keeps stack traces readable in test failures.
  • This webpack config is entirely separate from any production build config, though they often share loader rules.
  • karma-webpack runs an in-memory webpack build per test run rather than writing bundles to disk.
  • Watch mode reuses webpack's incremental compilation, keeping reruns fast after the first build.

karma-webpack Cheat Sheet

Key configuration points to remember when wiring up karma-webpack.

Setting Purpose
frameworks: [..., 'webpack'] Registers the webpack integration
preprocessors: { pattern: ['webpack'] } Applies bundling to matched files
config.webpack The webpack configuration object karma-webpack uses
config.webpackMiddleware Optional dev-middleware options (e.g. verbosity)
devtool: 'inline-source-map' Keeps stack traces mapped to original source

How karma-webpack Handles Entry Points

Unlike a normal webpack build with a fixed entry, karma-webpack treats every file matched by the associated preprocessors pattern as its own entry point, bundling each spec file (and its imports) independently for the browser to load.

  • Each matched spec file becomes an implicit webpack entry point.
  • Shared imports (like a utility module used by many specs) get resolved and bundled per entry.
  • This can make full rebuilds slower on very large suites — incremental watch-mode rebuilds mitigate this significantly.
  • output settings in a normal webpack config are ignored; karma-webpack manages bundling internally.

Combining karma-webpack with Coverage

When using webpack alongside karma-coverage, instrumentation typically happens via a babel/webpack loader (like babel-plugin-istanbul) rather than Karma's standalone coverage preprocessor, since the code has already been transformed by webpack before Karma would otherwise instrument it.

// webpack.test.config.js (relevant excerpt)
module: {
  rules: [
    {
      test: /\.js$/,
      exclude: /node_modules/,
      use: {
        loader: 'babel-loader',
        options: { plugins: ['istanbul'] }
      }
    }
  ]
}

Common Mistakes

  • Listing webpack in preprocessors but forgetting to also list it in frameworks, or vice versa.
  • Reusing a production webpack config unmodified, pulling in optimizations (like minification) that make failures harder to read.
  • Applying Karma's standalone karma-coverage preprocessor on top of already-webpack-transformed code, producing incorrect coverage mappings.
  • Forgetting devtool: 'inline-source-map', making stack traces point at bundled rather than original source lines.

Key Takeaways

  • karma-webpack bundles modern module-based code so Karma can serve and run it in the browser.
  • It requires registration in both frameworks and a matching preprocessors entry.
  • Each matched spec file becomes an implicit webpack entry point, bundled independently.
  • Coverage instrumentation with webpack typically happens via a loader plugin, not Karma's standalone coverage preprocessor.

Pro Tip

Keep your webpack test config as close to your production config's module resolution rules as possible (aliases, extensions), but strip anything related to optimization or minification. Divergence here is a frequent, hard-to-spot source of 'works in the app but not in tests' bugs.