or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

cli.mdconfiguration.mdindex.mdparallel-runner.mdreporting.mdsequential-runner.md
tile.json

reporting.mddocs/

0

# Reporting System

1

2

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.

3

4

## Capabilities

5

6

### ConsoleReporter Class

7

8

Default console output reporter providing formatted test results with color support and detailed failure information.

9

10

```javascript { .api }

11

/**

12

* A reporter that prints spec and suite results to the console

13

* A ConsoleReporter is installed by default

14

*/

15

class ConsoleReporter {

16

constructor();

17

18

/** Required capability declaration for parallel support */

19

reporterCapabilities: { parallel: true };

20

21

/** Default command to reproduce random seed results */

22

randomSeedReproductionCmd(seed: string): string;

23

}

24

```

25

26

### Reporter Configuration

27

28

Configure the console reporter with custom options and behavior.

29

30

```javascript { .api }

31

/**

32

* Configures the reporter with custom options

33

* @param options - Configuration options for the reporter

34

*/

35

setOptions(options: ConsoleReporterOptions): void;

36

37

interface ConsoleReporterOptions {

38

/** Whether to colorize the output */

39

showColors?: boolean;

40

/** Custom print function for output */

41

print?: (text: string) => void;

42

/** Function to filter/modify stack traces */

43

stackFilter?: (stack: string) => string;

44

/** Function that takes a random seed and returns the command to reproduce that seed */

45

randomSeedReproductionCmd?: (seed: string) => string;

46

/** Whether to list pending specs even if there are failures */

47

alwaysListPendingSpecs?: boolean;

48

}

49

```

50

51

**Usage Examples:**

52

53

```javascript

54

const { ConsoleReporter } = require('jasmine');

55

56

const reporter = new ConsoleReporter();

57

58

// Basic configuration

59

reporter.setOptions({

60

showColors: true,

61

alwaysListPendingSpecs: true

62

});

63

64

// Custom print function (e.g., for logging)

65

reporter.setOptions({

66

print: (text) => {

67

fs.appendFileSync('test-output.log', text);

68

process.stdout.write(text);

69

}

70

});

71

72

// Custom stack filter

73

reporter.setOptions({

74

stackFilter: (stack) => {

75

// Remove internal jasmine frames

76

return stack.split('\n')

77

.filter(line => !line.includes('node_modules/jasmine'))

78

.join('\n');

79

}

80

});

81

82

// Custom seed reproduction command

83

reporter.setOptions({

84

randomSeedReproductionCmd: (seed) => `npm test -- --seed=${seed}`

85

});

86

```

87

88

### Reporter Lifecycle Methods

89

90

Implement custom reporters by providing lifecycle callback methods.

91

92

```javascript { .api }

93

interface Reporter {

94

/** Called once at the beginning of the test suite */

95

jasmineStarted?(suiteInfo: JasmineStartedInfo): void;

96

97

/** Called once at the end of the test suite */

98

jasmineDone?(result: JasmineDoneInfo): void;

99

100

/** Called after each individual spec completes */

101

specDone?(result: SpecResult): void;

102

103

/** Called after each suite completes */

104

suiteDone?(result: SuiteResult): void;

105

106

/** Capability declaration for parallel support */

107

reporterCapabilities?: { parallel?: boolean };

108

}

109

110

interface JasmineStartedInfo {

111

/** Total number of specs defined (may be undefined in parallel mode) */

112

totalSpecsDefined?: number;

113

/** Randomization configuration */

114

order?: {

115

/** Whether specs are running in random order */

116

random: boolean;

117

/** Random seed being used */

118

seed: string;

119

};

120

/** Whether running in parallel mode */

121

parallel?: boolean;

122

/** Number of workers (only present in parallel mode) */

123

numWorkers?: number;

124

}

125

126

interface SpecResult {

127

/** Unique identifier for the spec */

128

id: string;

129

/** The spec's description */

130

description: string;

131

/** Full name including parent suite names */

132

fullName: string;

133

/** Array of failed expectations */

134

failedExpectations: FailedExpectation[];

135

/** Array of passed expectations */

136

passedExpectations: PassedExpectation[];

137

/** Reason for pending status if applicable */

138

pendingReason?: string;

139

/** Final status of the spec */

140

status: 'passed' | 'failed' | 'pending' | 'disabled';

141

/** Debug log entries if any */

142

debugLogs?: DebugLogEntry[];

143

/** Execution time in milliseconds */

144

duration?: number;

145

}

146

147

interface SuiteResult {

148

/** Unique identifier for the suite */

149

id: string;

150

/** The suite's description */

151

description: string;

152

/** Full name including parent suite names */

153

fullName: string;

154

/** Array of failed expectations from beforeAll/afterAll */

155

failedExpectations: FailedExpectation[];

156

/** Final status of the suite */

157

status: 'passed' | 'failed' | 'disabled';

158

}

159

```

