or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

configuration.mdcore-api.mdcore-classes.mdfactories.mdindex.mdplugins.mdreporters.mdtest-management.md
tile.json

factories.mddocs/

0

# Factory System

1

2

Test runner factory for testing reporters, plugins, and creating isolated test environments.

3

4

## Capabilities

5

6

### Runner Factory Function

7

8

Creates a new instance of the runner factory for testing and development purposes.

9

10

```typescript { .api }

11

/**

12

* Create an instance of the runner factory

13

* @returns RunnerFactory instance for creating isolated test environments

14

*/

15

function runner(): RunnerFactory;

16

```

17

18

### RunnerFactory Class

19

20

Factory class that provides an API to run dummy suites, groups, and tests for testing reporters and plugins.

21

22

```typescript { .api }

23

/**

24

* Runner factory exposes the API to run dummy suites, groups and tests.

25

* You might want to use the factory for testing reporters and plugins usage.

26

*/

27

class RunnerFactory {

28

/** Configure the factory with test configuration and CLI arguments */

29

configure(config: Config, argv?: string[]): this;

30

31

/** Define a custom emitter instance to use */

32

useEmitter(emitter: Emitter): this;

33

34

/** Run a single test using the runner */

35

async runTest(title: string, callback: TestExecutor<TestContext, undefined>): Promise<RunnerSummary>;

36

37

/** Enable/disable the bail mode */

38

bail(toggle?: boolean): this;

39

40

/** Run dummy test suites */

41

async runSuites(suites: (emitter: Emitter, refiner: Refiner, file?: string) => Suite[]): Promise<RunnerSummary>;

42

}

43

```

44

45

**Usage Examples:**

46

47

```typescript

48

import { runner } from "@japa/runner/factories";

49

import { assert } from "chai";

50

51

// Create factory instance

52

const factory = runner();

53

54

// Configure the factory

55

factory.configure({

56

files: ["tests/**/*.spec.ts"],

57

reporters: {

58

activated: ["spec"],

59

},

60

});

61

62

// Run a single test

63

const summary = await factory.runTest("should work", async (ctx) => {

64

assert.equal(2 + 2, 4);

65

});

66

67

console.log(`Test result: ${summary.hasError ? "FAILED" : "PASSED"}`);

68

```

69

70

### Testing Reporters

71

72

Use the factory to test custom reporters in isolation.

73

74

**Usage Examples:**

75

76

```typescript

77

import { runner } from "@japa/runner/factories";

78

import { Emitter, Suite, Test, TestContext } from "@japa/runner/core";

79

import { assert } from "chai";

80

81

// Custom reporter to test

82

const customReporter = {

83

name: "test-reporter",

84

handler: (runner, emitter) => {

85

const results: string[] = [];

86

87

emitter.on("test:start", (payload) => {

88

results.push(`START: ${payload.title}`);

89

});

90

91

emitter.on("test:end", (payload) => {

92

const status = payload.hasError ? "FAIL" : "PASS";

93

results.push(`END: ${payload.title} - ${status}`);

94

});

95

96

return { results };

97

},

98

};

99

100

// Test the reporter

101

const factory = runner();

102

factory.configure({

103

files: [],

104

reporters: {

105

activated: ["test-reporter"],

106

list: [customReporter],

107

},

108

});

109

110

// Run test with custom reporter

111

const summary = await factory.runTest("sample test", async (ctx) => {

112

assert.isTrue(true);

113

});

114

115

// Verify reporter output

116

console.log("Reporter captured:", customReporter.handler().results);

117

```

118

119

### Testing Plugins

120

121

Use the factory to test custom plugins in isolation.

122

123

**Usage Examples:**

124

125

```typescript

126

import { runner } from "@japa/runner/factories";

127

import { assert } from "chai";

128

129

// Custom plugin to test

130

const testPlugin = () => {

131

const events: string[] = [];

132

133

return ({ emitter }) => {

134

emitter.on("runner:start", () => {

135

events.push("runner started");

136

});

137

138

emitter.on("test:start", (payload) => {

139

events.push(`test started: ${payload.title}`);

140

});

141

142

emitter.on("test:end", (payload) => {

143

events.push(`test ended: ${payload.title}`);

144

});

145

146

emitter.on("runner:end", () => {

147

events.push("runner ended");

148

});

149

150

// Expose events for testing

151

return { events };

152

};

153

};

154

155

// Test the plugin

156

const factory = runner();

157

const pluginInstance = testPlugin();

158

159

factory.configure({

160

files: [],

161

plugins: [pluginInstance],

162

});

163

164

// Run test with plugin

165

await factory.runTest("plugin test", async (ctx) => {

166

assert.equal(1 + 1, 2);

167

});

168

169

// Verify plugin behavior

170

console.log("Plugin events:", pluginInstance().events);

171

```

172

173

### Running Multiple Test Suites

174

175

Create and run complex test scenarios with multiple suites.

176

177

**Usage Examples:**

178

179

