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

error-handling.mddocs/

0

# Error Handling

1

2

Robust error and exception handling capabilities for managing uncaught errors, manual failure reporting, and debugging during test execution.

3

4

## Capabilities

5

6

### Uncaught Error Handling

7

8

Handle and report uncaught errors that occur during test execution.

9

10

```javascript { .api }

11

/**

12

* Register callback for uncaught window errors (browser environment)

13

* @param {Function} callback - Function to handle window errors

14

*/

15

QUnit.onError(callback)

16

17

/**

18

* Register callback for uncaught exceptions (Node.js and modern browsers)

19

* @param {Function} callback - Function to handle uncaught exceptions

20

*/

21

QUnit.onUncaughtException(callback)

22

```

23

24

**Usage Examples:**

25

26

```javascript

27

import QUnit from "qunit";

28

29

// Handle uncaught window errors in browser

30

QUnit.onError(function(errorEvent) {

31

console.error("Uncaught window error:", {

32

message: errorEvent.message,

33

filename: errorEvent.filename,

34

lineno: errorEvent.lineno,

35

colno: errorEvent.colno,

36

error: errorEvent.error

37

});

38

39

// Return true to prevent default browser error handling

40

return true;

41

});

42

43

// Handle uncaught exceptions (promises, async functions, etc.)

44

QUnit.onUncaughtException(function(error) {

45

console.error("Uncaught exception:", {

46

name: error.name,

47

message: error.message,

48

stack: error.stack

49

});

50

51

// Log additional context if available

52

if (QUnit.config.current) {

53

console.error("Error occurred in test:", QUnit.config.current.testName);

54

}

55

});

56

57

// Example test that might generate uncaught errors

58

QUnit.test("async error handling", function(assert) {

59

const done = assert.async();

60

61

// This promise rejection might be uncaught

62

Promise.resolve().then(() => {

63

throw new Error("Simulated async error");

64

});

65

66

setTimeout(() => {

67

assert.ok(true, "test completed");

68

done();

69

}, 100);

70

});

71

```

72

73

### Manual Failure Reporting

74

75

Manually report test failures and push custom failure messages.

76

77

```javascript { .api }

78

/**

79

* Manually record a test failure with custom message and source location

80

* @param message - Failure message

81

* @param source - Source location information (optional)

82

*/

83

function pushFailure(message: string, source?: string): void;

84

```

85

86

**Usage Examples:**

87

88

```javascript

89

QUnit.test("manual failure reporting", function(assert) {

90

const user = getCurrentUser();

91

92

if (!user) {

93

// Report failure when user is not available

94

QUnit.pushFailure("Test requires authenticated user but none found");

95

return;

96

}

97

98

// Test continues if user is available

99

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

100

});

101

102

// Helper function for conditional testing

103

function requireFeature(featureName, callback) {

104

if (!isFeatureEnabled(featureName)) {

105

QUnit.pushFailure(

106

`Test requires feature '${featureName}' to be enabled`,

107

QUnit.stack(1) // Include stack trace from caller

108

);

109

return;

110

}

111

112

callback();

113

}

114

115

QUnit.test("feature-dependent test", function(assert) {

116

requireFeature("advanced-search", () => {

117

const results = performAdvancedSearch("query");

118

assert.ok(results.length > 0, "search returns results");

119

});

120

});

121

```

122

123

### Error Context and Debugging

124

125

Enhanced error reporting with context information and debugging utilities.

126

127

**Usage Examples:**

128

129

```javascript

130

// Enhanced error reporting with context

131

function createTestErrorHandler() {

132

const testContext = {

133

browser: navigator?.userAgent || "Node.js",

134

url: window?.location?.href || "N/A",

135

timestamp: new Date().toISOString()

136

};

137

138

QUnit.onError(function(errorEvent) {

139

const errorInfo = {

140

...testContext,

141

error: {

142

message: errorEvent.message,

143

filename: errorEvent.filename,

144

line: errorEvent.lineno,

145

column: errorEvent.colno,

146

stack: errorEvent.error?.stack

147

},

148

test: QUnit.config.current ? {

149

name: QUnit.config.current.testName,

150

module: QUnit.config.current.module.name

151

} : null

152

};

153

154

// Send to error tracking service

155

console.error("Test execution error:", JSON.stringify(errorInfo, null, 2));

156

157

// Report as test failure

158

QUnit.pushFailure(

159

`Uncaught error in test: ${errorEvent.message}`,

160

errorEvent.error?.stack

161

);

162

});

163

164

QUnit.onUncaughtException(function(error) {

165

const errorInfo = {

166

...testContext,

167

error: {

168

name: error.name,

169

message: error.message,

170

stack: error.stack

171

},

172

test: QUnit.config.current ? {

173

name: QUnit.config.current.testName,

174

module: QUnit.config.current.module.name

175

} : null

176

};

177

178

console.error("Uncaught exception in test:", JSON.stringify(errorInfo, null, 2));

179

180

QUnit.pushFailure(

181

`Uncaught exception: ${error.name}: ${error.message}`,

182

error.stack

183

);

184

});

185

}

186

187

// Initialize error handling

188

createTestErrorHandler();

189

```

190

191

### Test-Specific Error Handling

192

193

Handle errors within specific tests or modules.

194

195

**Usage Examples:**

196

197