160

161

### Custom Reporter Examples

162

163

Create custom reporters for various output formats and integrations.

164

165

**JSON Reporter:**

166

167

```javascript

168

class JSONReporter {

169

constructor() {

170

this.results = [];

171

this.startTime = null;

172

}

173

174

jasmineStarted(suiteInfo) {

175

this.startTime = Date.now();

176

console.log(JSON.stringify({

177

event: 'suiteStarted',

178

totalSpecs: suiteInfo.totalSpecsDefined,

179

random: suiteInfo.order?.random,

180

seed: suiteInfo.order?.seed

181

}));

182

}

183

184

specDone(result) {

185

this.results.push({

186

description: result.fullName,

187

status: result.status,

188

duration: result.duration,

189

failedExpectations: result.failedExpectations.map(fe => ({

190

message: fe.message,

191

stack: fe.stack

192

}))

193

});

194

}

195

196

jasmineDone(result) {

197

console.log(JSON.stringify({

198

event: 'suiteCompleted',

199

overallStatus: result.overallStatus,

200

totalTime: Date.now() - this.startTime,

201

specs: this.results

202

}));

203

}

204

}

205

206

// Usage

207

const jasmine = new Jasmine();

208

jasmine.addReporter(new JSONReporter());

209

```

210

211

**JUnit XML Reporter:**

212

213

```javascript

214

const fs = require('fs');

215

216

class JUnitReporter {

217

constructor(options = {}) {

218

this.outputFile = options.outputFile || 'test-results.xml';

219

this.results = [];

220

}

221

222

specDone(result) {

223

this.results.push(result);

224

}

225

226

jasmineDone(result) {

227

const xml = this.generateJUnitXML(this.results, result);

228

fs.writeFileSync(this.outputFile, xml);

229

}

230

231

generateJUnitXML(specs, suiteResult) {

232

const totalTests = specs.length;

233

const failures = specs.filter(s => s.status === 'failed').length;

234

const skipped = specs.filter(s => s.status === 'pending').length;

235

236

let xml = '<?xml version="1.0" encoding="UTF-8"?>\n';

237

xml += `<testsuite tests="${totalTests}" failures="${failures}" skipped="${skipped}" time="${suiteResult.totalTime / 1000}">\n`;

238

239

specs.forEach(spec => {

240

xml += ` <testcase name="${this.escapeXml(spec.description)}" time="${spec.duration / 1000}">\n`;

241

242

if (spec.status === 'failed') {

243

spec.failedExpectations.forEach(failure => {

244

xml += ` <failure message="${this.escapeXml(failure.message)}">\n`;

245

xml += ` ${this.escapeXml(failure.stack)}\n`;

246

xml += ' </failure>\n';

247

});

248

} else if (spec.status === 'pending') {

249

xml += ` <skipped message="Pending: ${this.escapeXml(spec.pendingReason || 'No reason given')}"/>\n`;

250

}

251

252

xml += ' </testcase>\n';

253

});

254

255

xml += '</testsuite>\n';

256

return xml;

257

}

258

259

escapeXml(str) {

260

return (str || '').replace(/[<>&'"]/g, (char) => {

261

switch (char) {

262

case '<': return '&lt;';

263

case '>': return '&gt;';

264

case '&': return '&amp;';

265

case '"': return '&quot;';

266

case "'": return '&#39;';

267

default: return char;

268

}

269

});

270

}

271

}

272

273

// Usage

274

const jasmine = new Jasmine();

275

jasmine.addReporter(new JUnitReporter({ outputFile: 'junit-results.xml' }));

276

```

277

278

### Parallel Reporter Support

