or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

event-system.mdindex.mdstate-management.mdtest-execution.mdtest-globals.md
tile.json

event-system.mddocs/

0

# Event System

1

2

Event-driven architecture for handling test lifecycle events and integrating with custom test environments. The event system provides comprehensive hooks into test execution phases for monitoring, reporting, and custom behavior.

3

4

## Capabilities

5

6

### Event Handler Types

7

8

Event handlers are functions that respond to test lifecycle events. Note that `addEventHandler` is not part of the public API - event handling is typically done through custom test environments.

9

10

```typescript { .api }

11

interface EventHandler {

12

/** Handle async events (most test lifecycle events) */

13

(event: AsyncEvent, state: State): void | Promise<void>;

14

/** Handle sync events (definition and error events) */

15

(event: SyncEvent, state: State): void;

16

}

17

```

18

19

### Event Integration with Test Environments

20

21

Custom test environments can handle events by implementing the `handleTestEvent` method.

22

23

```typescript { .api }

24

/**

25

* Custom test environment with event handling

26

*/

27

abstract class TestEnvironment {

28

/**

29

* Handle test events

30

* @param event - The event that occurred

31

* @param state - Current test state

32

* @returns Promise that resolves when handling is complete

33

*/

34

abstract handleTestEvent(event: Event, state: State): Promise<void>;

35

}

36

```

37

38

**Usage Examples:**

39

40

```typescript

41

import { TestEnvironment as NodeEnvironment } from 'jest-environment-node';

42

import { Event, State } from 'jest-circus';

43

44

class CustomTestEnvironment extends NodeEnvironment {

45

private testStartTime: number = 0;

46

47

async handleTestEvent(event: Event, state: State): Promise<void> {

48

switch (event.name) {

49

case 'setup':

50

console.log('Test suite setup');

51

break;

52

53

case 'test_start':

54

this.testStartTime = Date.now();

55

console.log(`Starting: ${event.test.name}`);

56

break;

57

58

case 'test_done':

59

const duration = Date.now() - this.testStartTime;

60

const status = event.test.errors.length > 0 ? 'FAILED' : 'PASSED';

61

console.log(`${status}: ${event.test.name} (${duration}ms)`);

62

63

// Custom logic for failed tests

64

if (event.test.errors.length > 0) {

65

await this.handleTestFailure(event.test);

66

}

67

break;

68

69

case 'run_finish':

70

await this.generateReport(state);

71

break;

72

}

73

}

74

75

private async handleTestFailure(test: TestEntry): Promise<void> {

76

// Custom failure handling

77

await this.captureScreenshot(test.name);

78

await this.logSystemState();

79

}

80

81

private async generateReport(state: State): Promise<void> {

82

// Generate custom test report

83

const report = {

84

totalTests: this.countTests(state.rootDescribeBlock),

85

unhandledErrors: state.unhandledErrors.length,

86

timestamp: new Date().toISOString()

87

};

88

await this.saveReport(report);

89

}

90

}

91

92

module.exports = CustomTestEnvironment;

93

```

94

95

## Event Types

96

97

### Synchronous Events

98

99

Events that are dispatched synchronously and do not pause test execution.

100

101

```typescript { .api }

102

type SyncEvent =

103

| StartDescribeDefinitionEvent

104

| FinishDescribeDefinitionEvent

105

| AddHookEvent

106

| AddTestEvent

107

| ErrorEvent;

108

109

interface StartDescribeDefinitionEvent {

110

name: 'start_describe_definition';

111

blockName: BlockName;

112

mode: BlockMode;

113

asyncError: Error;

114

}

115

116

interface FinishDescribeDefinitionEvent {

117

name: 'finish_describe_definition';

118

blockName: BlockName;

119

mode: BlockMode;

120

}

121

122

interface AddHookEvent {

123

name: 'add_hook';

124

hookType: HookType;

125

fn: HookFn;

126

timeout: number | undefined;

127

asyncError: Error;

128

}

129

130

interface AddTestEvent {

131

name: 'add_test';

132

testName: TestName;

133

fn: TestFn;

134

mode?: TestMode;

135

concurrent: boolean;

136

timeout: number | undefined;

137

failing: boolean;

138

asyncError: Error;

139

}

140

141

interface ErrorEvent {

142

name: 'error';

143

error: Exception;

144

}

145

```

146

147

### Asynchronous Events

148

149

Events that are dispatched asynchronously and pause test execution until all handlers complete.

