or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

basic-assertions.mdconfiguration.mdcontainment-assertions.mderror-assertions.mdindex.mdnumber-assertions.mdpattern-matching.mdpromise-assertions.mdproperty-assertions.mdstring-assertions.mdtype-assertions.md

error-assertions.mddocs/

0

# Error and Exception Assertions

1

2

Methods for testing function exceptions, error throwing, and error property validation.

3

4

## Exception Testing

5

6

### throw()

7

8

Test that a function throws an exception.

9

10

```javascript { .api }

11

/**

12

* Assert that the function throws an exception

13

* @param message - Optional expected error message (string, RegExp, or Function)

14

* @param properties - Optional expected error properties

15

* @returns This assertion for chaining

16

*/

17

throw(): Assertion;

18

throw(message: RegExp | string | Function, properties?: object): Assertion;

19

throw(properties: object): Assertion;

20

```

21

22

**Usage:**

23

```javascript

24

import should from 'should';

25

26

// Basic exception testing

27

(() => {

28

throw new Error('Something went wrong');

29

}).should.throw();

30

31

// Test specific error message

32

(() => {

33

throw new Error('Invalid input');

34

}).should.throw('Invalid input');

35

36

// Test error message with regex

37

(() => {

38

throw new Error('User not found: ID 123');

39

}).should.throw(/User not found/);

40

41

// Test error type

42

(() => {

43

throw new TypeError('Expected string');

44

}).should.throw(TypeError);

45

46

// Test error properties

47

(() => {

48

const error = new Error('Validation failed');

49

error.code = 400;

50

error.field = 'email';

51

throw error;

52

}).should.throw({ code: 400, field: 'email' });

53

54

// Combined message and properties

55

(() => {

56

const error = new Error('Database connection failed');

57

error.errno = -61;

58

error.code = 'ECONNREFUSED';

59

throw error;

60

}).should.throw('Database connection failed', { code: 'ECONNREFUSED' });

61

```

62

63

### throwError()

64

65

Alias for `throw()` with identical functionality.

66

67

```javascript { .api }

68

/**

69

* Assert that the function throws an error - alias for throw()

70

* @param message - Optional expected error message (string, RegExp, or Function)

71

* @param properties - Optional expected error properties

72

* @returns This assertion for chaining

73

*/

74

throwError(): Assertion;

75

throwError(message: RegExp | string | Function, properties?: object): Assertion;

76

throwError(properties: object): Assertion;

77

```

78

79

**Usage:**

80

```javascript

81

// Same functionality as throw()

82

(() => {

83

throw new Error('Critical failure');

84

}).should.throwError();

85

86

(() => {

87

throw new Error('Access denied');

88

}).should.throwError('Access denied');

89

90

(() => {

91

throw new RangeError('Index out of bounds');

92

}).should.throwError(RangeError);

93

```

94

95

## Specific Error Types

96

97

### Testing Different Error Types

98

```javascript

99

// TypeError testing

100

(() => {

101

const obj = null;

102

obj.property; // Will throw TypeError

103

}).should.throw(TypeError);

104

105

// RangeError testing

106

(() => {

107

const arr = new Array(-1); // Invalid array length

108

}).should.throw(RangeError);

109

110

// SyntaxError testing (in eval)

111

(() => {

112

eval('invalid javascript syntax !!!');

113

}).should.throw(SyntaxError);

114

115

// Custom error types

116

class ValidationError extends Error {

117

constructor(message, field) {

118

super(message);

119

this.name = 'ValidationError';

120

this.field = field;

121

}

122

}

123

124

(() => {

125

throw new ValidationError('Invalid email format', 'email');

126

}).should.throw(ValidationError);

127

```

128

129

## Async Function Testing

130

131

### Testing Async Functions That Throw

132

```javascript

133

// Promise-based async functions

134

async function asyncFunction() {

135

throw new Error('Async error');

136

}

137

138

// Test async function (returns rejected promise)

139

asyncFunction().should.be.rejected();

140

141

// With specific error

142

async function validateUser(id) {

143

if (!id) {

144

throw new Error('User ID is required');

145

}

146

// ... more logic

147

}

148

149

validateUser().should.be.rejectedWith('User ID is required');

150

```

151

152

### Testing Callback-based Functions

153

