or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

asymmetric-matchers.mdcollection-string-matchers.mdconfiguration-extension.mdcore-matchers.mdexception-matchers.mdindex.mdnumeric-matchers.mdspy-mock-matchers.md
tile.json

asymmetric-matchers.mddocs/

0

# Asymmetric Matchers

1

2

Special matchers for flexible pattern matching and partial object comparison. These matchers allow for more flexible assertions when exact matching is not practical or desired.

3

4

## Capabilities

5

6

### General Matching

7

8

#### expect.anything

9

10

Matches any value except `null` and `undefined`.

11

12

```javascript { .api }

13

/**

14

* Matches anything except null or undefined

15

* @returns Anything matcher instance

16

*/

17

expect.anything(): Anything;

18

```

19

20

**Usage Examples:**

21

22

```javascript

23

// Use in arrays

24

expect(['alice', 'bob', 'charlie']).toEqual([

25

'alice',

26

expect.anything(),

27

'charlie'

28

]);

29

30

// Use in objects

31

expect({

32

name: 'John',

33

id: 123,

34

timestamp: new Date()

35

}).toEqual({

36

name: 'John',

37

id: expect.anything(),

38

timestamp: expect.anything()

39

});

40

41

// Use with function calls

42

const mockFn = jest.fn();

43

mockFn('hello', 42, true);

44

45

expect(mockFn).toHaveBeenCalledWith(

46

'hello',

47

expect.anything(),

48

expect.anything()

49

);

50

51

// Won't match null or undefined

52

expect({value: null}).not.toEqual({value: expect.anything()});

53

expect({value: undefined}).not.toEqual({value: expect.anything()});

54

```

55

56

#### expect.any

57

58

Matches any instance of the specified constructor or type.

59

60

```javascript { .api }

61

/**

62

* Matches any instance of given constructor

63

* @param constructor - Constructor function or class to match against

64

* @returns Any matcher instance

65

*/

66

expect.any(constructor: Function): Any;

67

```

68

69

**Usage Examples:**

70

71

```javascript

72

// Primitive types

73

expect('hello').toEqual(expect.any(String));

74

expect(42).toEqual(expect.any(Number));

75

expect(true).toEqual(expect.any(Boolean));

76

77

// Object types

78

expect(new Date()).toEqual(expect.any(Date));

79

expect([1, 2, 3]).toEqual(expect.any(Array));

80

expect(/regex/).toEqual(expect.any(RegExp));

81

expect(new Error('test')).toEqual(expect.any(Error));

82

83

// Custom classes

84

class User {

85

constructor(name) {

86

this.name = name;

87

}

88

}

89

90

const user = new User('John');

91

expect(user).toEqual(expect.any(User));

92

93

// Use in complex objects

94

expect({

95

user: new User('John'),

96

createdAt: new Date(),

97

tags: ['admin', 'active']

98

}).toEqual({

99

user: expect.any(User),

100

createdAt: expect.any(Date),

101

tags: expect.any(Array)

102

});

103

104

// Use with mock function verification

105

const mockCallback = jest.fn();

106

mockCallback(new Error('something failed'));

107

108

expect(mockCallback).toHaveBeenCalledWith(expect.any(Error));

109

```

110

111

### Object Matching

112

113

#### expect.objectContaining

114

115

Matches objects that contain the specified properties (subset matching).

116

117

```javascript { .api }

118

/**

119

* Matches objects containing provided properties

120

* @param object - Object with properties that should be present

121

* @returns ObjectContaining matcher instance

122

*/

123

expect.objectContaining(object: Object): ObjectContaining;

124

```

125

126

**Usage Examples:**

127

128

```javascript

129

// Basic object containment

130

const user = {

131

id: 1,

132

name: 'John',

133

email: 'john@example.com',

134

preferences: {theme: 'dark'},

135

roles: ['user', 'admin']

136

};

137

138

expect(user).toEqual(expect.objectContaining({

139

name: 'John',

140

email: 'john@example.com'

141

}));

142

143

// Nested object containment

144

expect(user).toEqual(expect.objectContaining({

145

preferences: expect.objectContaining({

146

theme: 'dark'

147

})

148

}));

149

150

// Use in arrays

151

expect([

152

{id: 1, name: 'John'},

153

{id: 2, name: 'Jane'},

154

{id: 3, name: 'Bob'}

155

]).toContainEqual(expect.objectContaining({name: 'Jane'}));

156

157

// API response testing

158

const apiResponse = {

159

data: {id: 123, name: 'John'},

160

metadata: {timestamp: '2023-01-01', version: '1.0'},

161

status: 'success'

162

};

163

164

expect(apiResponse).toEqual(expect.objectContaining({

165

data: expect.objectContaining({id: 123}),

166

status: 'success'

167

}));

168

169

// Mock function verification

170

const mockFn = jest.fn();

171

mockFn({name: 'John', age: 30, city: 'New York'});

172

173

expect(mockFn).toHaveBeenCalledWith(

174

expect.objectContaining({name: 'John', age: 30})

175

);

176

```

