Generating JUnit XML Reports with Karma for CI Pipelines
Learn how to configure Karma to emit JUnit XML reports so your CI system can ingest test results reliably.
29 Sept 2025, 09:39 UTC

The problem: CI can’t read Karma’s native output
When you run Karma locally you see a colorful spec reporter in the terminal, but most CI systems (Jenkins, GitLab CI, Azure Pipelines) expect test results in JUnit XML format. Without that format the CI step either fails to parse results or shows no test data, making it hard to track failures or trends.
Thesis: adding the karma-junit-reporter plugin gives you a reliable, standards-compliant XML file that any JUnit-aware CI can consume
1. Why JUnit XML matters
JUnit XML is a simple, widely supported schema. Each <testsuite> represents a Karma browser run, and each <testcase> maps to an individual spec. Failure messages and stack traces appear as <failure> elements, which CI parsers turn into readable test reports.
2. Minimal configuration in karma.conf.js
Install the plugin as a dev dependency, then add it to the reporters array and point outputFile at a location that won’t clash with parallel runs.
// karma.conf.js
module.exports = function(config) {
config.set({
frameworks: ['jasmine'],
files: ['src/**/*.js', 'test/**/*.spec.js'],
reporters: ['progress', 'junit'], // add junit reporter
junitReporter: {
// Use a unique file per CI build to avoid overwrites
outputFile: 'test-results/junit.xml',
// Optional: include browser name in the testsuite name
useBrowserName: true
},
// ... other Karma options
});
};Run the install step once (requires only local npm permissions):
npm install karma karma-junit-reporter --save-dev3. Worked example
Create a tiny spec file
test/example.spec.js:describe('Demo suite', function() { it('should pass', function() { expect(true).toBe(true); }); it('should fail on purpose', function() { expect(false).toBe(true); }); });Start Karma:
npx karma startAfter the run finishes, check the generated file:
cat test-results/junit.xmlYou should see XML similar to:
<testsuite tests="2" failures="1"> <testcase classname="Demo suite" name="should pass"></testcase> <testcase classname="Demo suite" name="should fail on purpose"> <failure>Expected false to be true.</failure> </testcase> </testsuite>Validate the XML (optional but recommended):
xmllint --noout test-results/junit.xmlIf the command returns no error, the file is well-formed.
4. Trade-offs and limitations
Output file collisions: If you omit
outputFilethe reporter writesjunit.xmlin the current directory. Parallel Karma runs (e.g., matrix builds) will overwrite each other’s results. Fix: set a distinct path per build or include a timestamp/browser name.Missing environment metadata: The reporter does not automatically add Node.js version, OS, or Karma version. You can add custom properties via the
propertiesoption if your CI needs them.Browser-specific suites: With
useBrowserName: trueeach browser gets its own<testsuite>, which can make aggregation slightly more complex but gives finer granularity.
Actionable closing
Add the plugin, configure a safe output location, and verify the XML with a quick lint step. Once the file appears in your CI artifact store, plug it into the JUnit parser step of your pipeline and you’ll start seeing test counts, pass/fail ratios, and trend graphs without any extra work.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.