```javascript

154

function processData(data, callback) {

155

if (!data) {

156

callback(new Error('Data is required'));

157

return;

158

}

159

// Process data...

160

callback(null, processedData);

161

}

162

163

// Test callback error

164

function testCallback() {

165

processData(null, (err, result) => {

166

should.exist(err);

167

err.should.be.an.Error();

168

err.message.should.equal('Data is required');

169

should.not.exist(result);

170

});

171

}

172

```

173

174

## Error Property Validation

175

176

### Testing Custom Error Properties

177

```javascript

178

class APIError extends Error {

179

constructor(message, statusCode, details) {

180

super(message);

181

this.name = 'APIError';

182

this.statusCode = statusCode;

183

this.details = details;

184

}

185

}

186

187

function callAPI() {

188

throw new APIError('Request failed', 404, {

189

endpoint: '/users/123',

190

method: 'GET',

191

timestamp: Date.now()

192

});

193

}

194

195

// Test comprehensive error properties

196

(() => callAPI()).should.throw(APIError)

197

.and.have.property('statusCode', 404)

198

.and.have.property('details')

199

.which.has.property('endpoint');

200

201

// Alternative syntax

202

try {

203

callAPI();

204

should.fail('Expected APIError to be thrown');

205

} catch (error) {

206

error.should.be.instanceof(APIError);

207

error.should.have.property('message', 'Request failed');

208

error.should.have.property('statusCode', 404);

209

error.details.should.have.properties('endpoint', 'method');

210

error.details.endpoint.should.equal('/users/123');

211

}

212

```

213

214

## Validation Function Testing

215

216

### Input Validation

217

```javascript

218

function validateEmail(email) {

219

if (typeof email !== 'string') {

220

throw new TypeError('Email must be a string');

221

}

222

if (!email.includes('@')) {

223

throw new Error('Invalid email format');

224

}

225

if (email.length < 5) {

226

throw new Error('Email too short');

227

}

228

}

229

230

// Test various validation scenarios

231

(() => validateEmail(null)).should.throw(TypeError, 'Email must be a string');

232

(() => validateEmail('invalid')).should.throw('Invalid email format');

233

(() => validateEmail('a@b')).should.throw('Email too short');

234

(() => validateEmail('valid@email.com')).should.not.throw();

235

```

236

237

### Range Validation

238

```javascript

239

function validateAge(age) {

240

if (typeof age !== 'number') {

241

throw new TypeError('Age must be a number');

242

}

243

if (age < 0) {

244

throw new RangeError('Age cannot be negative');

245

}

246

if (age > 150) {

247

throw new RangeError('Age cannot exceed 150');

248

}

249

}

250

251

// Test age validation

252

(() => validateAge('25')).should.throw(TypeError);

253

(() => validateAge(-5)).should.throw(RangeError, 'Age cannot be negative');

254

(() => validateAge(200)).should.throw(RangeError, 'Age cannot exceed 150');

255

(() => validateAge(25)).should.not.throw();

256

```

257

258

### Configuration Validation

259

```javascript

260

function validateConfig(config) {

261

if (!config) {

262

throw new Error('Configuration is required');

263

}

264

if (!config.apiKey) {

265

const error = new Error('API key is missing');

266

error.code = 'CONFIG_MISSING_API_KEY';

267

throw error;

268

}

269

if (typeof config.timeout !== 'number' || config.timeout <= 0) {

270

const error = new Error('Timeout must be a positive number');

271

error.code = 'CONFIG_INVALID_TIMEOUT';

272

error.received = config.timeout;

273

throw error;

274

}

275

}

276

277

// Test configuration validation

278

(() => validateConfig(null)).should.throw('Configuration is required');

279

280

(() => validateConfig({})).should.throw({ code: 'CONFIG_MISSING_API_KEY' });

281

282

(() => validateConfig({

283

apiKey: 'test',

284

timeout: -1

285

})).should.throw('Timeout must be a positive number', {

286

code: 'CONFIG_INVALID_TIMEOUT',

287

received: -1

288

});

289

```

290

291

## Database and Network Error Testing

292

293

### Database Error Simulation

294