177

178

### Array Matching

179

180

#### expect.arrayContaining

181

182

Matches arrays that contain all of the specified elements.

183

184

```javascript { .api }

185

/**

186

* Matches arrays containing all provided elements

187

* @param array - Array with elements that should be present

188

* @returns ArrayContaining matcher instance

189

*/

190

expect.arrayContaining(array: Array): ArrayContaining;

191

```

192

193

**Usage Examples:**

194

195

```javascript

196

// Basic array containment

197

expect(['a', 'b', 'c', 'd', 'e']).toEqual(

198

expect.arrayContaining(['a', 'c', 'e'])

199

);

200

201

// Order doesn't matter

202

expect(['z', 'y', 'x']).toEqual(

203

expect.arrayContaining(['x', 'z'])

204

);

205

206

// Works with objects

207

expect([

208

{name: 'Alice', age: 25},

209

{name: 'Bob', age: 30},

210

{name: 'Charlie', age: 35}

211

]).toEqual(expect.arrayContaining([

212

{name: 'Alice', age: 25},

213

{name: 'Charlie', age: 35}

214

]));

215

216

// Nested in objects

217

expect({

218

users: ['john', 'jane', 'bob'],

219

admins: ['alice', 'charlie']

220

}).toEqual({

221

users: expect.arrayContaining(['john', 'jane']),

222

admins: expect.arrayContaining(['alice'])

223

});

224

225

// Testing API responses

226

const searchResults = {

227

results: [

228

{id: 1, title: 'First Post'},

229

{id: 2, title: 'Second Post'},

230

{id: 3, title: 'Third Post'}

231

]

232

};

233

234

expect(searchResults).toEqual({

235

results: expect.arrayContaining([

236

expect.objectContaining({title: 'First Post'}),

237

expect.objectContaining({title: 'Third Post'})

238

])

239

});

240

```

241

242

### String Matching

243

244

#### expect.stringContaining

245

246

Matches strings that contain the specified substring.

247

248

```javascript { .api }

249

/**

250

* Matches strings containing provided substring

251

* @param string - Substring that should be present

252

* @returns StringContaining matcher instance

253

*/

254

expect.stringContaining(string: string): StringContaining;

255

```

256

257

**Usage Examples:**

258

259

```javascript

260

// Basic substring matching

261

expect('Hello World').toEqual(expect.stringContaining('World'));

262

expect('JavaScript is awesome').toEqual(expect.stringContaining('Script'));

263

264

// Case sensitive

265

expect('Hello World').toEqual(expect.stringContaining('World'));

266

expect('Hello World').not.toEqual(expect.stringContaining('world'));

267

268

// Use in objects

269

expect({

270

message: 'User registration successful',

271

details: 'Account created for user@example.com'

272

}).toEqual({

273

message: expect.stringContaining('successful'),

274

details: expect.stringContaining('user@example.com')

275

});

276

277

// Use in arrays

278

expect(['error: file not found', 'warning: deprecated method']).toEqual([

279

expect.stringContaining('error:'),

280

expect.stringContaining('warning:')

281

]);

282

283

// Testing log messages

284

const logMessages = [

285

'INFO: Application started',

286

'DEBUG: Database connected',

287

'ERROR: Failed to process request'

288

];

289

290

expect(logMessages).toEqual(expect.arrayContaining([

291

expect.stringContaining('Application started'),

292

expect.stringContaining('ERROR:')

293

]));

294

```

295

296

#### expect.stringMatching

297

298

Matches strings that match the specified regular expression pattern.

299

300

```javascript { .api }

301

/**

302

* Matches strings matching provided pattern or regex

303

* @param pattern - String pattern or RegExp to match against

304

* @returns StringMatching matcher instance

305

*/

306

expect.stringMatching(pattern: string | RegExp): StringMatching;

307

```

308

309

**Usage Examples:**

310

311

