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

core-classes.mddocs/

0

# Core Classes

1

2

Low-level classes for advanced usage, testing frameworks, and plugin development.

3

4

## Capabilities

5

6

### Runner Class

7

8

Test execution engine that manages suites, reporters, and the overall test lifecycle.

9

10

```typescript { .api }

11

/**

12

* Runner class is used to execute the tests

13

*/

14

class Runner {

15

/** Enable or disable bail mode (stop on first failure) */

16

bail(toggle?: boolean): this;

17

18

/** Register a reporter for test output */

19

registerReporter(reporter: ReporterContract): void;

20

21

/** Get test execution summary */

22

getSummary(): RunnerSummary;

23

24

/** Register callback for suite events */

25

onSuite(callback: (suite: Suite) => void): void;

26

27

/** Add a suite to the runner */

28

add(suite: Suite): void;

29

30

/** Start test execution */

31

async start(): Promise<void>;

32

33

/** Execute all tests */

34

async exec(): Promise<void>;

35

36

/** Finish test execution */

37

async end(): Promise<void>;

38

}

39

40

interface RunnerSummary {

41

hasError: boolean;

42

aggregates: {

43

passed: number;

44

failed: number;

45

skipped: number;

46

todo: number;

47

total: number;

48

};

49

failureTree: Array<{

50

name: string;

51

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

52

children: Array<{

53

name: string;

54

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

55

}>;

56

}>;

57

}

58

```

59

60

**Usage Examples:**

61

62

```typescript

63

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

64

65

// Create and configure runner

66

const emitter = new Emitter();

67

const runner = new Runner(emitter);

68

69

// Enable bail mode

70

runner.bail(true);

71

72

// Register custom reporter

73

runner.registerReporter({

74

name: "custom",

75

handler: (runner, emitter) => {

76

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

77

console.log(`Test: ${payload.title} - ${payload.hasError ? "FAIL" : "PASS"}`);

78

});

79

},

80

});

81

82

// Add test suites

83

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

84

runner.add(unitSuite);

85

86

// Execute tests

87

await runner.start();

88

await runner.exec();

89

await runner.end();

90

91

// Get results

92

const summary = runner.getSummary();

93

console.log(`Tests: ${summary.aggregates.total}, Passed: ${summary.aggregates.passed}`);

94

```

95

96

### Test Class

97

98

Individual test instance with enhanced functionality and assertion capabilities.

99

100

```typescript { .api }

101

/**

102

* Test class represents an individual test and exposes API to tweak its runtime behavior

103

*/

104

class Test<TestData = undefined> {

105

/** Assert the test throws an exception with a certain error message */

106

throws(message: string | RegExp, errorConstructor?: any): this;

107

108

/** Set timeout for this test */

109

timeout(duration: number): this;

110

111

/** Set retry count for this test */

112

retry(count: number): this;

113

114

/** Mark test as todo (not implemented) */

115

todo(): this;

116

117

/** Mark test as skipped */

118

skip(): this;

119

120

/** Pin test (only run this test) */

121

pin(): this;

122

123

/** Add test setup hook */

124

setup(handler: TestHooksHandler<TestContext>): this;

125

126

/** Add test cleanup hook */

127

cleanup(handler: TestHooksCleanupHandler<TestContext>): this;

128

129

/** Execute the test */

130

run(executor: TestExecutor<TestContext, TestData>, debuggingError: Error): this;

131

}

132

133

type TestHooksHandler<Context> = (context: Context) => void | Promise<void>;

134

type TestHooksCleanupHandler<Context> = (context: Context) => void | Promise<void>;

135

```

136

137

**Usage Examples:**

138

139

