CLI for Jasmine, a simple JavaScript testing framework for browsers and Node
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
Jasmine provides a built-in console reporter with support for custom reporters, parallel execution aggregation, and detailed failure reporting with color output and flexible formatting options.
Default console output reporter providing formatted test results with color support and detailed failure information.
/**
* A reporter that prints spec and suite results to the console
* A ConsoleReporter is installed by default
*/
class ConsoleReporter {
constructor();
/** Required capability declaration for parallel support */
reporterCapabilities: { parallel: true };
/** Default command to reproduce random seed results */
randomSeedReproductionCmd(seed: string): string;
}Configure the console reporter with custom options and behavior.
/**
* Configures the reporter with custom options
* @param options - Configuration options for the reporter
*/
setOptions(options: ConsoleReporterOptions): void;
interface ConsoleReporterOptions {
/** Whether to colorize the output */
showColors?: boolean;
/** Custom print function for output */
print?: (text: string) => void;
/** Function to filter/modify stack traces */
stackFilter?: (stack: string) => string;
/** Function that takes a random seed and returns the command to reproduce that seed */
randomSeedReproductionCmd?: (seed: string) => string;
/** Whether to list pending specs even if there are failures */
alwaysListPendingSpecs?: boolean;
}Usage Examples:
const { ConsoleReporter } = require('jasmine');
const reporter = new ConsoleReporter();
// Basic configuration
reporter.setOptions({
showColors: true,
alwaysListPendingSpecs: true
});
// Custom print function (e.g., for logging)
reporter.setOptions({
print: (text) => {
fs.appendFileSync('test-output.log', text);
process.stdout.write(text);
}
});
// Custom stack filter
reporter.setOptions({
stackFilter: (stack) => {
// Remove internal jasmine frames
return stack.split('\n')
.filter(line => !line.includes('node_modules/jasmine'))
.join('\n');
}
});
// Custom seed reproduction command
reporter.setOptions({
randomSeedReproductionCmd: (seed) => `npm test -- --seed=${seed}`
});Implement custom reporters by providing lifecycle callback methods.
interface Reporter {
/** Called once at the beginning of the test suite */
jasmineStarted?(suiteInfo: JasmineStartedInfo): void;
/** Called once at the end of the test suite */
jasmineDone?(result: JasmineDoneInfo): void;
/** Called after each individual spec completes */
specDone?(result: SpecResult): void;
/** Called after each suite completes */
suiteDone?(result: SuiteResult): void;
/** Capability declaration for parallel support */
reporterCapabilities?: { parallel?: boolean };
}
interface JasmineStartedInfo {
/** Total number of specs defined (may be undefined in parallel mode) */
totalSpecsDefined?: number;
/** Randomization configuration */
order?: {
/** Whether specs are running in random order */
random: boolean;
/** Random seed being used */
seed: string;
};
/** Whether running in parallel mode */
parallel?: boolean;
/** Number of workers (only present in parallel mode) */
numWorkers?: number;
}
interface SpecResult {
/** Unique identifier for the spec */
id: string;
/** The spec's description */
description: string;
/** Full name including parent suite names */
fullName: string;
/** Array of failed expectations */
failedExpectations: FailedExpectation[];
/** Array of passed expectations */
passedExpectations: PassedExpectation[];
/** Reason for pending status if applicable */
pendingReason?: string;
/** Final status of the spec */
status: 'passed' | 'failed' | 'pending' | 'disabled';
/** Debug log entries if any */
debugLogs?: DebugLogEntry[];
/** Execution time in milliseconds */
duration?: number;
}
interface SuiteResult {
/** Unique identifier for the suite */
id: string;
/** The suite's description */
description: string;
/** Full name including parent suite names */
fullName: string;
/** Array of failed expectations from beforeAll/afterAll */
failedExpectations: FailedExpectation[];
/** Final status of the suite */
status: 'passed' | 'failed' | 'disabled';
}Create custom reporters for various output formats and integrations.
JSON Reporter:
class JSONReporter {
constructor() {
this.results = [];
this.startTime = null;
}
jasmineStarted(suiteInfo) {
this.startTime = Date.now();
console.log(JSON.stringify({
event: 'suiteStarted',
totalSpecs: suiteInfo.totalSpecsDefined,
random: suiteInfo.order?.random,
seed: suiteInfo.order?.seed
}));
}
specDone(result) {
this.results.push({
description: result.fullName,
status: result.status,
duration: result.duration,
failedExpectations: result.failedExpectations.map(fe => ({
message: fe.message,
stack: fe.stack
}))
});
}
jasmineDone(result) {
console.log(JSON.stringify({
event: 'suiteCompleted',
overallStatus: result.overallStatus,
totalTime: Date.now() - this.startTime,
specs: this.results
}));
}
}
// Usage
const jasmine = new Jasmine();
jasmine.addReporter(new JSONReporter());JUnit XML Reporter:
const fs = require('fs');
class JUnitReporter {
constructor(options = {}) {
this.outputFile = options.outputFile || 'test-results.xml';
this.results = [];
}
specDone(result) {
this.results.push(result);
}
jasmineDone(result) {
const xml = this.generateJUnitXML(this.results, result);
fs.writeFileSync(this.outputFile, xml);
}
generateJUnitXML(specs, suiteResult) {
const totalTests = specs.length;
const failures = specs.filter(s => s.status === 'failed').length;
const skipped = specs.filter(s => s.status === 'pending').length;
let xml = '<?xml version="1.0" encoding="UTF-8"?>\n';
xml += `<testsuite tests="${totalTests}" failures="${failures}" skipped="${skipped}" time="${suiteResult.totalTime / 1000}">\n`;
specs.forEach(spec => {
xml += ` <testcase name="${this.escapeXml(spec.description)}" time="${spec.duration / 1000}">\n`;
if (spec.status === 'failed') {
spec.failedExpectations.forEach(failure => {
xml += ` <failure message="${this.escapeXml(failure.message)}">\n`;
xml += ` ${this.escapeXml(failure.stack)}\n`;
xml += ' </failure>\n';
});
} else if (spec.status === 'pending') {
xml += ` <skipped message="Pending: ${this.escapeXml(spec.pendingReason || 'No reason given')}"/>\n`;
}
xml += ' </testcase>\n';
});
xml += '</testsuite>\n';
return xml;
}
escapeXml(str) {
return (str || '').replace(/[<>&'"]/g, (char) => {
switch (char) {
case '<': return '<';
case '>': return '>';
case '&': return '&';
case '"': return '"';
case "'": return ''';
default: return char;
}
});
}
}
// Usage
const jasmine = new Jasmine();
jasmine.addReporter(new JUnitReporter({ outputFile: 'junit-results.xml' }));Create reporters that work with parallel execution by implementing proper capabilities.
interface ParallelReporter extends Reporter {
/** Required for parallel execution support */
reporterCapabilities: {
parallel: true;
};
}Parallel-Compatible Reporter:
class ParallelFileReporter {
constructor(options = {}) {
this.outputFile = options.outputFile || 'parallel-results.log';
this.reporterCapabilities = { parallel: true };
}
jasmineStarted(suiteInfo) {
const message = `Started parallel execution with ${suiteInfo.numWorkers || 'unknown'} workers\n`;
fs.appendFileSync(this.outputFile, message);
}
specDone(result) {
// This will be called from multiple worker processes
const message = `${new Date().toISOString()} - ${result.fullName}: ${result.status}\n`;
fs.appendFileSync(this.outputFile, message);
}
jasmineDone(result) {
const message = `Completed parallel execution: ${result.overallStatus} in ${result.totalTime}ms with ${result.numWorkers} workers\n`;
fs.appendFileSync(this.outputFile, message);
}
}
// Usage with ParallelRunner
const ParallelRunner = require('jasmine/parallel');
const runner = new ParallelRunner({ numWorkers: 4 });
runner.addReporter(new ParallelFileReporter({ outputFile: 'parallel-test.log' }));Configure the built-in console reporter through the runner's configuration methods.
/**
* Configures the default reporter that is installed if no other reporter is specified
* @param options - Configuration options for the default console reporter
*/
configureDefaultReporter(options: ConsoleReporterOptions): void;Usage Examples:
const Jasmine = require('jasmine');
const jasmine = new Jasmine();
// Configure default reporter
jasmine.configureDefaultReporter({
showColors: process.stdout.isTTY,
alwaysListPendingSpecs: false,
print: (text) => {
// Custom print function
process.stdout.write(text);
}
});
// For parallel runner
const ParallelRunner = require('jasmine/parallel');
const runner = new ParallelRunner();
runner.configureDefaultReporter({
showColors: true,
alwaysListPendingSpecs: true
});Use multiple reporters simultaneously for different output formats.
const Jasmine = require('jasmine');
const jasmine = new Jasmine();
// Clear default reporter
jasmine.clearReporters();
// Add multiple custom reporters
jasmine.addReporter(new JSONReporter());
jasmine.addReporter(new JUnitReporter({ outputFile: 'junit.xml' }));
jasmine.addReporter(new ConsoleReporter());
await jasmine.execute();Handle reporter errors and failures gracefully.
class SafeReporter {
constructor(wrappedReporter) {
this.wrapped = wrappedReporter;
this.reporterCapabilities = wrappedReporter.reporterCapabilities;
}
jasmineStarted(suiteInfo) {
try {
this.wrapped.jasmineStarted?.(suiteInfo);
} catch (error) {
console.error('Reporter error in jasmineStarted:', error);
}
}
specDone(result) {
try {
this.wrapped.specDone?.(result);
} catch (error) {
console.error('Reporter error in specDone:', error);
}
}
jasmineDone(result) {
try {
this.wrapped.jasmineDone?.(result);
} catch (error) {
console.error('Reporter error in jasmineDone:', error);
}
}
}
// Usage
const jasmine = new Jasmine();
jasmine.addReporter(new SafeReporter(new CustomReporter()));