```javascript

295

class DatabaseError extends Error {

296

constructor(message, query, errno) {

297

super(message);

298

this.name = 'DatabaseError';

299

this.query = query;

300

this.errno = errno;

301

}

302

}

303

304

function executeQuery(sql) {

305

if (!sql) {

306

throw new DatabaseError('SQL query is required', null, 1001);

307

}

308

if (sql.includes('DROP TABLE')) {

309

throw new DatabaseError('DROP TABLE not allowed', sql, 1142);

310

}

311

// ... execute query

312

}

313

314

// Test database error handling

315

(() => executeQuery('')).should.throw(DatabaseError)

316

.with.property('errno', 1001);

317

318

(() => executeQuery('DROP TABLE users')).should.throw(DatabaseError)

319

.with.property('errno', 1142)

320

.and.have.property('query', 'DROP TABLE users');

321

```

322

323

### Network Error Simulation

324

```javascript

325

class NetworkError extends Error {

326

constructor(message, statusCode, url) {

327

super(message);

328

this.name = 'NetworkError';

329

this.statusCode = statusCode;

330

this.url = url;

331

}

332

}

333

334

function fetchData(url) {

335

if (!url.startsWith('https://')) {

336

throw new NetworkError('Only HTTPS URLs allowed', 400, url);

337

}

338

if (url.includes('blocked.com')) {

339

throw new NetworkError('Domain is blocked', 403, url);

340

}

341

// ... fetch data

342

}

343

344

// Test network error scenarios

345

(() => fetchData('http://insecure.com')).should.throw(NetworkError)

346

.with.properties({

347

statusCode: 400,

348

url: 'http://insecure.com'

349

});

350

351

(() => fetchData('https://blocked.com/api')).should.throw(NetworkError)

352

.with.property('statusCode', 403);

353

```

354

355

## Testing Functions That Should NOT Throw

356

357

### Successful Execution Testing

358

```javascript

359

function safeOperation(data) {

360

// This function should not throw for valid input

361

return data.toString().toUpperCase();

362

}

363

364

function robustParser(input) {

365

try {

366

return JSON.parse(input);

367

} catch (e) {

368

return null; // Return null instead of throwing

369

}

370

}

371

372

// Test that functions don't throw

373

(() => safeOperation('hello')).should.not.throw();

374

(() => safeOperation(123)).should.not.throw();

375

(() => robustParser('invalid json')).should.not.throw();

376

377

// Test return values of non-throwing functions

378

safeOperation('hello').should.equal('HELLO');

379

should(robustParser('invalid json')).be.null();

380

should(robustParser('{"valid": true}')).eql({ valid: true });

381

```

382

383

## Complex Error Scenario Testing

384

385

### Multiple Error Conditions

386

```javascript

387

function complexValidation(user) {

388

const errors = [];

389

390

if (!user.name || user.name.length < 2) {

391

errors.push({ field: 'name', message: 'Name must be at least 2 characters' });

392

}

393

394

if (!user.email || !user.email.includes('@')) {

395

errors.push({ field: 'email', message: 'Valid email is required' });

396

}

397

398

if (user.age !== undefined && (user.age < 0 || user.age > 150)) {

399

errors.push({ field: 'age', message: 'Age must be between 0 and 150' });

400

}

401

402

if (errors.length > 0) {

403

const error = new Error('Validation failed');

404

error.name = 'ValidationError';

405

error.errors = errors;

406

throw error;

407

}

408

409

return user;

410

}

411

412

// Test multiple validation errors

413

(() => complexValidation({

414

name: 'A',

415

email: 'invalid',

416

age: -5

417

})).should.throw('Validation failed')

418

.with.property('errors')

419

.which.has.length(3);

420

421

// Test successful validation

422

(() => complexValidation({

423

name: 'John Doe',

424

email: 'john@example.com',

425

age: 30

426

})).should.not.throw();

427

```

428

429

## Chaining and Negation

430

431

```javascript

432

const throwingFunction = () => {

433

throw new Error('Test error');

434

};

435

436

const nonThrowingFunction = () => {

437

return 'success';

438

};

439

440

// Chaining with other assertions

441

throwingFunction.should.be.a.Function().and.throw();

442

nonThrowingFunction.should.be.a.Function().and.not.throw();

443

444

// Complex chaining

445

(() => {

446

const error = new Error('Custom error');

447

error.code = 500;

448

throw error;

449

}).should.throw()

450

.with.property('message', 'Custom error')

451

.and.have.property('code', 500);

452

```