279

280

Create reporters that work with parallel execution by implementing proper capabilities.

281

282

```javascript { .api }

283

interface ParallelReporter extends Reporter {

284

/** Required for parallel execution support */

285

reporterCapabilities: {

286

parallel: true;

287

};

288

}

289

```

290

291

**Parallel-Compatible Reporter:**

292

293

```javascript

294

class ParallelFileReporter {

295

constructor(options = {}) {

296

this.outputFile = options.outputFile || 'parallel-results.log';

297

this.reporterCapabilities = { parallel: true };

298

}

299

300

jasmineStarted(suiteInfo) {

301

const message = `Started parallel execution with ${suiteInfo.numWorkers || 'unknown'} workers\n`;

302

fs.appendFileSync(this.outputFile, message);

303

}

304

305

specDone(result) {

306

// This will be called from multiple worker processes

307

const message = `${new Date().toISOString()} - ${result.fullName}: ${result.status}\n`;

308

fs.appendFileSync(this.outputFile, message);

309

}

310

311

jasmineDone(result) {

312

const message = `Completed parallel execution: ${result.overallStatus} in ${result.totalTime}ms with ${result.numWorkers} workers\n`;

313

fs.appendFileSync(this.outputFile, message);

314

}

315

}

316

317

// Usage with ParallelRunner

318

const ParallelRunner = require('jasmine/parallel');

319

const runner = new ParallelRunner({ numWorkers: 4 });

320

runner.addReporter(new ParallelFileReporter({ outputFile: 'parallel-test.log' }));

321

```

322

323

### Default Reporter Configuration

324

325

Configure the built-in console reporter through the runner's configuration methods.

326

327

```javascript { .api }

328

/**

329

* Configures the default reporter that is installed if no other reporter is specified

330

* @param options - Configuration options for the default console reporter

331

*/

332

configureDefaultReporter(options: ConsoleReporterOptions): void;

333

```

334

335

**Usage Examples:**

336

337

```javascript

338

const Jasmine = require('jasmine');

339

const jasmine = new Jasmine();

340

341

// Configure default reporter

342

jasmine.configureDefaultReporter({

343

showColors: process.stdout.isTTY,

344

alwaysListPendingSpecs: false,

345

print: (text) => {

346

// Custom print function

347

process.stdout.write(text);

348

}

349

});

350

351

// For parallel runner

352

const ParallelRunner = require('jasmine/parallel');

353

const runner = new ParallelRunner();

354

355

runner.configureDefaultReporter({

356

showColors: true,

357

alwaysListPendingSpecs: true

358

});

359

```

360

361

### Multiple Reporter Support

362

363

Use multiple reporters simultaneously for different output formats.

364

365

```javascript

366

const Jasmine = require('jasmine');

367

const jasmine = new Jasmine();

368

369

// Clear default reporter

370

jasmine.clearReporters();

371

372

// Add multiple custom reporters

373

jasmine.addReporter(new JSONReporter());

374

jasmine.addReporter(new JUnitReporter({ outputFile: 'junit.xml' }));

375

jasmine.addReporter(new ConsoleReporter());

376

377

await jasmine.execute();

378

```

379

380

### Reporter Error Handling

381

382

Handle reporter errors and failures gracefully.

383

384

```javascript

385

class SafeReporter {

386

constructor(wrappedReporter) {

387

this.wrapped = wrappedReporter;

388

this.reporterCapabilities = wrappedReporter.reporterCapabilities;

389

}

390

391

jasmineStarted(suiteInfo) {

392

try {

393

this.wrapped.jasmineStarted?.(suiteInfo);

394

} catch (error) {

395

console.error('Reporter error in jasmineStarted:', error);

396

}

397

}

398

399

specDone(result) {

400

try {

401

this.wrapped.specDone?.(result);

402

} catch (error) {

403

console.error('Reporter error in specDone:', error);

404

}

405

}

406

407

jasmineDone(result) {

408

try {

409

this.wrapped.jasmineDone?.(result);

410

} catch (error) {

411

console.error('Reporter error in jasmineDone:', error);

412

}

413

}

414

}

415

416

// Usage

417

const jasmine = new Jasmine();

418

jasmine.addReporter(new SafeReporter(new CustomReporter()));

419

```