Karma ChromeHeadless: CI vs Local Development Guide
Configure Karma to use ChromeHeadless for CI and autoWatch for local development. Learn how to add a custom launcher for containerised environments, switch modes with an environment variable, and avoid common pitfalls.
27 Aug 2025, 12:52 UTC

Problem: Mixing CI and local test workflows in a single Karma config
When a project uses Karma to run unit tests, developers often want instant feedback on code changes while also ensuring that the same test suite passes cleanly in a continuous‑integration (CI) pipeline. The two environments have different expectations: CI jobs should finish quickly and exit, whereas local work benefits from a long‑running process that re‑runs tests automatically.
Thesis: Use singleRun:true for CI and autoWatch:true for local work, and add a custom ChromeHeadless launcher for containerised CI.
By configuring Karma to launch Chrome in headless mode and selecting the appropriate run mode, you can share a single karma.conf.js between developers and CI systems. The key is to expose a custom launcher that adds the flags required when Chrome runs as root inside a Docker container.
Local Development – autoWatch:true
When you start Karma locally with npx karma start, the default behaviour is to keep the process alive and re‑run the tests on every file change. This is enabled by autoWatch:true and singleRun:false (the default). Why it matters: it gives developers instant feedback without restarting the test runner.
Typical command:
npx karma start
CI – singleRun:true and ChromeHeadless
In a CI environment you want the test runner to start, run once, and exit with a status code that the pipeline can use. Set singleRun:true in karma.conf.js and launch Chrome in headless mode. The official karma-chrome-launcher package provides a ChromeHeadless browser name that starts Chrome without a graphical display.
Example snippet:
module.exports = {
basePath: '',
frameworks: ['jasmine'],
files: ['src/**/*.js', 'test/**/*.spec.js'],
preprocessors: {
'src/**/*.js': ['webpack'],
'test/**/*.spec.js': ['webpack']
},
reporters: ['progress'],
browsers: ['ChromeHeadless'],
singleRun: true,
autoWatch: false
};
Running this configuration:
npx karma start karma.conf.js --single-run
should exit with code 0 if all tests pass. Verify by checking the exit status in the CI job log.
Container‑Specific Flags: --no-sandbox and --disable-gpu
When Chrome runs inside a Docker container as root, it refuses to start unless you disable the sandbox. A custom launcher definition in karma.conf.js adds the required flags:
module.exports = {
// ... previous config omitted for brevity
customLaunchers: {
ChromeHeadlessNoSandbox: {
base: 'ChromeHeadless',
flags: ['--no-sandbox', '--disable-gpu']
}
},
browsers: ['ChromeHeadlessNoSandbox']
};
If you see errors like Failed to start chrome: no sandbox available in container logs, add the custom launcher above. After updating, re‑run the CI job to confirm Chrome launches successfully.
Practical Example – Switching Modes with an Environment Variable
You can keep a single config file and let the environment decide which mode to use. Add a small helper that reads process.env.CI:
const isCI = !!process.env.CI;
module.exports = {
// ... other settings
singleRun: isCI,
autoWatch: !isCI,
browsers: isCI ? ['ChromeHeadlessNoSandbox'] : ['ChromeHeadless']
};
In CI, set CI=true (most CI providers do this automatically). Locally the variable is absent, so autoWatch:true is enabled. This pattern eliminates the need for separate config files.
Trade‑Offs and Limitations
- Resource consumption: Running ChromeHeadless consumes memory; parallel runs on small CI runners may cause flakiness. Consider limiting
concurrencyor disabling parallelism if problems arise. - Version drift: A mismatch between the Chrome binary and
karma-chrome-launchercan cause startup failures. Runnpm list karma karma-chrome-launcherto verify compatibility. - Missing libraries: In minimal Docker images, libraries like
libnss3may be absent, leading to silent failures. Add them to the image if you encounter errors such as “chrome: error while loading shared libraries”.
Actionable Checklist
- Install
karma,karma-chrome-launcher, and your test framework (e.g.,karma-jasmine). - Define a custom ChromeHeadless launcher with
--no-sandboxand--disable-gpufor container use. - Use the
CIenvironment variable to togglesingleRunandautoWatch. - In CI, run
npx karma start karma.conf.js --single-runand confirm the process exits with code 0. - Locally, run
npx karma start, modify a source file, and verify the tests re‑run automatically. - If Chrome fails to start in the container, inspect logs and add missing system libraries.
Following these steps gives you a unified, reliable Karma setup that satisfies both fast local feedback and robust CI integration.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.