A WebdriverIO utility to help reporting all events with extensible base class for custom reporters
—
The WDIO Reporter provides a comprehensive event system based on EventEmitter that captures all aspects of test execution. The system includes event interfaces and types that define the structure of data passed through the reporter event system.
Interfaces for WebDriver command execution events that capture command details, parameters, and results.
/**
* Base interface for WebDriver command arguments
* Contains common properties for all command events
*/
interface CommandArgs {
sessionId: string;
method?: string;
endpoint?: string;
// DevTools specific properties
retries?: number;
command?: string;
params?: unknown;
}
/**
* Arguments passed before WebDriver command execution
* Extends CommandArgs with request body information
*/
interface BeforeCommandArgs extends CommandArgs {
body: unknown;
}
/**
* Arguments passed after WebDriver command execution
* Extends CommandArgs with result information
*/
interface AfterCommandArgs extends CommandArgs {
result: unknown;
/**
* @deprecated Use `command` instead
* Custom commands also send along the command name
* Note: onAfterCommand was never called for custom commands in some cases
*/
name?: string;
}Usage Example:
export class CommandTrackingReporter extends WDIOReporter {
onBeforeCommand(commandArgs: BeforeCommandArgs) {
console.log(`Executing command: ${commandArgs.command || commandArgs.method}`);
console.log(`Session: ${commandArgs.sessionId}`);
console.log(`Endpoint: ${commandArgs.endpoint}`);
if (commandArgs.body) {
console.log(`Request body:`, commandArgs.body);
}
}
onAfterCommand(commandArgs: AfterCommandArgs) {
console.log(`Command completed: ${commandArgs.command || commandArgs.method}`);
console.log(`Result:`, commandArgs.result);
if (commandArgs.retries && commandArgs.retries > 0) {
console.log(`Retries: ${commandArgs.retries}`);
}
}
}Interfaces defining the structure of test-related events throughout the test lifecycle.
/**
* Test event interface defining test metadata and state
* Used across all test lifecycle events
*/
interface Test {
type: 'test:start' | 'test:pass' | 'test:fail' | 'test:retry' | 'test:pending' | 'test:end' | 'test:skip';
title: string;
parent: string;
fullTitle: string;
pending: boolean;
file?: string;
body?: string;
duration?: number;
cid: string;
specs: string[];
uid: string;
pendingReason?: string;
error?: Error;
errors?: Error[];
retries?: number;
argument?: string | Argument;
state?: string;
}
/**
* Test argument interface for parameterized tests (Cucumber)
* Contains structured data passed to test scenarios
*/
interface Argument {
rows?: {
cells: string[];
}[];
}Interface for test and suite tagging system used in BDD frameworks.
/**
* Tag interface for test marking and categorization
* Used primarily in Cucumber and similar BDD frameworks
*/
interface Tag {
name: string;
line: number;
}Usage Example:
export class TaggedReporter extends WDIOReporter {
onSuiteStart(suiteStats: SuiteStats) {
if (suiteStats.tags && suiteStats.tags.length > 0) {
const tagNames = suiteStats.tags.map(tag =>
typeof tag === 'string' ? tag : tag.name
);
console.log(`Suite "${suiteStats.title}" has tags: ${tagNames.join(', ')}`);
}
}
onTestStart(testStats: TestStats) {
if (testStats.argument && typeof testStats.argument === 'object' && testStats.argument.rows) {
console.log(`Test "${testStats.title}" has data table:`);
testStats.argument.rows.forEach((row, index) => {
console.log(` Row ${index + 1}: [${row.cells.join(', ')}]`);
});
}
}
}The event system follows a predictable lifecycle for test execution:
runner:start → onRunnerStart()runner:end → onRunnerEnd()suite:start → onSuiteStart()suite:retry → onSuiteRetry() (Cucumber only)suite:end → onSuiteEnd()hook:start → onHookStart()hook:end → onHookEnd()test:start → onTestStart()test:pass | test:fail | test:skip | test:pending → corresponding handlertest:retry → onTestRetry() (if retries enabled)test:end → onTestEnd()client:beforeCommand → onBeforeCommand()client:afterCommand → onAfterCommand()client:beforeAssertion → onBeforeAssertion()client:afterAssertion → onAfterAssertion()In addition to the processed event handler methods, you can register listeners for raw events directly:
Usage Example:
export class RawEventReporter extends WDIOReporter {
constructor(options: Partial<Reporters.Options>) {
super(options);
// Listen to raw events directly
this.on('suite:start', (rawSuiteData) => {
console.log('Raw suite data:', rawSuiteData);
});
this.on('test:fail', (rawTestData) => {
console.log('Raw test failure data:', rawTestData);
});
// Custom event handling
this.on('client:beforeCommand', (rawCommandData) => {
if (rawCommandData.body?.script) {
console.log('Script command detected');
}
});
}
}The WDIOReporter automatically processes raw event data before calling the handler methods:
getErrorsFromEvent() utilitytransformCommandScript()This processing ensures that event handler methods receive clean, structured data objects rather than raw framework events.
Install with Tessl CLI
npx tessl i tessl/npm-wdio--reporter