0
# Reporters
1
2
Test result reporting configuration with output formatting, custom reporter support, and flexible logging options for WebdriverIO test execution.
3
4
## Capabilities
5
6
### Reporter Configuration
7
8
Core reporter configuration options for output formatting and logging.
9
10
```typescript { .api }
11
/**
12
* Reporter configuration options
13
*/
14
interface Options {
15
/** Output directory for reporter files */
16
outputDir?: string;
17
/** Complete path of the reporter log file */
18
logFile?: string;
19
/** Define filename format for reporter log files */
20
outputFileFormat?: (options: OutputFileFormatOptions) => string;
21
/** Set complete path for reporter's log output */
22
setLogFile?: (cid: string, name: string) => string;
23
/** Output to stdout instead of file */
24
stdout?: boolean;
25
/** Write to custom stream instead of file */
26
writeStream?: WriteStream | {
27
write: (content: unknown) => boolean;
28
};
29
/** Allow additional options from 3rd party reporters */
30
[key: string]: unknown;
31
}
32
33
/**
34
* Options for output file format function
35
*/
36
interface OutputFileFormatOptions {
37
/** Capability ID */
38
cid: string;
39
/** Test capabilities */
40
capabilities: RequestedStandaloneCapabilities | RequestedMultiremoteCapabilities;
41
}
42
```
43
44
### Reporter Instance Interface
45
46
Reporter instance interface extending Node.js EventEmitter.
47
48
```typescript { .api }
49
/**
50
* Reporter instance interface
51
*/
52
interface ReporterInstance extends EventEmitter {
53
/** Whether reporter has finished processing all events */
54
isSynchronised: boolean;
55
}
56
57
/**
58
* Reporter class constructor
59
*/
60
interface ReporterClass {
61
new(options: Partial<Options>): ReporterInstance;
62
}
63
```
64
65
### Reporter Entry Types
66
67
Different ways to configure reporters in WebdriverIO.
68
69
```typescript { .api }
70
/**
71
* Reporter configuration options
72
*/
73
type ReporterEntry =
74
/** Reporter name as string */
75
| string
76
/** Reporter class */
77
| ReporterClass
78
/** Reporter name with options */
79
| [string, WebdriverIO.ReporterOption]
80
/** Reporter class with options */
81
| [ReporterClass, WebdriverIO.ReporterOption];
82
```
83
84
### File System Integration
85
86
WriteStream interface for custom output destinations.
87
88
```typescript { .api }
89
import type { WriteStream } from 'node:fs';
90
91
/**
92
* Custom write stream interface
93
*/
94
interface CustomWriteStream {
95
/** Write content to stream */
96
write: (content: unknown) => boolean;
97
}
98
```
99
100
**Usage Examples:**
101
102
```typescript
103
import type { Reporters } from "@wdio/types";
104
import { EventEmitter } from "node:events";
105
import { createWriteStream } from "node:fs";
106
107
// Custom reporter implementation
108
class CustomJSONReporter extends EventEmitter implements Reporters.ReporterInstance {
109
private results: any[] = [];
110
private outputFile: string;
111
public isSynchronised: boolean = true;
112
113
constructor(private options: Partial<Reporters.Options>) {
114
super();
115
this.outputFile = options.logFile || 'test-results.json';
116
117
this.on('test:start', this.onTestStart.bind(this));
118
this.on('test:end', this.onTestEnd.bind(this));
119
this.on('runner:end', this.onRunnerEnd.bind(this));
120
}
121
122
onTestStart(test: any) {
123
console.log(`Starting test: ${test.fullTitle}`);
124
}
125
126
onTestEnd(test: any) {
127
this.results.push({
128
title: test.fullTitle,
129
state: test.state,
130
duration: test.duration,
131
error: test.error
132
});
133
}
134
135
onRunnerEnd() {
136
const fs = require('fs');
137
fs.writeFileSync(this.outputFile, JSON.stringify(this.results, null, 2));
138
console.log(`Results written to ${this.outputFile}`);
139
}
140
}
141
142
// Reporter configuration examples
143
const reporterConfigs: Reporters.ReporterEntry[] = [
144
// Built-in reporter by name
145
'spec',
146
147
// Built-in reporter with options
148
['allure', {
149
outputDir: './allure-results',
150
disableWebdriverStepsReporting: true
151
}],
152
153
// Custom reporter class
154
CustomJSONReporter,
155
156
// Custom reporter class with options
157
[CustomJSONReporter, {
158
logFile: './custom-results.json',
159
outputDir: './reports'
160
}],
161
162
// JSON reporter with custom formatting
163
['json', {
164
outputDir: './json-reports',
165
outputFileFormat: (options) => {
166
const { cid, capabilities } = options;
167
const browserName = capabilities.browserName || 'unknown';
168
return `results-${cid}-${browserName}.json`;
169
}
170
}],
171
172
// Spec reporter to stdout
173
['spec', {
174
stdout: true
175
}],
176
177
// Custom write stream
178
['spec', {
179
writeStream: createWriteStream('./test-output.log')
180
}]
181
];
182
183
// Advanced reporter with custom output formatting
184
class AdvancedReporter extends EventEmitter implements Reporters.ReporterInstance {
185
public isSynchronised: boolean = true;
186
private writeStream?: Reporters.Options['writeStream'];
187
188
constructor(private options: Partial<Reporters.Options>) {
189
super();
190
191
// Configure output destination
192
if (options.writeStream) {
193
this.writeStream = options.writeStream;
194
} else if (options.stdout) {
195
this.writeStream = { write: (content) => { console.log(content); return true; } };
196
} else if (options.logFile) {
197
this.writeStream = createWriteStream(options.logFile);
198
}
199
200
this.setupEventHandlers();
201
}
202
203
private setupEventHandlers() {
204
this.on('runner:start', (runner) => {
205
this.write(`Starting tests for ${runner.cid}\n`);
206
});
207
208
this.on('suite:start', (suite) => {
209
this.write(`Suite: ${suite.title}\n`);
210
});
211
212
this.on('test:end', (test) => {
213
const status = test.passed ? 'PASS' : 'FAIL';
214
const duration = test.duration ? `(${test.duration}ms)` : '';
215
this.write(` ${status}: ${test.title} ${duration}\n`);
216
217
if (!test.passed && test.error) {
218
this.write(` Error: ${test.error.message}\n`);
219
}
220
});
221
222
this.on('runner:end', (runner) => {
223
this.write(`Finished tests for ${runner.cid}\n`);
224
});
225
}
226
227
private write(content: string) {
228
if (this.writeStream && 'write' in this.writeStream) {
229
this.writeStream.write(content);
230
}
231
}
232
}
233
234
// Global namespace extension for custom reporter options
235
declare global {
236
namespace WebdriverIO {
237
interface ReporterOption extends Reporters.Options {
238
// Custom reporter-specific options can be added here
239
customOption?: boolean;
240
customFormatter?: (data: any) => string;
241
}
242
}
243
}
244
```