
Research
/Security News
Weaponizing Discord for Command and Control Across npm, PyPI, and RubyGems.org
Socket researchers uncover how threat actors weaponize Discord across the npm, PyPI, and RubyGems ecosystems to exfiltrate sensitive data.
@wdio/junit-reporter
Advanced tools
A WebdriverIO reporter that creates Jenkins compatible XML based JUnit reports
A WebdriverIO reporter that creates Jenkins compatible XML based JUnit reports
The easiest way is to keep @wdio/junit-reporter
as a devDependency in your package.json
, via:
npm install @wdio/junit-reporter --save-dev
Instructions on how to install WebdriverIO
can be found here.
This reporter will output a report for each runner, so in turn you will receive an XML report for each spec file. Below are examples of XML output given different scenarios in the spec file.
describe('a test suite', () => {
it('a test case', function () {
// do something
// assert something
});
});
becomes
<testsuites>
<testsuite name="a test suite" timestamp="2019-04-18T13:45:21" time="11.735" tests="0" failures="0" errors="0" skipped="0">
<properties>
<property name="specId" value="0"/>
<property name="suiteName" value="a test suite"/>
<property name="capabilities" value="chrome"/>
<property name="file" value=".\test\specs\asuite.spec.js"/>
</properties>
<testcase classname="chrome.a_test_case" name="a_test_suite_a_test_case" time="11.706"/>
</testsuite>
</testsuites>
describe('a test suite', () => {
describe('a nested test suite', function() {
it('a test case', function () {
// do something
// assert something
});
});
});
becomes
<testsuites>
<testsuite name="a test suite" timestamp="2019-04-18T13:45:21" time="11.735" tests="0" failures="0" errors="0" skipped="0">
<properties>
<property name="specId" value="0"/>
<property name="suiteName" value="a test suite"/>
<property name="capabilities" value="chrome"/>
<property name="file" value=".\test\specs\asuite.spec.js"/>
</properties>
</testsuite>
<testsuite name="a nested test suite" timestamp="2019-04-18T13:45:21" time="11.735" tests="0" failures="0" errors="0" skipped="0">
<properties>
<property name="specId" value="0"/>
<property name="suiteName" value="a nested test suite"/>
<property name="capabilities" value="chrome"/>
<property name="file" value=".\test\specs\asuite.spec.js"/>
</properties>
<testcase classname="chrome.a_test_case" name="a nested test suite a test case" time="11.706"/>
</testsuite>
</testsuites>
describe('a test suite', () => {
it('a test case', function () {
// do something
// assert something
});
});
describe('a second test suite', () => {
it('a second test case', function () {
// do something
// assert something
});
});
becomes
<testsuites>
<testsuite name="a test suite" timestamp="2019-04-18T13:45:21" time="11.735" tests="0" failures="0" errors="0" skipped="0">
<properties>
<property name="specId" value="0"/>
<property name="suiteName" value="a test suite"/>
<property name="capabilities" value="chrome"/>
<property name="file" value=".\test\specs\asuite.spec.js"/>
<testcase classname="chrome.a_test_case" name="a nested test suite a test case" time="11.706"/>
</properties>
</testsuite>
<testsuite name="a second test suite" timestamp="2019-04-18T13:45:21" time="11.735" tests="0" failures="0" errors="0" skipped="0">
<properties>
<property name="specId" value="0"/>
<property name="suiteName" value="a second test suite"/>
<property name="capabilities" value="chrome"/>
<property name="file" value=".\test\specs\asuite.spec.js"/>
</properties>
<testcase classname="chrome.a_second_test_case" name="a_second_test_suite_a_second_test_case" time="11.706"/>
</testsuite>
</testsuites>
All test case failures are mapped as JUnit test case errors. A failed test case due to assertion failure or error will look like:
<testcase classname="chrome.a_test_case" name="a_test_suite_a_test_case" time="0.372">
<failure message="Error: some error"/>
<system-err>
<![CDATA[
Error: some assertion failure
at UserContext.<anonymous> (C:\repo\webdriver-example\test\specs/a_test_suite.spec.js:22:17)
]]>
</system-err>
</testcase>
The following example shows a basic configuration for this reporter:
// wdio.conf.js
export const config = {
// ...
reporters: [['junit', {
outputDir: './',
outputFileFormat: () => `test-results.xml`;
}]],
// ...
};
The following options are supported:
Define a directory where your XML files should get stored. Ignored if either logFile
or setLogFile
are defined.
Type: String
Function for defining the filename format for the reporter log files. Ignored if either logFile
or setLogFile
are defined.
The function accepts an object input parameter with the cid
and capabilities
keys.
Type: Object
Default: (opts) => `wdio-${opts.cid}-junit-reporter.log`
Example:
// wdio.conf.js
export const config = {
// ...
reporters: [['junit', {
outputDir: './',
outputFileFormat: (opts) => `results-${opts.cid}-${opts.capabilities.browserName}.xml`,
}]],
// ...
};
Path to the reporter log file relative to the current directory. Overrides outputDir
and outputFileFormat
.
Ignored if setLogFile
is defined.
Type: String
Example:
// wdio.conf.js
export const config = {
// ...
reporters: [['junit', {
logFile: './reports/junit-report.xml',
}]],
// ...
};
Function for defining the path for the reporter log files. Overrides outputDir
, outputFileFormat
, and logFile
.
The function accepts two input parameters: cid
and name
(the reporter name, set to junit
).
Type: Object
Example:
// wdio.conf.js
export const config = {
// ...
reporters: [['junit', {
setLogFile: (cid, name) => `./reports/results-${cid}-${name}.xml`,
}]],
// ...
};
Output the generated XML to the console instead of creating a log file.
Type: boolean
Default: false
Set a stream to which the generated XML should be output, instead of creating a log file.
Note: logFile
must not be set, unless stdout
is set to true
.
Type: WriteStream
Format the generated name of a test suite, using custom regex or a function.
The function accepts an object input parameter with the name
and suite
keys.
Type: Regex | Object
,
Default: /[^a-zA-Z0-9@]+/
Example with Regex:
// wdio.conf.js
export const config = {
// ...
reporters: [['junit', {
outputDir: './',
suiteNameFormat: /[^a-zA-Z0-9@]+/
}]],
// ...
};
Example with function:
// wdio.conf.js
export const config = {
// ...
reporters: [['junit', {
outputDir: './',
suiteNameFormat: ({name, suite}) => `suite-${name}-${suite.title}`,
}]],
// ...
};
Format the generated classname of a test case.
The function accepts an object input parameter with the packageName
, activeFeatureName
(Cucumber only), and suite
(non-Cucumber only) keys.
Type: Object
Default (Cucumber): (opts) => `${opts.packageName}${opts.activeFeatureName}`
Default (others): (opts) => `${opts.packageName}.${(opts.suite.fullTitle || opts.suite.title).replace(/\s/g, '_')}`
Example (Cucumber):
// wdio.conf.js
export const config = {
// ...
reporters: [['junit', {
outputDir: './',
classNameFormat: ({packageName, activeFeatureName}) => `class-${packageName}-${activeFeatureName}`,
}]],
// ...
};
Example (others):
// wdio.conf.js
export const config = {
// ...
reporters: [['junit', {
outputDir: './',
classNameFormat: ({packageName, suite}) => `class-${packageName}-${suite.title}`,
}]],
// ...
};
Adds a file
attribute to each testcase. The value of this attribute matches the filepath property of the parent test
suite. This config is primarily for CircleCI, but may break on other CI platforms.
Type: Boolean
Default: false
Example simplified XML:
<testsuite>
<properties>
<property name="file" value="file://./path/to/test/file.js"/>
</properties>
<testcase file="file://./path/to/test/file.js">
<!-- ... -->
</testcase>
</testsuite>
You can break out packages by an additional level by setting 'packageName'
. For example, if you wanted to iterate over a test suite with a different environment variable set:
Type: String
Default (Cucumber): CucumberJUnitReport-${sanitizedCapabilities}
Default (others): ${sanitizedCapabilities}
Example:
// wdio.conf.js
export const config = {
// ...
reporters: [['junit', {
outputDir: './',
packageName: process.env.USER_ROLE // chrome.41 - administrator
}]],
// ...
};
Allows to set various combinations of error notifications inside xml.
Given a Jasmine test like expect(true).toBe(false, 'my custom message')
you will get this test error:
{
matcherName: 'toBe',
message: 'Expected true to be false, \'my custom message\'.',
stack: 'Error: Expected true to be false, \'my custom message\'.\n at UserContext.it (/home/mcelotti/Workspace/WebstormProjects/forcebeatwio/test/marco/prova1.spec.js:3:22)',
passed: false,
expected: [ false, 'my custom message' ],
actual: true
}
Therefore you can choose which key will be used where, see the example below.
Type: Object
,
Default: errorOptions: { error: "message" }
Example:
// wdio.conf.js
export const config = {
// ...
reporters: [['junit', {
outputDir: './',
errorOptions: {
error: 'message',
failure: 'message',
stacktrace: 'stack'
}
}]],
// ...
};
Attach console logs from the test in the reporter.
Type: Boolean
Default: false
Example:
// wdio.conf.js
export const config = {
// ...
reporters: [['junit', {
outputDir: './',
addWorkerLogs: true
}]],
// ...
};
Add a JUnit testcase property to the currently running test step. The typical usecase for this is adding a link to an issue or a testcase.
Simplified example (Mocha):
import { addProperty } from '@wdio/junit-reporter'
describe('Suite', () => {
it('Case', () => {
addProperty('test_case', 'TC-1234')
})
})
<testsuite name="Suite">
<testcase classname="chrome.Case" name="Suite Case">
<properties>
<property name="test_case" value="TC-1234" />
</properties>
</testcase>
</testsuite>
Last but not least you need to tell your CI job (e.g. Jenkins) where it can find the XML file. To do that, add a post-build action to your job that gets executed after the test has run and point Jenkins (or your desired CI system) to your XML test results:
If there is no such post-build step in your CI system, there is probably a plugin for that somewhere on the internet.
For more information on WebdriverIO see the homepage.
v9.20.0 (2025-09-27)
webdriver
wdio-cucumber-framework
wdio-allure-reporter
webdriverio
wdio-utils
wdio-browserstack-service
wdio-cli
, wdio-config
webdriverio
wdio-browserstack-service
, wdio-local-runner
wdio-junit-reporter
mocha-junit-reporter is a reporter for Mocha that generates test results in JUnit XML format. It is similar to @wdio/junit-reporter but is specifically designed for Mocha test framework. It provides similar functionalities like generating JUnit XML reports and customizing output file names.
jest-junit is a Jest reporter that generates test results in JUnit XML format. It is similar to @wdio/junit-reporter but is tailored for the Jest testing framework. It offers features like generating JUnit XML reports and configuring output file paths.
karma-junit-reporter is a reporter for the Karma test runner that produces test results in JUnit XML format. It is similar to @wdio/junit-reporter but is designed for use with the Karma test runner. It provides functionalities like generating JUnit XML reports and customizing output file names.
FAQs
A WebdriverIO reporter that creates Jenkins compatible XML based JUnit reports
The npm package @wdio/junit-reporter receives a total of 227,491 weekly downloads. As such, @wdio/junit-reporter popularity was classified as popular.
We found that @wdio/junit-reporter demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 3 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Research
/Security News
Socket researchers uncover how threat actors weaponize Discord across the npm, PyPI, and RubyGems ecosystems to exfiltrate sensitive data.
Security News
Socket now integrates with Bun 1.3’s Security Scanner API to block risky packages at install time and enforce your organization’s policies in local dev and CI.
Research
The Socket Threat Research Team is tracking weekly intrusions into the npm registry that follow a repeatable adversarial playbook used by North Korean state-sponsored actors.