```javascript

198

QUnit.module("Error Handling Tests", {

199

beforeEach: function() {

200

// Set up test-specific error tracking

201

this.errors = [];

202

203

this.originalOnError = QUnit.onError;

204

QUnit.onError = (error) => {

205

this.errors.push(error);

206

return true; // Prevent default handling

207

};

208

},

209

210

afterEach: function() {

211

// Restore original error handler

212

QUnit.onError = this.originalOnError;

213

}

214

}, function() {

215

216

QUnit.test("capture and verify errors", function(assert) {

217

// Intentionally trigger an error

218

setTimeout(() => {

219

throw new Error("Test error");

220

}, 10);

221

222

const done = assert.async();

223

224

setTimeout(() => {

225

assert.strictEqual(this.errors.length, 1, "one error was captured");

226

assert.strictEqual(this.errors[0].message, "Test error", "correct error message");

227

done();

228

}, 50);

229

});

230

});

231

```

232

233

### Error Recovery and Resilience

234

235

Implement error recovery patterns for robust test suites.

236

237

**Usage Examples:**

238

239

```javascript

240

// Retry mechanism for flaky tests

241

function retryOnError(testFn, maxRetries = 3) {

242

return function(assert) {

243

let attempt = 0;

244

let lastError = null;

245

246

const runTest = () => {

247

attempt++;

248

249

try {

250

const result = testFn.call(this, assert);

251

252

// Handle async tests

253

if (result && typeof result.catch === 'function') {

254

return result.catch(error => {

255

lastError = error;

256

if (attempt < maxRetries) {

257

console.warn(`Test attempt ${attempt} failed, retrying...`);

258

return runTest();

259

} else {

260

QUnit.pushFailure(

261

`Test failed after ${maxRetries} attempts. Last error: ${error.message}`,

262

error.stack

263

);

264

}

265

});

266

}

267

268

return result;

269

} catch (error) {

270

lastError = error;

271

if (attempt < maxRetries) {

272

console.warn(`Test attempt ${attempt} failed, retrying...`);

273

return runTest();

274

} else {

275

QUnit.pushFailure(

276

`Test failed after ${maxRetries} attempts. Last error: ${error.message}`,

277

error.stack

278

);

279

}

280

}

281

};

282

283

return runTest();

284

};

285

}

286

287

QUnit.test("flaky network test", retryOnError(async function(assert) {

288

const response = await fetch("/api/unstable-endpoint");

289

assert.strictEqual(response.status, 200, "API responds successfully");

290

}));

291

292

// Circuit breaker pattern for external dependencies

293

class TestCircuitBreaker {

294

constructor(threshold = 3, timeout = 30000) {

295

this.failureCount = 0;

296

this.threshold = threshold;

297

this.timeout = timeout;

298

this.nextAttempt = Date.now();

299

this.state = 'CLOSED'; // CLOSED, OPEN, HALF_OPEN

300

}

301

302

async execute(testFn) {

303

if (this.state === 'OPEN') {

304

if (Date.now() < this.nextAttempt) {

305

QUnit.pushFailure("Circuit breaker is OPEN - skipping test");

306

return;

307

} else {

308

this.state = 'HALF_OPEN';

309

}

310

}

311

312

try {

313

const result = await testFn();

314

this.onSuccess();

315

return result;

316

} catch (error) {

317

this.onFailure();

318

throw error;

319

}

320

}

321

322

onSuccess() {

323

this.failureCount = 0;

324

this.state = 'CLOSED';

325

}

326

327

onFailure() {

328

this.failureCount++;

329

if (this.failureCount >= this.threshold) {

330

this.state = 'OPEN';

331

this.nextAttempt = Date.now() + this.timeout;

332

}

333

}

334

}

335

336

const externalServiceBreaker = new TestCircuitBreaker();

337

338

QUnit.test("external service test", async function(assert) {

339

await externalServiceBreaker.execute(async () => {

340

const result = await callExternalService();

341

assert.ok(result.success, "external service responded");

342

});

343

});

344

```

345

346

### Legacy Error Handling

347

348

Support for deprecated error handling methods.

349

350

```javascript { .api }

351

/**

352

* @deprecated Use QUnit.onUncaughtException instead

353

* Handle unhandled promise rejections

354

* @param reason - Rejection reason

355

*/

356

function onUnhandledRejection(reason: any): void;

357

```

358

359

**Usage Examples:**

360

361

```javascript

362

// Legacy method (deprecated but still available)

363

QUnit.onUnhandledRejection(function(reason) {

364

console.warn("QUnit.onUnhandledRejection is deprecated");

365

console.error("Unhandled rejection:", reason);

366

});

367

368

// Modern equivalent

369

QUnit.onUncaughtException(function(error) {

370

console.error("Uncaught exception:", error);

371

});

372

```

373

374

## Types

375

376

```javascript { .api }

377

interface ErrorHandler {

378

(error: Error): void;

379

}

380

381

interface WindowErrorHandler {

382

(errorEvent: ErrorEvent): boolean | void;

383

}

384

385

interface ErrorEvent {

386

/** Error message */

387

message: string;

388

/** Source filename */

389

filename: string;

390

/** Line number */

391

lineno: number;

392

/** Column number */

393

colno: number;

394

/** Error object */

395

error: Error;

396

}

397

398

interface TestError {

399

/** Error name */

400

name: string;

401

/** Error message */

402

message: string;

403

/** Stack trace */

404

stack: string;

405

/** Source location */

406

source?: string;

407

/** Test context when error occurred */

408

testName?: string;

409

/** Module context when error occurred */

410

module?: string;

411

}

412

413

interface ErrorContext {

414

/** Current test information */

415

test?: {

416

name: string;

417

module: string;

418

id: string;

419

};

420

/** Browser/environment information */

421

environment?: {

422

userAgent: string;

423

url: string;

424

timestamp: string;

425

};

426

/** Custom error data */

427

[key: string]: any;

428

}

429

```