0
# Test Utilities
1
2
Additional testing utilities including asymmetric equality testers, clock mocking, and helper functions for complex testing scenarios. These tools help handle edge cases and create more flexible test assertions.
3
4
## Capabilities
5
6
### Asymmetric Equality Testers
7
8
Special matcher objects that provide flexible matching for complex assertions.
9
10
```javascript { .api }
11
/**
12
* Match any instance of the given constructor
13
* @param constructor - Constructor function to match against
14
* @returns AsymmetricEqualityTester
15
*/
16
jasmine.any(constructor: Function): AsymmetricEqualityTester;
17
18
/**
19
* Match any non-null, non-undefined value
20
* @returns AsymmetricEqualityTester
21
*/
22
jasmine.anything(): AsymmetricEqualityTester;
23
24
/**
25
* Match objects that contain at least the provided properties
26
* @param sample - Object with properties to match
27
* @returns AsymmetricEqualityTester
28
*/
29
jasmine.objectContaining(sample: object): AsymmetricEqualityTester;
30
31
/**
32
* Match arrays that contain at least the provided elements
33
* @param sample - Array with elements to match
34
* @returns AsymmetricEqualityTester
35
*/
36
jasmine.arrayContaining(sample: any[]): AsymmetricEqualityTester;
37
38
/**
39
* Match arrays with exactly the provided contents (order independent)
40
* @param sample - Array with exact contents to match
41
* @returns AsymmetricEqualityTester
42
*/
43
jasmine.arrayWithExactContents(sample: any[]): AsymmetricEqualityTester;
44
45
/**
46
* Match Set objects that contain at least the provided values
47
* @param sample - Set with values to match
48
* @returns AsymmetricEqualityTester
49
*/
50
jasmine.setContaining(sample: Set<any>): AsymmetricEqualityTester;
51
52
/**
53
* Match Map objects that contain at least the provided key-value pairs
54
* @param sample - Map with entries to match
55
* @returns AsymmetricEqualityTester
56
*/
57
jasmine.mapContaining(sample: Map<any, any>): AsymmetricEqualityTester;
58
```
59
60
**Usage Examples:**
61
62
```javascript
63
// Match any string
64
expect('hello world').toEqual(jasmine.any(String));
65
expect(42).not.toEqual(jasmine.any(String));
66
67
// Match any number
68
expect(123).toEqual(jasmine.any(Number));
69
expect(new Date()).toEqual(jasmine.any(Date));
70
71
// Match anything non-null/undefined
72
expect('anything').toEqual(jasmine.anything());
73
expect(0).toEqual(jasmine.anything());
74
expect(false).toEqual(jasmine.anything());
75
expect(null).not.toEqual(jasmine.anything());
76
77
// Partial object matching
78
expect({
79
id: 123,
80
name: 'Alice',
81
email: 'alice@example.com',
82
metadata: { created: '2023-01-01' }
83
}).toEqual(jasmine.objectContaining({
84
name: 'Alice',
85
metadata: jasmine.objectContaining({ created: jasmine.any(String) })
86
}));
87
88
// Partial array matching
89
expect(['apple', 'banana', 'cherry', 'date']).toEqual(
90
jasmine.arrayContaining(['banana', 'cherry'])
91
);
92
93
// Exact array contents (order doesn't matter)
94
expect([3, 1, 2]).toEqual(jasmine.arrayWithExactContents([1, 2, 3]));
95
96
// Set matching
97
const userRoles = new Set(['admin', 'user', 'moderator']);
98
expect(userRoles).toEqual(jasmine.setContaining(new Set(['admin', 'user'])));
99
100
// Map matching
101
const userPrefs = new Map([
102
['theme', 'dark'],
103
['language', 'en'],
104
['notifications', true]
105
]);
106
expect(userPrefs).toEqual(jasmine.mapContaining(new Map([
107
['theme', 'dark'],
108
['notifications', jasmine.any(Boolean)]
109
])));
110
```
111
112
### String Matching Utilities
113
114
Asymmetric equality testers for string pattern matching.
115
116
```javascript { .api }
117
/**
118
* Match strings that match the given pattern
119
* @param pattern - RegExp or string pattern to match
120
* @returns AsymmetricEqualityTester
121
*/
122
jasmine.stringMatching(pattern: string | RegExp): AsymmetricEqualityTester;
123
124
/**
125
* Match strings that contain the given substring
126
* @param substring - Substring to search for
127
* @returns AsymmetricEqualityTester
128
*/
129
jasmine.stringContaining(substring: string): AsymmetricEqualityTester;
130
```
131
132
**Usage Examples:**
133
134
```javascript
135
// Pattern matching
136
expect('hello@example.com').toEqual(jasmine.stringMatching(/\S+@\S+\.\S+/));
137
expect('user123').toEqual(jasmine.stringMatching(/user\d+/));
138
expect('Product ABC-123').toEqual(jasmine.stringMatching('ABC'));
139
140
// Substring matching
141
expect('The quick brown fox').toEqual(jasmine.stringContaining('quick'));
142
expect('Error: File not found').toEqual(jasmine.stringContaining('Error:'));
143
144
// In object matching
145
expect({
146
id: 'user-456',
147
email: 'bob@company.com',
148
message: 'Welcome to our service!'
149
}).toEqual({
150
id: jasmine.stringMatching(/user-\d+/),
151
email: jasmine.stringContaining('@company.com'),
152
message: jasmine.stringContaining('Welcome')
153
});
154
```
155
156
### Truthiness and Collection Utilities
157
158
Asymmetric equality testers for common value patterns.
159
160
```javascript { .api }
161
/**
162
* Match any truthy value
163
* @returns AsymmetricEqualityTester
164
*/
165
jasmine.truthy(): AsymmetricEqualityTester;
166
167
/**
168
* Match any falsy value
169
* @returns AsymmetricEqualityTester
170
*/
171
jasmine.falsy(): AsymmetricEqualityTester;
172
173
/**
174
* Match empty collections or strings
175
* @returns AsymmetricEqualityTester
176
*/
177
jasmine.empty(): AsymmetricEqualityTester;
178
179
/**
180
* Match non-empty collections or strings
181
* @returns AsymmetricEqualityTester
182
*/
183
jasmine.notEmpty(): AsymmetricEqualityTester;
184
185
/**
186
* Match using reference equality (===)
187
* @param expected - Value to compare by reference
188
* @returns AsymmetricEqualityTester
189
*/
190
jasmine.is(expected: any): AsymmetricEqualityTester;
191
```
192
193
**Usage Examples:**
194
195
```javascript
196
// Truthiness matching
197
expect(1).toEqual(jasmine.truthy());
198
expect('hello').toEqual(jasmine.truthy());
199
expect(true).toEqual(jasmine.truthy());
200
expect(0).not.toEqual(jasmine.truthy());
201
202
expect(false).toEqual(jasmine.falsy());
203
expect(0).toEqual(jasmine.falsy());
204
expect('').toEqual(jasmine.falsy());
205
expect(null).toEqual(jasmine.falsy());
206
207
// Collection matching
208
expect([]).toEqual(jasmine.empty());
209
expect('').toEqual(jasmine.empty());
210
expect(new Set()).toEqual(jasmine.empty());
211
212
expect([1, 2, 3]).toEqual(jasmine.notEmpty());
213
expect('hello').toEqual(jasmine.notEmpty());
214
expect(new Map([['key', 'value']])).toEqual(jasmine.notEmpty());
215
216
// Reference equality
217
const obj = { name: 'test' };
218
expect(obj).toEqual(jasmine.is(obj));
219
expect({ name: 'test' }).not.toEqual(jasmine.is(obj)); // Different objects
220
```
221
222
### Clock Mocking
223
224
Functions for mocking JavaScript's timer functions and Date constructor.
225
226
```javascript { .api }
227
/**
228
* Get the mock clock instance
229
* @returns Clock instance for time manipulation
230
*/
231
jasmine.clock(): Clock;
232
233
interface Clock {
234
/**
235
* Install the mock clock, replacing native timer functions
236
*/
237
install(): void;
238
239
/**
240
* Uninstall the mock clock, restoring native timer functions
241
*/
242
uninstall(): void;
243
244
/**
245
* Advance the mock clock by the specified number of milliseconds
246
* @param milliseconds - Time to advance
247
*/
248
tick(milliseconds: number): void;
249
250
/**
251
* Set the mock current date
252
* @param date - Date to set as current time
253
*/
254
mockDate(date?: Date): void;
255
256
/**
257
* Get the current mock time
258
* @returns Current mock time as Date
259
*/
260
mockDate(): Date;
261
}
262
```
263
264
**Usage Examples:**
265
266
```javascript
267
describe('Timer functions', () => {
268
beforeEach(() => {
269
jasmine.clock().install();
270
});
271
272
afterEach(() => {
273
jasmine.clock().uninstall();
274
});
275
276
it('should handle setTimeout', () => {
277
let callback = jasmine.createSpy('callback');
278
279
setTimeout(callback, 1000);
280
expect(callback).not.toHaveBeenCalled();
281
282
jasmine.clock().tick(1000);
283
expect(callback).toHaveBeenCalled();
284
});
285
286
it('should handle setInterval', () => {
287
let callback = jasmine.createSpy('callback');
288
289
setInterval(callback, 500);
290
291
jasmine.clock().tick(1500);
292
expect(callback).toHaveBeenCalledTimes(3);
293
});
294
295
it('should mock Date', () => {
296
const mockDate = new Date(2023, 0, 1); // January 1, 2023
297
jasmine.clock().mockDate(mockDate);
298
299
expect(new Date()).toEqual(mockDate);
300
expect(Date.now()).toBe(mockDate.getTime());
301
302
// Advance time
303
jasmine.clock().tick(60000); // 1 minute
304
expect(new Date().getTime()).toBe(mockDate.getTime() + 60000);
305
});
306
307
it('should handle async operations with timers', async () => {
308
const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms));
309
310
const startTime = Date.now();
311
const promise = delay(2000).then(() => Date.now() - startTime);
312
313
jasmine.clock().tick(2000);
314
const elapsed = await promise;
315
316
expect(elapsed).toBe(2000);
317
});
318
});
319
```
320
321
### Pretty Printing Utilities
322
323
Functions for formatting objects in test output and error messages.
324
325
```javascript { .api }
326
/**
327
* Pretty print any value for display in test output
328
* @param object - Value to format
329
* @returns Formatted string representation
330
*/
331
jasmine.pp(object: any): string;
332
333
/**
334
* Check if a value is undefined
335
* @param obj - Value to check
336
* @returns Whether value is undefined
337
*/
338
jasmine.isUndefined(obj: any): boolean;
339
340
/**
341
* Create a shallow clone of an object or array
342
* @param obj - Object or array to clone
343
* @returns Shallow copy of the input
344
*/
345
jasmine.clone(obj: any): any;
346
347
/**
348
* Clone function arguments into a regular array
349
* @param args - Arguments object to clone
350
* @returns Array containing the arguments
351
*/
352
jasmine.cloneArgs(args: IArguments): any[];
353
```
354
355
**Usage Examples:**
356
357
```javascript
358
// Pretty printing for custom error messages
359
const complexObject = {
360
users: [{ name: 'Alice' }, { name: 'Bob' }],
361
settings: { theme: 'dark', notifications: true }
362
};
363
364
console.log(jasmine.pp(complexObject));
365
// Output: Object({ users: [ Object({ name: 'Alice' }), Object({ name: 'Bob' }) ], settings: Object({ theme: 'dark', notifications: true }) })
366
367
// Utility functions
368
expect(jasmine.isUndefined(undefined)).toBe(true);
369
expect(jasmine.isUndefined(null)).toBe(false);
370
371
const original = { a: 1, b: [2, 3] };
372
const cloned = jasmine.clone(original);
373
cloned.a = 99;
374
expect(original.a).toBe(1); // Original unchanged
375
376
function testFunction() {
377
const argsArray = jasmine.cloneArgs(arguments);
378
expect(Array.isArray(argsArray)).toBe(true);
379
expect(argsArray).toEqual(['arg1', 'arg2']);
380
}
381
testFunction('arg1', 'arg2');
382
```
383
384
### Utility Helper Functions
385
386
Additional utility functions for testing scenarios.
387
388
```javascript { .api }
389
/**
390
* Get property descriptor from object or its prototype chain
391
* @param obj - Object to inspect
392
* @param prop - Property name
393
* @returns Property descriptor or undefined
394
*/
395
jasmine.getPropertyDescriptor(obj: any, prop: string): PropertyDescriptor | undefined;
396
397
/**
398
* Create a matcher that always fails (useful for testing)
399
* @param message - Optional failure message
400
* @returns Failed matcher result
401
*/
402
jasmine.createSpy.isSpy(obj: any): boolean;
403
```
404
405
**Usage Examples:**
406
407
```javascript
408
// Property descriptor inspection
409
const obj = {
410
get name() { return this._name; },
411
set name(value) { this._name = value; }
412
};
413
414
const descriptor = jasmine.getPropertyDescriptor(obj, 'name');
415
expect(descriptor.get).toBeDefined();
416
expect(descriptor.set).toBeDefined();
417
418
// Spy detection
419
const regularFunction = () => {};
420
const spy = jasmine.createSpy('testSpy');
421
422
expect(jasmine.createSpy.isSpy(regularFunction)).toBe(false);
423
expect(jasmine.createSpy.isSpy(spy)).toBe(true);
424
425
// This is useful for conditional spy setup
426
function maybeSpyOn(obj, method) {
427
if (!jasmine.createSpy.isSpy(obj[method])) {
428
spyOn(obj, method);
429
}
430
}
431
```
432
433
### Error Handling Utilities
434
435
Utilities for working with errors and exceptions in tests.
436
437
```javascript { .api }
438
/**
439
* Create an error with a specific message and stack trace
440
* Used internally by Jasmine for consistent error formatting
441
*/
442
jasmine.createError(message: string, stack?: string): Error;
443
444
/**
445
* Format error messages consistently
446
* Used by matchers for error reporting
447
*/
448
jasmine.formatErrorMsg(domain: string, usage: string): (msg: string) => string;
449
```
450
451
**Usage Examples:**
452
453
```javascript
454
// In custom matchers or test utilities
455
function validateInput(input) {
456
if (!input) {
457
throw jasmine.createError('Input is required');
458
}
459
return input.toUpperCase();
460
}
461
462
// Custom matcher using error formatting
463
jasmine.addMatchers({
464
toBeValidConfig: (util) => {
465
return {
466
compare: (actual) => {
467
const formatter = jasmine.formatErrorMsg('ConfigValidator', 'toBeValidConfig()');
468
469
if (typeof actual !== 'object') {
470
return {
471
pass: false,
472
message: formatter('Expected an object')
473
};
474
}
475
476
return { pass: true };
477
}
478
};
479
}
480
});
481
```
482
483
### Debug and Development Utilities
484
485
Utilities for debugging tests and working with Jasmine's internal functionality.
486
487
```javascript { .api }
488
/**
489
* Log a debug message that will be included in spec results if the spec fails
490
* @param message - Message to log for debugging
491
*/
492
jasmine.debugLog(message: string): void;
493
494
/**
495
* Check if a function is a Jasmine spy
496
* @param putativeSpy - Function to check
497
* @returns Whether the function is a spy
498
*/
499
jasmine.isSpy(putativeSpy: any): boolean;
500
501
/**
502
* Replace global error handling with a spy for testing uncaught exceptions
503
* @param fn - Async function to run with global error spy active
504
* @returns Promise that resolves when the function completes
505
*/
506
jasmine.spyOnGlobalErrorsAsync(fn: (globalErrorSpy: Spy) => Promise<void>): Promise<void>;
507
```
508
509
**Usage Examples:**
510
511
```javascript
512
describe('Debug utilities', () => {
513
it('should log debug messages on failure', () => {
514
jasmine.debugLog('Setting up test data');
515
const testData = { id: 1, name: 'test' };
516
517
jasmine.debugLog('Performing validation');
518
expect(testData.id).toBe(2); // This will fail
519
520
// Debug messages will appear in the failure output
521
});
522
523
it('should detect spies correctly', () => {
524
const regularFunction = () => 'result';
525
const spyFunction = jasmine.createSpy('testSpy');
526
527
expect(jasmine.isSpy(regularFunction)).toBe(false);
528
expect(jasmine.isSpy(spyFunction)).toBe(true);
529
530
// Useful for conditional logic
531
if (!jasmine.isSpy(regularFunction)) {
532
console.log('This is not a spy');
533
}
534
});
535
536
it('should spy on global errors', async () => {
537
await jasmine.spyOnGlobalErrorsAsync(async (globalErrorSpy) => {
538
// Trigger an uncaught exception
539
setTimeout(() => {
540
throw new Error('Test error');
541
}, 0);
542
543
// Wait for the error to be thrown
544
await new Promise(resolve => setTimeout(resolve, 10));
545
546
// Verify the error was caught by the spy
547
expect(globalErrorSpy).toHaveBeenCalledWith(jasmine.any(Error));
548
expect(globalErrorSpy.calls.argsFor(0)[0].message).toBe('Test error');
549
});
550
});
551
});
552
```
553
554
## Types
555
556
```javascript { .api }
557
interface AsymmetricEqualityTester {
558
asymmetricMatch(other: any, customTesters: EqualityTester[]): boolean;
559
jasmineToString(): string;
560
}
561
562
interface Clock {
563
install(): void;
564
uninstall(): void;
565
tick(milliseconds: number): void;
566
mockDate(date?: Date): void | Date;
567
}
568
569
interface EqualityTester {
570
(first: any, second: any): boolean | undefined;
571
}
572
```