or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

assertions.mdcli.mdconfiguration.mderror-handling.mdevents.mdhooks.mdindex.mdtest-definition.mdtest-flavors.mdutilities.md

hooks.mddocs/

0

# Hook System

1

2

Global and module-level hooks for setup and teardown operations, providing flexible test lifecycle management across all tests or within specific modules.

3

4

## Capabilities

5

6

### Global Hooks

7

8

Execute functions before or after every test across all modules.

9

10

```javascript { .api }

11

/**

12

* Global beforeEach hook - runs before every test

13

* @param {Function} callback - Function to execute before each test

14

*/

15

QUnit.hooks.beforeEach(callback)

16

17

/**

18

* Global afterEach hook - runs after every test

19

* @param {Function} callback - Function to execute after each test

20

*/

21

QUnit.hooks.afterEach(callback)

22

```

23

24

**Usage Examples:**

25

26

```javascript

27

import QUnit from "qunit";

28

29

// Global setup that runs before every test

30

QUnit.hooks.beforeEach(function(assert) {

31

// Reset global state

32

window.testData = {};

33

34

// Clear any timers

35

clearAllTimers();

36

37

// Log test start

38

console.log(`Starting test: ${assert.test.testName}`);

39

});

40

41

// Global cleanup that runs after every test

42

QUnit.hooks.afterEach(function(assert) {

43

// Cleanup DOM modifications

44

document.body.innerHTML = "";

45

46

// Reset mocks

47

jest.restoreAllMocks();

48

49

// Log test completion

50

console.log(`Completed test: ${assert.test.testName}`);

51

});

52

```

53

54

### Module-Level Hooks

55

56

Execute functions at specific points in module lifecycle (documented in test-definition.md for reference).

57

58

```javascript { .api }

59

/**

60

* Module hooks (defined within module options or callback)

61

* @typedef {Object} ModuleOptions

62

* @property {Function} [before] - Run once before all tests in module

63

* @property {Function} [beforeEach] - Run before each test in module

64

* @property {Function} [afterEach] - Run after each test in module

65

* @property {Function} [after] - Run once after all tests in module

66

*/

67

68

// Available within module callback function:

69

hooks.before(callback) // Module-level before hook

70

hooks.beforeEach(callback) // Module-level beforeEach hook

71

hooks.afterEach(callback) // Module-level afterEach hook

72

hooks.after(callback) // Module-level after hook

73

```

74

75

### Hook Execution Order

76

77

Understanding the order of hook execution is important for proper test setup:

78

79

**Setup Order (before test):**

80

1. Module `before()` (once per module, before first test)

81

2. Global `QUnit.hooks.beforeEach()`

82

3. Module `beforeEach()`

83

4. Test execution

84

85

**Teardown Order (after test):**

86

1. Module `afterEach()` (in reverse order of registration)

87

2. Global `QUnit.hooks.afterEach()`

88

3. Module `after()` (once per module, after last test, in reverse order)

89

90

**Usage Examples:**

91

92

```javascript

93

// Global hooks that apply to all tests

94

QUnit.hooks.beforeEach(function(assert) {

95

// This runs before every single test

96

this.startTime = Date.now();

97

console.log(`Starting test: ${assert.test.testName}`);

98

});

99

100

QUnit.hooks.afterEach(function(assert) {

101

// This runs after every single test

102

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

103

console.log(`Test duration: ${duration}ms`);

104

});

105

106

// Module with hooks defined in options

107

QUnit.module("Database Tests", {

108

before: function() {

109

// Runs once before all tests in this module

110

this.db = new TestDatabase();

111

this.db.connect();

112

},

113

114

beforeEach: function(assert) {

115

// Runs before each test in this module (after global beforeEach)

116

this.db.clearTables();

117

this.transaction = this.db.beginTransaction();

118

},

119

120

afterEach: function(assert) {

121

// Runs after each test in this module (before global afterEach)

122

this.transaction.rollback();

123

},

124

125

after: function() {

126

// Runs once after all tests in this module

127

this.db.disconnect();

128

}

129

}, function() {

130

// Tests go here

131

});

132

133

// Alternative: Module with hooks defined in callback

134

QUnit.module("API Tests", function(hooks) {

135

136

QUnit.test("user creation", function(assert) {

137

// Global beforeEach runs first

138

// Module before ran once at start

139

// Module beforeEach runs

140

// Test executes

141

// Module afterEach runs

142

// Global afterEach runs last

143

144

const user = this.db.createUser("test");

145

assert.ok(user.id, "user has ID");

146

});

147

148

QUnit.test("user deletion", function(assert) {

149

// Same hook order applies

150

const user = this.db.createUser("test");

151

this.db.deleteUser(user.id);

152

assert.notOk(this.db.findUser(user.id), "user was deleted");

153

});

154

});

155

```

156

157

### Hook Context and Scope

158

159

Hooks share context with tests and other hooks within the same module.

160

161

```javascript { .api }

162

/**

163

* Hook context - hooks and tests share the same testEnvironment object

164

* Properties can be added dynamically and will be available to all

165

* hooks and tests within the same module

166

*/

167

// this.propertyName is available in hooks and tests

168

// The 'this' context is the module's testEnvironment

169

```

170

171

**Usage Examples:**