150

151

```typescript { .api }

152

type AsyncEvent =

153

| SetupEvent

154

| IncludeTestLocationEvent

155

| RunStartEvent

156

| RunFinishEvent

157

| RunDescribeStartEvent

158

| RunDescribeFinishEvent

159

| TestStartEvent

160

| TestDoneEvent

161

| TestRetryEvent

162

| HookStartEvent

163

| HookSuccessEvent

164

| HookFailureEvent;

165

166

interface SetupEvent {

167

name: 'setup';

168

testNamePattern?: string;

169

runtimeGlobals: JestGlobals;

170

parentProcess: NodeJS.Process;

171

}

172

173

interface IncludeTestLocationEvent {

174

name: 'include_test_location_in_result';

175

}

176

177

interface RunStartEvent {

178

name: 'run_start';

179

}

180

181

interface RunFinishEvent {

182

name: 'run_finish';

183

}

184

185

interface RunDescribeStartEvent {

186

name: 'run_describe_start';

187

describeBlock: DescribeBlock;

188

}

189

190

interface RunDescribeFinishEvent {

191

name: 'run_describe_finish';

192

describeBlock: DescribeBlock;

193

}

194

195

interface TestStartEvent {

196

name: 'test_start';

197

test: TestEntry;

198

}

199

200

interface TestDoneEvent {

201

name: 'test_done';

202

test: TestEntry;

203

}

204

205

interface TestRetryEvent {

206

name: 'test_retry';

207

test: TestEntry;

208

}

209

210

interface HookStartEvent {

211

name: 'hook_start';

212

hook: Hook;

213

}

214

215

interface HookSuccessEvent {

216

name: 'hook_success';

217

hook: Hook;

218

describeBlock?: DescribeBlock;

219

test?: TestEntry;

220

}

221

222

interface HookFailureEvent {

223

name: 'hook_failure';

224

error: Exception;

225

hook: Hook;

226

describeBlock?: DescribeBlock;

227

test?: TestEntry;

228

}

229

```

230

231

**Usage Examples:**

232

233

```typescript

234

import { addEventHandler } from "jest-circus";

235

236

// Handle specific event types

237

addEventHandler((event, state) => {

238

// TypeScript type narrowing

239

if (event.name === 'test_start') {

240

// event is now typed as TestStartEvent

241

console.log(`Test started: ${event.test.name}`);

242

console.log(`Parent describe: ${event.test.parent.name}`);

243

}

244

245

if (event.name === 'hook_failure') {

246

// event is now typed as HookFailureEvent

247

console.error(`${event.hook.type} hook failed:`, event.error);

248

if (event.test) {

249

console.error(`In test: ${event.test.name}`);

250

}

251

}

252

});

253

254

// Handle all test lifecycle events

255

addEventHandler(async (event, state) => {

256

const testEvents = [

257

'test_start',

258

'test_done',

259

'test_retry'

260

] as const;

261

262

if (testEvents.includes(event.name as any)) {

263

await logTestEvent(event, state);

264

}

265

});

266

```

267

268

## Event Timing and Execution

269

270

Important notes about event handling behavior:

271

272

- **Synchronous events** (`start_describe_definition`, `finish_describe_definition`, `add_hook`, `add_test`, `error`) do not pause test execution

273

- **Asynchronous events** pause execution until all handlers complete their promises

274

- Event handlers should be registered before test execution begins

275

- Multiple handlers can be registered and will execute in registration order

276

- Throwing errors in event handlers will stop test execution

277

- Event data should not be mutated as it may cause unexpected behavior

278

279

**Usage Examples:**

280

281

```typescript

282

import { addEventHandler } from "jest-circus";

283

284

// Event handler that doesn't block

285

addEventHandler((event, state) => {

286

// Synchronous logging - won't pause tests

287

if (event.name === 'add_test') {

288

console.log(`Registered test: ${event.testName}`);

289

}

290

});

291

292

// Event handler that blocks until complete

293

addEventHandler(async (event, state) => {

294

if (event.name === 'test_done') {

295

// This will pause until the async operation completes

296

await uploadTestResults(event.test);

297

}

298

});

299

300

// Error handling in event handlers

301

addEventHandler(async (event, state) => {

302

try {

303

if (event.name === 'run_finish') {

304

await generateReport(state);

305

}

306

} catch (error) {

307

console.error('Report generation failed:', error);

308

// Don't re-throw - would stop test execution

309

}

310

});

311

```