0
# Reporter System
1
2
Built-in reporters and reporter creation for test output formatting and result reporting.
3
4
## Capabilities
5
6
### Spec Reporter
7
8
Creates a detailed, human-readable spec-style test output with hierarchical display of suites, groups, and tests.
9
10
```typescript { .api }
11
/**
12
* Create an instance of the spec reporter
13
* @param options - Optional reporter configuration
14
* @returns Named reporter contract
15
*/
16
function spec(options?: BaseReporterOptions): NamedReporterContract;
17
18
interface BaseReporterOptions {
19
/** Maximum number of stack trace frames to display */
20
framesMaxLimit?: number;
21
}
22
23
interface NamedReporterContract {
24
name: string;
25
handler: (...args: any[]) => ReporterContract;
26
}
27
```
28
29
**Usage Examples:**
30
31
```typescript
32
import { configure } from "@japa/runner";
33
import { spec } from "@japa/runner/reporters";
34
35
configure({
36
files: ["tests/**/*.spec.ts"],
37
reporters: {
38
activated: ["spec"],
39
list: [spec()],
40
},
41
});
42
43
// With custom options
44
configure({
45
files: ["tests/**/*.spec.ts"],
46
reporters: {
47
activated: ["detailed-spec"],
48
list: [
49
{
50
...spec({ framesMaxLimit: 20 }),
51
name: "detailed-spec",
52
},
53
],
54
},
55
});
56
```
57
58
### Dot Reporter
59
60
Creates a minimalist dot-style output where each test is represented by a single character (. for pass, x for fail).
61
62
```typescript { .api }
63
/**
64
* Create an instance of the dot reporter
65
* @param options - Optional reporter configuration
66
* @returns Named reporter contract
67
*/
68
function dot(options?: BaseReporterOptions): NamedReporterContract;
69
```
70
71
**Usage Examples:**
72
73
```typescript
74
import { configure } from "@japa/runner";
75
import { dot } from "@japa/runner/reporters";
76
77
configure({
78
files: ["tests/**/*.spec.ts"],
79
reporters: {
80
activated: ["dot"],
81
list: [dot()],
82
},
83
});
84
85
// Multiple reporters
86
configure({
87
files: ["tests/**/*.spec.ts"],
88
reporters: {
89
activated: ["dot", "spec"],
90
list: [dot(), spec()],
91
},
92
});
93
```
94
95
### NDJSON Reporter
96
97
Creates newline-delimited JSON output for programmatic consumption and integration with external tools.
98
99
```typescript { .api }
100
/**
101
* Create an instance of the ndjson reporter
102
* @param options - Optional reporter configuration
103
* @returns Named reporter contract
104
*/
105
function ndjson(options?: BaseReporterOptions): NamedReporterContract;
106
```
107
108
**Usage Examples:**
109
110
```typescript
111
import { configure } from "@japa/runner";
112
import { ndjson } from "@japa/runner/reporters";
113
114
configure({
115
files: ["tests/**/*.spec.ts"],
116
reporters: {
117
activated: ["ndjson"],
118
list: [ndjson()],
119
},
120
});
121
122
// Useful for CI/CD pipelines
123
configure({
124
files: ["tests/**/*.spec.ts"],
125
reporters: {
126
activated: ["ndjson", "spec"],
127
list: [
128
ndjson({ framesMaxLimit: 5 }),
129
spec(),
130
],
131
},
132
});
133
```
134
135
### GitHub Reporter
136
137
Creates GitHub Actions-compatible output with annotations and formatted messages for CI/CD integration.
138
139
```typescript { .api }
140
/**
141
* Create an instance of the github reporter
142
* @param options - Optional reporter configuration
143
* @returns Named reporter contract
144
*/
145
function github(options?: BaseReporterOptions): NamedReporterContract;
146
```
147
148
**Usage Examples:**
149
150
```typescript
151
import { configure } from "@japa/runner";
152
import { github } from "@japa/runner/reporters";
153
154
// GitHub Actions CI configuration
155
configure({
156
files: ["tests/**/*.spec.ts"],
157
reporters: {
158
activated: ["github"],
159
list: [github()],
160
},
161
});
162
163
// Combination for local development and CI
164
const isCI = process.env.CI === "true";
165
configure({
166
files: ["tests/**/*.spec.ts"],
167
reporters: {
168
activated: isCI ? ["github"] : ["spec"],
169
list: [
170
github(),
171
spec(),
172
],
173
},
174
});
175
```
176
177
### Custom Reporter Creation
178
179
Create custom reporters for specialized output formats or integrations.
180
181
```typescript { .api }
182
interface ReporterContract {
183
name: string;
184
handler: (runner: Runner, emitter: Emitter) => void;
185
}
186
187
interface Runner {
188
getSummary(): RunnerSummary;
189
onSuite(callback: (suite: Suite) => void): void;
190
}
191
192
interface Emitter {
193
on(event: string, callback: (...args: any[]) => void): void;
194
emit(event: string, ...args: any[]): void;
195
}
196
```
197
198
**Usage Examples:**
199
200
```typescript
201
import { configure } from "@japa/runner";
202
203
// Custom JSON file reporter
204
const jsonFileReporter = {
205
name: "json-file",
206
handler: (runner, emitter) => {
207
const results: any[] = [];
208
209
emitter.on("test:end", (payload) => {
210
results.push({
211
title: payload.title,
212
duration: payload.duration,
213
hasError: payload.hasError,
214
errors: payload.errors,
215
});
216
});
217
218
emitter.on("runner:end", () => {
219
const fs = require("fs");
220
fs.writeFileSync("test-results.json", JSON.stringify(results, null, 2));
221
});
222
},
223
};
224
225
// Custom Slack reporter
226
const slackReporter = {
227
name: "slack",
228
handler: (runner, emitter) => {
229
emitter.on("runner:end", async () => {
230
const summary = runner.getSummary();
231
if (summary.hasError) {
232
await sendSlackNotification(`Tests failed: ${summary.failedCount} failures`);
233
}
234
});
235
},
236
};
237
238
configure({
239
files: ["tests/**/*.spec.ts"],
240
reporters: {
241
activated: ["spec", "json-file", "slack"],
242
list: [
243
spec(),
244
jsonFileReporter,
245
slackReporter,
246
],
247
},
248
});
249
```
250
251
### Multiple Reporter Configuration
252
253
Configure multiple reporters to run simultaneously for different output needs.
254
255
**Usage Examples:**
256
257
```typescript
258
import { configure } from "@japa/runner";
259
import { spec, dot, ndjson, github } from "@japa/runner/reporters";
260
261
// Development environment
262
configure({
263
files: ["tests/**/*.spec.ts"],
264
reporters: {
265
activated: ["spec"],
266
list: [spec({ framesMaxLimit: 10 })],
267
},
268
});
269
270
// CI environment
271
configure({
272
files: ["tests/**/*.spec.ts"],
273
reporters: {
274
activated: ["github", "ndjson"],
275
list: [
276
github(),
277
ndjson(),
278
],
279
},
280
});
281
282
// Complete setup with environment detection
283
const isDevelopment = process.env.NODE_ENV === "development";
284
const isCI = process.env.CI === "true";
285
286
let activeReporters: string[];
287
if (isDevelopment) {
288
activeReporters = ["spec"];
289
} else if (isCI) {
290
activeReporters = ["github", "ndjson"];
291
} else {
292
activeReporters = ["dot"];
293
}
294
295
configure({
296
files: ["tests/**/*.spec.ts"],
297
reporters: {
298
activated: activeReporters,
299
list: [
300
spec({ framesMaxLimit: 15 }),
301
dot(),
302
ndjson({ framesMaxLimit: 5 }),
303
github(),
304
],
305
},
306
});
307
```
308
309
## Types
310
311
### Reporter Contract Types
312
313
```typescript { .api }
314
interface NamedReporterContract {
315
name: string;
316
handler: (...args: any[]) => ReporterContract;
317
}
318
319
interface ReporterContract {
320
name: string;
321
handler: (runner: Runner, emitter: Emitter) => void;
322
}
323
324
interface BaseReporterOptions {
325
framesMaxLimit?: number;
326
}
327
```
328
329
### Runner Summary Type
330
331
```typescript { .api }
332
interface RunnerSummary {
333
hasError: boolean;
334
aggregates: {
335
passed: number;
336
failed: number;
337
skipped: number;
338
todo: number;
339
total: number;
340
};
341
failureTree: Array<{
342
name: string;
343
errors: Array<{
344
phase: string;
345
error: Error;
346
}>;
347
children: Array<{
348
name: string;
349
errors: Array<{
350
phase: string;
351
error: Error;
352
}>;
353
}>;
354
}>;
355
}
356
```
357
358
### Event Types
359
360
Common events emitted by the test runner that reporters can listen to:
361
362
```typescript { .api }
363
// Runner events
364
"runner:start" | "runner:end"
365
366
// Suite events
367
"suite:start" | "suite:end"
368
369
// Group events
370
"group:start" | "group:end"
371
372
// Test events
373
"test:start" | "test:end"
374
```