172

173

```javascript

174

QUnit.module("API Tests", {

175

before: function() {

176

// Set up shared resources

177

this.apiClient = new APIClient();

178

this.testUser = { name: "Test User", email: "test@example.com" };

179

},

180

181

beforeEach: function() {

182

// Prepare for each test

183

this.requestId = Math.random().toString(36);

184

},

185

186

afterEach: function() {

187

// Clean up after each test

188

if (this.createdResources) {

189

this.createdResources.forEach(resource => {

190

this.apiClient.delete(resource.url);

191

});

192

this.createdResources = [];

193

}

194

}

195

}, function() {

196

197

QUnit.test("create user", function(assert) {

198

// Access shared context from hooks

199

const response = this.apiClient.post("/users", this.testUser);

200

201

// Store for cleanup

202

this.createdResources = [{ url: `/users/${response.id}` }];

203

204

assert.ok(response.id, "user was created");

205

});

206

});

207

```

208

209

### Async Hooks

210

211

Hooks can be asynchronous using promises or async/await.

212

213

```javascript { .api }

214

/**

215

* Async hooks - QUnit automatically waits for Promise resolution

216

* Both promise-returning and async/await patterns are supported

217

*/

218

219

// Promise-based hooks

220

hooks.before(function() {

221

return fetch('/setup').then(response => {

222

this.setupData = response.data;

223

});

224

});

225

226

// Async/await hooks

227

hooks.beforeEach(async function() {

228

this.testData = await generateTestData();

229

});

230

```

231

232

**Usage Examples:**

233

234

```javascript

235

QUnit.module("Async Setup Tests", {

236

before: async function() {

237

// Async setup

238

this.server = await startTestServer();

239

this.database = await connectToDatabase();

240

},

241

242

beforeEach: async function() {

243

// Async preparation for each test

244

await this.database.seedTestData();

245

this.session = await this.server.createSession();

246

},

247

248

afterEach: async function() {

249

// Async cleanup after each test

250

await this.session.destroy();

251

await this.database.clearTestData();

252

},

253

254

after: async function() {

255

// Async teardown

256

await this.database.disconnect();

257

await this.server.stop();

258

}

259

}, function() {

260

261

QUnit.test("async test with async hooks", async function(assert) {

262

const response = await this.server.request("/api/data");

263

assert.strictEqual(response.status, 200);

264

});

265

});

266

267

// Global async hooks

268

QUnit.hooks.beforeEach(async function() {

269

await setupGlobalState();

270

});

271

272

QUnit.hooks.afterEach(async function() {

273

await cleanupGlobalState();

274

});

275

```

276

277

### Error Handling in Hooks

278

279

Handle errors gracefully in hook functions.

280

281

**Usage Examples:**

282

283

```javascript

284

QUnit.module("Error Handling", {

285

before: function() {

286

try {

287

this.resource = createExpensiveResource();

288

} catch (error) {

289

// Hook errors will fail all tests in the module

290

throw new Error(`Failed to initialize resource: ${error.message}`);

291

}

292

},

293

294

beforeEach: function(assert) {

295

if (!this.resource) {

296

assert.pushResult({

297

result: false,

298

message: "Resource not available, skipping test",

299

source: "beforeEach hook"

300

});

301

return;

302

}

303

304

this.resource.reset();

305

}

306

}, function() {

307

// Tests will only run if hooks succeed

308

});

309

```

310

311

## Hook Function Signatures

312

313

```javascript { .api }

314

/**

315

* Module-level hook signatures

316

* @param {Function} before - function() - no assert parameter

317

* @param {Function} beforeEach - function(assert) - receives assert object

318

* @param {Function} afterEach - function(assert) - receives assert object

319

* @param {Function} after - function() - no assert parameter

320

*/

321

322

/**

323

* Global hook signatures

324

* @param {Function} callback - function(assert) - receives assert object

325

*/

326

QUnit.hooks.beforeEach(function(assert) {

327

// Global beforeEach always receives assert parameter

328

});

329

330

QUnit.hooks.afterEach(function(assert) {

331

// Global afterEach always receives assert parameter

332

});

333

334

/**

335

* Hook context (this)

336

* - All hooks and tests within a module share the same testEnvironment

337

* - Properties set on 'this' are available to subsequent hooks and tests

338

* - The context is reset for each module

339

*/

340

```

341

342

## Hook Registration Methods

343

344

```javascript { .api }

345

// Method 1: Module options object

346

QUnit.module('Module Name', {

347

before() { /* ... */ },

348

beforeEach(assert) { /* ... */ },

349

afterEach(assert) { /* ... */ },

350

after() { /* ... */ }

351

}, function() {

352

// tests

353

});

354

355

// Method 2: Hooks parameter in module callback

356

QUnit.module('Module Name', function(hooks) {

357

hooks.before(function() { /* ... */ });

358

hooks.beforeEach(function(assert) { /* ... */ });

359

hooks.afterEach(function(assert) { /* ... */ });

360

hooks.after(function() { /* ... */ });

361

362

// tests

363

});

364

365

// Method 3: Global hooks

366

QUnit.hooks.beforeEach(function(assert) { /* ... */ });

367

QUnit.hooks.afterEach(function(assert) { /* ... */ });

368

```