Generate multiple mocha reports in a single mocha execution.
npx @tessl/cli install tessl/npm-cypress-multi-reporters@1.6.0Cypress Multi Reporters enables generating multiple Mocha test reports simultaneously in a single test execution. It supports various output formats including spec, JSON, TAP, xUnit, and JUnit reports through a configurable system that allows users to specify which reporters to enable and their individual options.
npm install cypress-multi-reporters --save-devconst MultiReporters = require('cypress-multi-reporters');For ES6/TypeScript:
import MultiReporters from 'cypress-multi-reporters';# Basic usage with default configuration
./node_modules/.bin/mocha --reporter cypress-multi-reporters
# With custom configuration file
./node_modules/.bin/mocha --reporter cypress-multi-reporters --reporter-options configFile=config.jsonconst Mocha = require('mocha');
const mocha = new Mocha({
reporter: 'cypress-multi-reporters',
reporterOptions: {
reporterEnabled: 'spec, json',
jsonReporterOptions: {
output: 'test-results.json'
}
}
});
mocha.addFile('./test/sample.test.js');
mocha.run();Cypress Multi Reporters is built around several key components:
The core functionality that enables multiple Mocha reporters to run simultaneously.
/**
* Main MultiReporters class constructor
* @param {Object} runner - Mocha test runner instance
* @param {Object} options - Configuration options
*/
function MultiReporters(runner, options);Handles loading and merging configuration from multiple sources.
/**
* Get merged configuration options
* @param {Object} options - Raw options object
* @returns {Object} Merged configuration options
*/
MultiReporters.prototype.getOptions = function(options);
/**
* Load custom configuration from file or reporterOptions
* @param {Object} options - Options containing configFile or direct reporterOptions
* @returns {Object} Custom configuration object
*/
MultiReporters.prototype.getCustomOptions = function(options);
/**
* Load default configuration from CONFIG_FILE
* @returns {Object} Default configuration object
*/
MultiReporters.prototype.getDefaultOptions = function();
/**
* Resolve configuration for individual reporters
* @param {Object} options - Global options object
* @param {string} name - Reporter name
* @returns {Object} Reporter-specific configuration object
*/
MultiReporters.prototype.getReporterOptions = function(options, name);Coordinates completion across all registered reporters.
/**
* Handle completion when all reporters finish
* @param {number} failures - Number of test failures
* @param {Function} fn - Callback function to execute when all reporters complete
*/
MultiReporters.prototype.done = function(failures, fn);/**
* Default configuration file path
* @type {string}
*/
MultiReporters.CONFIG_FILE = '../config.json';interface Configuration {
/** Comma-delimited list of reporters to enable */
reporterEnabled: string | string[];
/** Common options shared across all reporters */
reporterOptions?: ReporterOptions;
/** Dynamic output configuration for templating */
cmrOutput?: string | string[][];
/** Reporter-specific options using camelCase naming */
[reporterName + 'ReporterOptions']?: ReporterOptions;
}
interface ReporterOptions {
/** Reporter identifier */
id?: string;
/** Output file path */
output?: string;
/** Custom options specific to the reporter */
[key: string]: any;
}Configuration can be provided through multiple sources (in order of precedence):
configFile option// Example: JSON configuration file
{
"reporterEnabled": "spec, xunit, json",
"reporterOptions": {
"id": "default"
},
"xunitReporterOptions": {
"output": "test-results.xml"
},
"jsonReporterOptions": {
"output": "test-results.json"
}
}
// Example: JavaScript configuration file
module.exports = {
reporterEnabled: "mochawesome, mocha-junit-reporter",
mochawesomeReporterOptions: {
reportDir: `.reports/${process.env.SITE_LOCALE}`
},
mochaJunitReporterReporterOptions: {
mochaFile: `./junit/${process.env.SITE_LOCALE}/[hash].xml`
}
};The cmrOutput option enables dynamic file naming using template substitution:
# Command line usage
mocha --reporter cypress-multi-reporters --reporterOptions configFile=config.json,cmrOutput=json+output+specialID// Configuration with template
{
"jsonReporterOptions": {
"output": "results/test-{id}.json"
}
}
// Results in: results/test-specialID.jsonReporter names are converted to camelCase for configuration keys:
@my-org/custom → myOrgCustomReporterOptionsmocha-junit-reporter → mochaJunitReporterReporterOptionsxunit → xunitReporterOptionsspec - Hierarchical view of test resultsjson - JSON format outputtap - Test Anything Protocol formatxunit - xUnit XML formatdot - Dot matrix outputmocha-junit-reporter, mochawesome)@org/reporter)// Configuration
{
"reporterEnabled": "spec, json, tap",
"jsonReporterOptions": {
"output": "test-results.json"
}
}{
"reporterEnabled": "mocha-junit-reporter",
"mochaJunitReporterReporterOptions": {
"mochaFile": "junit-results.xml",
"properties": {
"CI": "true"
}
}
}// Environment-specific configuration
const locale = process.env.SITE_LOCALE || 'US';
module.exports = {
reporterEnabled: "mochawesome, mocha-junit-reporter",
mochawesomeReporterOptions: {
reportDir: `.reports/${locale}`,
reportFilename: `test-results-${locale}`
},
mochaJunitReporterReporterOptions: {
mochaFile: `./junit/${locale}/results.xml`
}
};The package gracefully handles various error conditions:
// cypress.config.js
module.exports = {
e2e: {
setupNodeEvents(on, config) {
return require('./cypress/plugins/index.js')(on, config);
},
},
reporter: 'cypress-multi-reporters',
reporterOptions: {
configFile: 'reporter-config.json'
}
};const Mocha = require('mocha');
const mocha = new Mocha({
reporter: 'cypress-multi-reporters',
timeout: 60000,
reporterOptions: {
reporterEnabled: 'spec, json, mocha-junit-reporter',
jsonReporterOptions: {
output: 'test-results.json'
},
mochaJunitReporterReporterOptions: {
mochaFile: 'junit-results.xml'
}
}
});
mocha.addFile('./test/suite.test.js');
mocha.run((failures) => {
process.exitCode = failures ? 1 : 0;
});