Adding a Custom JSON Reporter to Karma for Better Test Insights
Learn how to extend Karma’s test runner with a custom reporter that emits JSON events for CI pipelines or Slack bots.
01 Mar 2026, 06:49 UTC

Why a custom reporter?
When your test suite grows, the default Karma console output can become noisy and hard to parse programmatically. You might want to feed test results into a CI dashboard, trigger a Slack alert on failures, or store metrics for trend analysis. Karma’s built‑in reporters cover the basics, but they don’t let you shape the payload to match downstream consumers.
Karma exposes a reporter API that lets you hook into the test lifecycle and emit whatever format you need. This post walks through creating a simple JSON reporter, wiring it into karma.conf.js, and checking that it works, followed by the trade‑offs you should keep in mind.
Understanding the reporter lifecycle
Karma calls a reporter object at specific moments:
onRunStart– when the test runner begins.onSpecStart– before each individual spec (test) runs.onSpecComplete– after a spec finishes, with the result object.onRunComplete– when all specs have finished.
The result object passed to onSpecComplete contains the test name, status (passed|failed|skipped), execution time, and, if failed, the error stack trace. Because the reporter runs in the Karma server process, you also have access to browser information such as browser.name and browser.id.
Building a minimal JSON reporter
Create a file named karma-json-reporter.js in your project root. The module must export a factory function that returns an object with the hooks you care about.
// karma-json-reporter.js
const fs = require('fs');
const path = require('path');
function createJsonReporter() {
const results = [];
return {
onSpecComplete: function (browser, result) {
// Only keep failures for this example; adjust as needed
if (result.status === 'failed') {
results.push({
browser: browser.name,
test: result.description,
status: result.status,
time: result.time,
error: result.error ? result.error.message : null,
stack: result.error ? error.error.stack : null
});
}
},
onRunComplete: function () {
const outPath = path.resolve(__dirname, 'karma-test-results.json');
fs.writeFileSync(outPath, JSON.stringify(results, null, 2));
console.log(`[karma-json-reporter] Wrote ${results.length} failure(s) to ${outPath}`);
}
};
}
module.exports = { 'reporter:json': ['factory', createJsonReporter] };
What this does:
- Collects failure details in an array.
- When the run ends, writes a pretty‑printed JSON file next to the project.
- Logs a short confirmation to the console so you can see the reporter fired.
Wiring the reporter into Karma
Add the reporter to the reporters array and tell Karma where to find the plugin via customReporters.
// karma.conf.js
module.exports = function (config) {
config.set({
// … existing config …
reporters: ['progress', 'json'], // 'progress' keeps the default console output
customReporters: {
// No extra configuration needed for this simple reporter
json: {}
}
});
};
Run the test suite as usual:
# From the project root
karma start --single-run
If any specs fail, you should see a line like:
[karma-json-reporter] Wrote 2 failure(s) to /path/to/project/karma-test-results.json
Open the generated JSON file to verify it contains the expected fields. No output is invented here; you would inspect the actual file after a run.
Trade‑offs and limitations
While custom reporters are powerful, they run in the Karma server process, not inside each browser. Keep these points in mind:
- Performance: Heavy I/O (e.g., writing large logs after every spec) or synchronous network calls will slow the entire test run because Karma waits for the reporter to finish before moving on.
- Multi‑browser runs: The same reporter instance receives events from all configured browsers. If you need per‑browser separation, include
browser.idorbrowser.namein your output, as shown in the example. - Error handling: Throwing from a hook will abort Karma. Wrap risky operations in
try/catchand log errors internally rather than letting them propagate.
A practical way to check that the reporter isn’t hurting performance is to compare the total run time with and without the reporter enabled (using time karma start or your CI’s timing). If the difference is negligible (< 5 % for a typical suite), the reporter is likely safe for regular use.
Actionable closing
If you need structured test data for dashboards, alerts, or historical analysis, a custom Karma reporter is a straightforward solution. Start with a minimal implementation like the JSON example above, verify the output file, then gradually add the fields your consumers require. Remember to keep I/O light and to disambiguate multi‑browser events, and you’ll gain richer insights without sacrificing test speed.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.