```typescript

180

import { runner } from "@japa/runner/factories";

181

import { Suite, Test, TestContext, Group, Emitter, Refiner } from "@japa/runner/core";

182

import { assert } from "chai";

183

184

const factory = runner();

185

186

factory.configure({

187

files: [],

188

reporters: {

189

activated: ["spec"],

190

},

191

});

192

193

// Create test suites programmatically

194

const summary = await factory.runSuites((emitter, refiner, file) => {

195

// Unit tests suite

196

const unitSuite = new Suite("unit", emitter, refiner);

197

198

const mathGroup = new Group("Math operations", emitter, refiner);

199

const addTest = new Test("should add numbers", (test) => new TestContext(test), emitter, refiner, mathGroup);

200

addTest.run(async (ctx) => {

201

assert.equal(2 + 3, 5);

202

}, new Error());

203

204

unitSuite.add(mathGroup);

205

206

// Integration tests suite

207

const integrationSuite = new Suite("integration", emitter, refiner);

208

209

const apiTest = new Test("should call API", (test) => new TestContext(test), emitter, refiner);

210

apiTest.run(async (ctx) => {

211

// Mock API call

212

const result = await Promise.resolve({ status: "ok" });

213

assert.equal(result.status, "ok");

214

}, new Error());

215

216

integrationSuite.add(apiTest);

217

218

return [unitSuite, integrationSuite];

219

});

220

221

console.log(`Ran ${summary.aggregates.total} tests, ${summary.aggregates.passed} passed`);

222

```

223

224

### Factory with Custom Emitter

225

226

Use a custom emitter to capture and analyze test events.

227

228

**Usage Examples:**

229

230

```typescript

231

import { runner } from "@japa/runner/factories";

232

import { Emitter } from "@japa/runner/core";

233

import { assert } from "chai";

234

235

// Custom emitter with event logging

236

class LoggingEmitter extends Emitter {

237

private eventLog: Array<{ event: string; timestamp: number; payload?: any }> = [];

238

239

emit(event: string, ...args: any[]) {

240

this.eventLog.push({

241

event,

242

timestamp: Date.now(),

243

payload: args.length === 1 ? args[0] : args,

244

});

245

246

return super.emit(event, ...args);

247

}

248

249

getEventLog() {

250

return this.eventLog;

251

}

252

253

clearLog() {

254

this.eventLog = [];

255

}

256

}

257

258

// Use custom emitter with factory

259

const customEmitter = new LoggingEmitter();

260

const factory = runner();

261

262

factory

263

.useEmitter(customEmitter)

264

.configure({

265

files: [],

266

});

267

268

// Run test and capture events

269

await factory.runTest("event logging test", async (ctx) => {

270

assert.isTrue(true);

271

});

272

273

// Analyze captured events

274

const events = customEmitter.getEventLog();

275

console.log("Captured events:", events.map(e => e.event));

276

```

277

278

### Bail Mode Testing

279

280

Test bail mode behavior where execution stops on first failure.

281

282

**Usage Examples:**

283

284

```typescript

285

import { runner } from "@japa/runner/factories";

286

import { assert } from "chai";

287

288

const factory = runner();

289

290

// Enable bail mode

291

factory

292

.bail(true)

293

.configure({

294

files: [],

295

});

296

297

// Run suites with bail mode

298

const summary = await factory.runSuites((emitter, refiner) => {

299

const suite = new Suite("bail test", emitter, refiner);

300

301

// First test (will fail)

302

const failingTest = new Test("failing test", (test) => new TestContext(test), emitter, refiner);

303

failingTest.run(async (ctx) => {

304

assert.equal(1, 2); // This will fail

305

}, new Error());

306

307

// Second test (should not run due to bail)

308

const passingTest = new Test("passing test", (test) => new TestContext(test), emitter, refiner);

309

passingTest.run(async (ctx) => {

310

assert.equal(1, 1);

311

}, new Error());

312

313

suite.add(failingTest);

314

suite.add(passingTest);

315

316

return [suite];

317

});

318

319

console.log(`Bail mode: ${summary.aggregates.total} total, ${summary.aggregates.failed} failed`);

320

```

321

322

### Sync Reporter

323

324

Built-in synchronous reporter for testing that throws on test failures.

325

326

```typescript { .api }

327

/**

328

* Synchronous reporter that throws errors on test failures

329

* Useful for testing scenarios where you want immediate failure feedback

330

*/

331

const syncReporter: ReporterContract;

332

```

333

334

**Usage Examples:**

335

336

```typescript

337

import { runner, syncReporter } from "@japa/runner/factories";

338

import { assert } from "chai";

339

340

const factory = runner();

341

342

factory.configure({

343

files: [],

344

reporters: {

345

activated: ["sync"],

346

list: [syncReporter],

347

},

348

});

349

350

try {

351

// This will throw if any test fails

352

await factory.runTest("failing test", async (ctx) => {

353

assert.equal(1, 2);

354

});

355

} catch (error) {

356

console.log("Test failed as expected:", error.message);

357

}

358

```

359

360

### Create Dummy Tests

361

362

Utility function for creating test data and scenarios.

363

364

```typescript { .api }

365

/**

366

* Create dummy tests for testing and development purposes

367

*/

368

function createDummyTests(): any; // Implementation specific

369

```

370

371

## Types

372

373

### Factory Types

374

375

```typescript { .api }

376

interface RunnerFactory {

377

configure(config: Config, argv?: string[]): this;

378

useEmitter(emitter: Emitter): this;

379

runTest(title: string, callback: TestExecutor<TestContext, undefined>): Promise<RunnerSummary>;

380

bail(toggle?: boolean): this;

381

runSuites(suites: (emitter: Emitter, refiner: Refiner, file?: string) => Suite[]): Promise<RunnerSummary>;

382

}

383

384

interface RunnerSummary {

385

hasError: boolean;

386

aggregates: {

387

passed: number;

388

failed: number;

389

skipped: number;

390

todo: number;

391

total: number;

392

};

393

failureTree: Array<{

394

name: string;

395

errors: Array<{ phase: string; error: Error }>;

396

children: Array<{

397

name: string;

398

errors: Array<{ phase: string; error: Error }>;

399

}>;

400

}>;

401

}

402

```

403

404

### Suite Factory Function Type

405

406

```typescript { .api }

407

type SuiteFactory = (emitter: Emitter, refiner: Refiner, file?: string) => Suite[];

408

```