```javascript

312

// Basic regex matching

313

expect('hello@example.com').toEqual(

314

expect.stringMatching(/^[\w\.-]+@[\w\.-]+\.\w+$/)

315

);

316

317

expect('2023-12-25').toEqual(

318

expect.stringMatching(/^\d{4}-\d{2}-\d{2}$/)

319

);

320

321

// String pattern matching

322

expect('user123').toEqual(expect.stringMatching('user'));

323

324

// Case insensitive matching

325

expect('JavaScript').toEqual(expect.stringMatching(/javascript/i));

326

327

// Use in complex objects

328

expect({

329

user: {

330

email: 'john.doe@company.com',

331

phone: '(555) 123-4567',

332

id: 'user_abc123'

333

}

334

}).toEqual({

335

user: {

336

email: expect.stringMatching(/@company\.com$/),

337

phone: expect.stringMatching(/^\(\d{3}\) \d{3}-\d{4}$/),

338

id: expect.stringMatching(/^user_/)

339

}

340

});

341

342

// Testing URL patterns

343

const apiUrls = [

344

'https://api.example.com/v1/users',

345

'https://api.example.com/v1/posts',

346

'https://api.example.com/v2/comments'

347

];

348

349

expect(apiUrls).toEqual(expect.arrayContaining([

350

expect.stringMatching(/\/v1\/users$/),

351

expect.stringMatching(/\/v2\//)

352

]));

353

```

354

355

## Advanced Usage Patterns

356

357

### Combining Asymmetric Matchers

358

359

```javascript

360

// Complex nested matching

361

const complexObject = {

362

user: {

363

id: 'user_123',

364

profile: {

365

name: 'John Doe',

366

email: 'john@example.com',

367

settings: {

368

notifications: true,

369

preferences: ['email', 'sms']

370

}

371

}

372

},

373

metadata: {

374

createdAt: new Date(),

375

version: '1.2.3'

376

}

377

};

378

379

expect(complexObject).toEqual({

380

user: expect.objectContaining({

381

id: expect.stringMatching(/^user_/),

382

profile: expect.objectContaining({

383

name: expect.any(String),

384

email: expect.stringContaining('@'),

385

settings: expect.objectContaining({

386

preferences: expect.arrayContaining(['email'])

387

})

388

})

389

}),

390

metadata: expect.objectContaining({

391

createdAt: expect.any(Date),

392

version: expect.stringMatching(/^\d+\.\d+\.\d+$/)

393

})

394

});

395

```

396

397

### Testing API Responses

398

399

```javascript

400

// Testing flexible API response structure

401

const apiResponse = {

402

data: [

403

{id: 1, name: 'John', email: 'john@test.com', createdAt: '2023-01-01T00:00:00Z'},

404

{id: 2, name: 'Jane', email: 'jane@test.com', createdAt: '2023-01-02T00:00:00Z'}

405

],

406

pagination: {

407

total: 2,

408

page: 1,

409

perPage: 10

410

},

411

meta: {

412

requestId: 'req_abc123',

413

timestamp: 1672531200000

414

}

415

};

416

417

expect(apiResponse).toEqual({

418

data: expect.arrayContaining([

419

expect.objectContaining({

420

id: expect.any(Number),

421

name: expect.any(String),

422

email: expect.stringMatching(/@test\.com$/),

423

createdAt: expect.stringMatching(/^\d{4}-\d{2}-\d{2}T/)

424

})

425

]),

426

pagination: expect.objectContaining({

427

total: expect.any(Number),

428

page: 1

429

}),

430

meta: expect.objectContaining({

431

requestId: expect.stringMatching(/^req_/),

432

timestamp: expect.any(Number)

433

})

434

});

435

```

436

437

### Testing Event Data

438

439

```javascript

440

// Testing event payloads with flexible structure

441

function trackEvent(eventName, properties) {

442

// Event tracking implementation

443

}

444

445

const trackEventSpy = jest.fn();

446

trackEventSpy('user_signup', {

447

userId: 'user_123',

448

email: 'user@example.com',

449

timestamp: Date.now(),

450

source: 'web',

451

properties: {

452

plan: 'premium',

453

referrer: 'google'

454

}

455

});

456

457

expect(trackEventSpy).toHaveBeenCalledWith(

458

'user_signup',

459

expect.objectContaining({

460

userId: expect.stringMatching(/^user_/),

461

email: expect.stringContaining('@'),

462

timestamp: expect.any(Number),

463

source: expect.any(String),

464

properties: expect.objectContaining({

465

plan: expect.any(String)

466

})

467

})

468

);

469

```

470

471

## Using with Regular Matchers

472

473

Asymmetric matchers can be combined with regular matchers:

474

475

```javascript

476

const mockFn = jest.fn();

477

mockFn('hello', {id: 123, name: 'John'}, ['a', 'b', 'c']);

478

479

expect(mockFn).toHaveBeenCalledWith(

480

'hello', // exact match

481

expect.objectContaining({id: 123}), // asymmetric match

482

expect.arrayContaining(['a', 'c']) // asymmetric match

483

);

484

```

485

486

## Negation Support

487

488

Asymmetric matchers support negation:

489

490

```javascript

491

expect('hello').not.toEqual(expect.stringContaining('world'));

492

expect([1, 2, 3]).not.toEqual(expect.arrayContaining([4, 5]));

493

expect({a: 1}).not.toEqual(expect.objectContaining({b: 2}));

494

```