```typescript

140

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

141

142

// Create test instance

143

const emitter = new Emitter();

144

const refiner = new Refiner();

145

const test = new Test("should validate input", (test) => new TestContext(test), emitter, refiner);

146

147

// Configure test

148

test

149

.timeout(5000)

150

.retry(2)

151

.setup(async (context) => {

152

context.database = await setupTestDatabase();

153

})

154

.cleanup(async (context) => {

155

await cleanupTestDatabase(context.database);

156

});

157

158

// Test that expects an exception

159

const errorTest = new Test("should throw error", (test) => new TestContext(test), emitter, refiner);

160

errorTest

161

.throws("Invalid input", ValidationError)

162

.run(async (ctx) => {

163

throw new ValidationError("Invalid input");

164

}, new Error());

165

166

// Pin test for focused debugging

167

const debugTest = new Test("debug test", (test) => new TestContext(test), emitter, refiner);

168

debugTest

169

.pin()

170

.run(async (ctx) => {

171

// This test will run exclusively when pinned

172

// Note: You would need to import assert from your assertion library

173

// assert.isTrue(true);

174

}, new Error());

175

```

176

177

### TestContext Class

178

179

Test context that carries data and provides utilities for individual tests.

180

181

```typescript { .api }

182

/**

183

* Test context carries context data for a given test

184

*/

185

class TestContext {

186

/** The test instance this context belongs to */

187

test: Test;

188

189

/** Register a cleanup function that runs after the test finishes */

190

cleanup(cleanupCallback: TestHooksCleanupHandler<TestContext>): void;

191

192

constructor(test: Test);

193

}

194

```

195

196

**Usage Examples:**

197

198

```typescript

199

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

200

201

test("should handle cleanup", async (ctx) => {

202

// Set up resources

203

const connection = await createDatabaseConnection();

204

const tempFile = await createTempFile();

205

206

// Register cleanup functions

207

ctx.cleanup(async () => {

208

await connection.close();

209

console.log("Database connection closed");

210

});

211

212

ctx.cleanup(async () => {

213

await deleteTempFile(tempFile);

214

console.log("Temp file deleted");

215

});

216

217

// Test logic

218

await connection.query("SELECT 1");

219

await writeToFile(tempFile, "test data");

220

221

// Cleanup functions will run automatically after test completion

222

});

223

```

224

225

### Group Class

226

227

Container for organizing related tests with shared configuration and hooks.

228

229

```typescript { .api }

230

/**

231

* TestGroup is used to bulk configure a collection of tests and define lifecycle hooks

232

*/

233

class Group {

234

/** Add a test to this group */

235

add(test: Test): void;

236

237

/** Enable bail mode for this group */

238

bail(toggle?: boolean): this;

239

240

/** Set timeout for all tests in group */

241

timeout(duration: number): this;

242

243

/** Set retry count for all tests in group */

244

retry(count: number): this;

245

246

/** Add group setup hook (runs once before all tests) */

247

setup(handler: GroupHooksHandler<TestContext>): this;

248

249

/** Add group teardown hook (runs once after all tests) */

250

teardown(handler: GroupHooksHandler<TestContext>): this;

251

252

/** Add hooks that run before/after each test */

253

each: {

254

setup(handler: GroupHooksHandler<TestContext>): Group;

255

teardown(handler: GroupHooksHandler<TestContext>): Group;

256

};

257

258

/** Apply function to all tests in group */

259

tap(handler: (test: Test) => void): this;

260

}

261

262

type GroupHooksHandler<Context> = (context: Context) => void | Promise<void>;

263

```

264

265

**Usage Examples:**

266

267

```typescript

268

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

269

270

// Create group

271

const emitter = new Emitter();

272

const refiner = new Refiner();

273

const group = new Group("Database Tests", emitter, refiner);

274

275

// Configure group

276

group

277

.timeout(10000)

278

.retry(1)

279

.bail(false);

280

281

// Add group-level hooks

282

group.setup(async (context) => {

283

console.log("Setting up database for all tests");

284

context.db = await setupDatabase();

285

});

286

287

group.teardown(async (context) => {

288

console.log("Cleaning up database after all tests");

289

await cleanupDatabase(context.db);

290

});

291

292

// Add per-test hooks

293

group.each.setup(async (context) => {

294

await context.db.beginTransaction();

295

});

296

297

group.each.teardown(async (context) => {

298

await context.db.rollbackTransaction();

299

});

300

301

// Apply configuration to all tests

302

group.tap((test) => {

303

test.timeout(5000);

304

});

305

```

