Implementation:Webdriverio Webdriverio SpecReporter Class
Overview
Concrete tool for formatted console test result reporting provided by the @wdio/spec-reporter package.
Metadata
| Field | Value |
|---|---|
| Page Type | Implementation |
| Repository | webdriverio/webdriverio |
| Package | @wdio/spec-reporter
|
| Source File | packages/wdio-spec-reporter/src/index.ts, Lines L17-697
|
| Types | packages/wdio-spec-reporter/src/types.ts
|
| Related Principle | Principle: Test_Result_Reporting |
Description
The SpecReporter class extends WDIOReporter to produce formatted, colored console output showing test suite hierarchy, individual test results (checkmark for pass, X for fail, dash for skipped), timing information, and error stacks for failures. It is the default and most commonly used reporter for WDIO projects.
The reporter tracks suite ordering, maintains state counts (passed, failed, skipped, pending, retried), computes indentation for nested suites, and produces a final summary with pass/fail counts and total duration. It supports real-time reporting (printing results as tests complete) and deferred reporting (printing a complete summary after all tests in a worker finish).
For Sauce Labs users, the reporter can generate sharable test result links. It also handles multiremote sessions, Cucumber data tables and docstrings, and suite-level retries.
Source Reference
| File | Lines | Description |
|---|---|---|
packages/wdio-spec-reporter/src/index.ts |
L17-697 | SpecReporter class with all event handlers and formatting logic |
packages/wdio-spec-reporter/src/types.ts |
L1-95 | SpecReporterOptions, StateCount, Symbols, State enum, ChalkColors |
packages/wdio-spec-reporter/src/utils.ts |
-- | Table formatting utilities for Cucumber data tables |
Signature
class SpecReporter extends WDIOReporter {
constructor(options: SpecReporterOptions)
// Event handlers
onRunnerStart(runner: RunnerStats): void
onSuiteStart(suite: SuiteStats): void
onSuiteEnd(): void
onSuiteRetry(): void
onHookEnd(hook: HookStats): void
onTestStart(): void
onTestPass(testStat: TestStats): void
onTestFail(testStat: TestStats): void
onTestSkip(testStat: TestStats): void
onTestPending(testStat: TestStats): void
onRunnerEnd(runner: RunnerStats): void
// Formatting methods
printReport(runner: RunnerStats): void
getResultDisplay(preface?: string): string[]
getCountDisplay(duration: string): string[]
getFailureDisplay(): string[]
getHeaderDisplay(runner: RunnerStats): string[]
getOrderedSuites(): SuiteStats[]
getEventsToReport(suite: SuiteStats): (HookStats | TestStats)[]
getEnviromentCombo(capability: Capabilities, verbose?: boolean, isMultiremote?: boolean): string
}
Import
Configured via the reporters array in wdio.conf.ts:
// String form (default options)
reporters: ['spec']
// Array form (with options)
reporters: [['spec', {
onlyFailures: true,
addConsoleLogs: true,
realtimeReporting: false,
showPreface: true,
color: true
}]]
Or as a direct import for programmatic use:
import SpecReporter from '@wdio/spec-reporter'
Options
| Option | Type | Default | Description |
|---|---|---|---|
onlyFailures |
boolean |
false |
Only print results for runners that had failures |
addConsoleLogs |
boolean |
false |
Capture and display console.log output from tests |
realtimeReporting |
boolean |
false |
Print test results as they complete (not just at runner end) |
showPreface |
boolean |
true |
Show browser/capability prefix on each line (e.g., [Chrome 120 #0])
|
color |
boolean |
true |
Enable/disable colored output via Chalk |
symbols |
Partial<Symbols> |
{passed: '✓', failed: '✖', skipped: '-', pending: '?', retried: '↻'} |
Custom symbols for test states |
sauceLabsSharableLinks |
boolean |
true |
Generate sharable Sauce Labs test result links |
Inputs / Outputs Contract
Inputs (Event Handlers)
| Event Handler | Input Type | Description |
|---|---|---|
onRunnerStart |
RunnerStats |
Worker started: capabilities, cid, session info |
onSuiteStart |
SuiteStats |
Suite (describe/feature) started: title, file |
onSuiteEnd |
-- | Suite completed |
onSuiteRetry |
-- | Suite is being retried (adjusts state counts) |
onHookEnd |
HookStats |
Hook completed (counts as failure if hook.error exists) |
onTestStart |
-- | Test started (resets console output buffer) |
onTestPass |
TestStats |
Test passed |
onTestFail |
TestStats |
Test failed |
onTestSkip |
TestStats |
Test skipped |
onTestPending |
TestStats |
Test pending (with pendingReason) |
onRunnerEnd |
RunnerStats |
Worker finished: triggers final report output |
Outputs
Formatted console output with the following structure:
------------------------------------------------------------------
[Chrome 120 linux #0] Running: Chrome 120 linux
[Chrome 120 linux #0] Session ID: abc123def456
[Chrome 120 linux #0]
[Chrome 120 linux #0] >> test/specs/login.spec.ts
[Chrome 120 linux #0] Login Page
[Chrome 120 linux #0] ✓ should display the login form
[Chrome 120 linux #0] ✓ should accept valid credentials
[Chrome 120 linux #0] ✖ should show error for invalid credentials
[Chrome 120 linux #0]
[Chrome 120 linux #0] 2 passing (3.2s)
[Chrome 120 linux #0] 1 failing
[Chrome 120 linux #0]
[Chrome 120 linux #0] 1) Login Page should show error for invalid credentials
[Chrome 120 linux #0] Expected "Login failed" to equal "Invalid credentials"
[Chrome 120 linux #0] at Context.<anonymous> (test/specs/login.spec.ts:25:9)
Color Scheme
| State | Color | Symbol |
|---|---|---|
| Passed | Green | ✓
|
| Failed | Red | ✖
|
| Skipped | Cyan | -
|
| Pending | Cyan | ?
|
| Retried | Yellow | ↻
|
| Unknown/Default | Gray | (none) |
Implemented via the getColor() method and Chalk:
// packages/wdio-spec-reporter/src/index.ts L622-643
getColor(state?: string): ChalkColors {
let color = ChalkColors.GRAY
switch (state) {
case State.PASSED: color = ChalkColors.GREEN; break
case State.PENDING:
case State.SKIPPED: color = ChalkColors.CYAN; break
case State.FAILED: color = ChalkColors.RED; break
case State.RETRIED: color = ChalkColors.YELLOW; break
}
return color
}
Usage Example
Basic Configuration
// wdio.conf.ts
export const config: WebdriverIO.Config = {
reporters: ['spec'],
// ... other config
}
Show Only Failures (CI-friendly)
// wdio.conf.ts
export const config: WebdriverIO.Config = {
reporters: [['spec', {
onlyFailures: true,
showPreface: false
}]],
// ... other config
}
With Console Log Capture
// wdio.conf.ts
export const config: WebdriverIO.Config = {
reporters: [['spec', {
addConsoleLogs: true,
realtimeReporting: true
}]],
// ... other config
}
Internal State Management
The SpecReporter tracks state using several internal structures:
// packages/wdio-spec-reporter/src/index.ts L38-44
private _stateCounts: StateCount = {
passed: 0,
failed: 0,
skipped: 0,
pending: 0,
retried: 0
}
Suite ordering is maintained by tracking UIDs in the order suites are started:
// packages/wdio-spec-reporter/src/index.ts L96-106
onSuiteStart(suite: SuiteStats) {
this._suiteName = suite.file?.replace(process.cwd(), '')
this.printCurrentStats(suite)
this._suiteUids.add(suite.uid)
if (suite.type === 'feature') {
this._indents = 0
this._suiteIndents[suite.uid] = this._indents
} else {
this._suiteIndents[suite.uid] = ++this._indents
}
}
The getEventsToReport() method filters events to show only the latest retry of each test and only failed hooks, avoiding duplicate output for retried tests:
// packages/wdio-spec-reporter/src/index.ts L331-359
getEventsToReport(suite: SuiteStats) {
return [
...suite.hooksAndTests.reduce((accumulator, currentItem) => {
if (currentItem instanceof TestStats) {
const existingTestIndex = accumulator.findIndex(
(test) => test instanceof TestStats &&
test.fullTitle === currentItem.fullTitle
)
if (existingTestIndex === -1) {
accumulator.push(currentItem)
} else {
// Keep the test with the highest retry count
const existingTest = accumulator[existingTestIndex] as TestStats
if (currentItem.retries > existingTest.retries) {
accumulator.splice(existingTestIndex, 1, currentItem)
}
}
} else {
accumulator.push(currentItem)
}
return accumulator
}, []).filter((item) => {
return item.type === 'test' || Boolean(item.error)
})
]
}
Related Pages
- Implements: Principle: Test_Result_Reporting
- Receives events from: Implementation: Mocha_BDD_Globals
- Orchestrated by: Implementation: Launcher_Class