306

307

### Suite Class

308

309

Top-level container representing a collection of tests and groups for a specific testing category.

310

311

```typescript { .api }

312

/**

313

* A suite is a collection of tests created around a given testing type

314

*/

315

class Suite {

316

/** The suite name */

317

name: string;

318

319

/** Add a test or group to this suite */

320

add(testOrGroup: Test | Group): void;

321

322

/** Enable bail mode for this suite */

323

bail(toggle?: boolean): this;

324

325

/** Set timeout for all tests in suite */

326

timeout(duration: number): this;

327

328

/** Set retry count for all tests in suite */

329

retry(count: number): this;

330

331

/** Register callback for group events */

332

onGroup(callback: (group: Group) => void): void;

333

334

/** Register callback for test events */

335

onTest(callback: (test: Test) => void): void;

336

}

337

```

338

339

**Usage Examples:**

340

341

```typescript

342

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

343

344

// Create suite

345

const emitter = new Emitter();

346

const refiner = new Refiner();

347

const suite = new Suite("Integration Tests", emitter, refiner);

348

349

// Configure suite

350

suite

351

.timeout(30000)

352

.bail(true);

353

354

// Listen to events

355

suite.onGroup((group) => {

356

console.log(`Group added to suite: ${group.title}`);

357

});

358

359

suite.onTest((test) => {

360

console.log(`Test added to suite: ${test.title}`);

361

});

362

363

// Add tests and groups

364

const apiGroup = new Group("API Tests", emitter, refiner);

365

suite.add(apiGroup);

366

367

const standaloneTest = new Test("standalone test", (test) => new TestContext(test), emitter, refiner);

368

suite.add(standaloneTest);

369

```

370

371

### Emitter Class

372

373

Event emitter for communication between test runner components.

374

375

```typescript { .api }

376

/**

377

* Event emitter for test runner communication

378

*/

379

class Emitter {

380

/** Listen to an event */

381

on(event: string, callback: (...args: any[]) => void): void;

382

383

/** Emit an event */

384

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

385

386

/** Listen to an event once */

387

once(event: string, callback: (...args: any[]) => void): void;

388

389

/** Remove event listener */

390

off(event: string, callback: (...args: any[]) => void): void;

391

}

392

```

393

394

**Usage Examples:**

395

396

```typescript

397

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

398

399

const emitter = new Emitter();

400

401

// Listen to events

402

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

403

console.log(`Test started: ${payload.title}`);

404

});

405

406

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

407

const status = payload.hasError ? "FAILED" : "PASSED";

408

console.log(`Test ${status}: ${payload.title}`);

409

});

410

411

// Emit events

412

emitter.emit("test:start", { title: "My Test" });

413

emitter.emit("test:end", { title: "My Test", hasError: false });

414

415

// One-time listener

416

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

417

console.log("All tests completed");

418

});

419

```

420

421

## Types

422

423

### Core Class Types

424

425

```typescript { .api }

426

interface TestExecutor<Context, TestData> {

427

(context: Context, done?: Function): void | Promise<void>;

428

}

429

430

interface ReporterContract {

431

name: string;

432

handler: (runner: Runner, emitter: Emitter) => void;

433

}

434

435

interface TestHooksHandler<Context> {

436

(context: Context): void | Promise<void>;

437

}

438

439

interface TestHooksCleanupHandler<Context> {

440

(context: Context): void | Promise<void>;

441

}

442

443

interface GroupHooksHandler<Context> {

444

(context: Context): void | Promise<void>;

445

}

446

```

447

448

### Summary and Result Types

449

450

```typescript { .api }

451

interface RunnerSummary {

452

hasError: boolean;

453

aggregates: {

454

passed: number;

455

failed: number;

456

skipped: number;

457

todo: number;

458

total: number;

459

};

460

failureTree: Array<{

461

name: string;

462

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

463

children: Array<{

464

name: string;

465

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

466

}>;

467

}>;

468

}

469

```