hermes-test 1.0.1 → 1.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/hermes-test.js +14 -14
- package/dist/harness.bundle.js +212 -98
- package/globals.d.ts +12 -9
- package/index.d.ts +33 -26
- package/package.json +4 -4
- package/src/expect.ts +202 -114
- package/src/fetch.ts +19 -5
- package/src/harness.ts +129 -33
- package/src/hooks.ts +131 -43
- package/src/index.ts +22 -14
- package/src/mock.ts +15 -11
- package/src/polyfills.js +151 -73
- package/src/render.ts +54 -32
- package/src/shims/async-storage.js +9 -9
- package/src/shims/react-i18next.js +30 -10
- package/src/shims/react-native-launch-arguments.js +3 -1
- package/src/shims/react-native.js +133 -41
- package/src/shims/react.js +3 -3
- package/src/shims/rtk-query-core.js +18 -8
- package/src/shims/rtk-query.js +18 -8
- package/src/shims/tanstack-query.js +2 -2
- package/src/spy.ts +32 -36
- package/src/store.ts +27 -17
- package/src/timers.ts +5 -3
package/src/expect.ts
CHANGED
|
@@ -6,9 +6,9 @@ const _readFile = (globalThis as any).__HT_readFile || (() => null);
|
|
|
6
6
|
const _writeFile = (globalThis as any).__HT_writeFile || (() => false);
|
|
7
7
|
|
|
8
8
|
// Snapshot state — set by the harness before each test runs
|
|
9
|
-
let _snapshotFile = '';
|
|
10
|
-
let _snapshotTestName = '';
|
|
11
|
-
let _snapshotCounter = 0;
|
|
9
|
+
let _snapshotFile = ''; // path to .snap file
|
|
10
|
+
let _snapshotTestName = ''; // current test name (used as snapshot key)
|
|
11
|
+
let _snapshotCounter = 0; // counter for multiple snapshots in one test
|
|
12
12
|
let _updateSnapshots = false;
|
|
13
13
|
|
|
14
14
|
// Cache of loaded snapshot files: path → { key → serialized value }
|
|
@@ -22,10 +22,14 @@ function _setSnapshotContext(file: string, testName: string, update: boolean) {
|
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
function _serializeSnapshot(value: any): string {
|
|
25
|
-
return JSON.stringify(
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
25
|
+
return JSON.stringify(
|
|
26
|
+
value,
|
|
27
|
+
(_key, val) => {
|
|
28
|
+
if (typeof val === 'function') return '[Function]';
|
|
29
|
+
return val;
|
|
30
|
+
},
|
|
31
|
+
2,
|
|
32
|
+
);
|
|
29
33
|
}
|
|
30
34
|
|
|
31
35
|
function _loadSnapshots(path: string): Record<string, string> {
|
|
@@ -49,7 +53,9 @@ function _saveSnapshots(path: string, data: Record<string, string>) {
|
|
|
49
53
|
}
|
|
50
54
|
|
|
51
55
|
let _totalSnapshotCount = 0;
|
|
52
|
-
export function getSnapshotCount(): number {
|
|
56
|
+
export function getSnapshotCount(): number {
|
|
57
|
+
return _totalSnapshotCount;
|
|
58
|
+
}
|
|
53
59
|
|
|
54
60
|
function _matchSnapshot(actual: any): void {
|
|
55
61
|
_snapshotCounter++;
|
|
@@ -75,16 +81,18 @@ function _matchSnapshot(actual: any): void {
|
|
|
75
81
|
if (serialized !== expected) {
|
|
76
82
|
throw new Error(
|
|
77
83
|
`Snapshot mismatch for "${key}":\n` +
|
|
78
|
-
|
|
79
|
-
|
|
84
|
+
`Expected:\n${expected}\n\nReceived:\n${serialized}\n\n` +
|
|
85
|
+
`Run with --update-snapshots to update.`,
|
|
80
86
|
);
|
|
81
87
|
}
|
|
82
88
|
}
|
|
83
89
|
|
|
84
90
|
function deepEqual(a: any, b: any): boolean {
|
|
85
91
|
// Support asymmetric matchers (expect.anything(), expect.any(), expect.objectContaining())
|
|
86
|
-
if (b != null && typeof b === 'object' && b.__htMatcher && typeof b.matches === 'function')
|
|
87
|
-
|
|
92
|
+
if (b != null && typeof b === 'object' && b.__htMatcher && typeof b.matches === 'function')
|
|
93
|
+
return b.matches(a);
|
|
94
|
+
if (a != null && typeof a === 'object' && a.__htMatcher && typeof a.matches === 'function')
|
|
95
|
+
return a.matches(b);
|
|
88
96
|
|
|
89
97
|
if (a === b) return true;
|
|
90
98
|
if (a == null || b == null) return a === b;
|
|
@@ -100,10 +108,10 @@ function deepEqual(a: any, b: any): boolean {
|
|
|
100
108
|
}
|
|
101
109
|
|
|
102
110
|
if (typeof a === 'object') {
|
|
103
|
-
const keysA = Object.keys(a).filter(
|
|
104
|
-
const keysB = Object.keys(b).filter(
|
|
111
|
+
const keysA = Object.keys(a).filter(k => a[k] !== undefined);
|
|
112
|
+
const keysB = Object.keys(b).filter(k => b[k] !== undefined);
|
|
105
113
|
if (keysA.length !== keysB.length) return false;
|
|
106
|
-
return keysA.every(
|
|
114
|
+
return keysA.every(k => deepEqual(a[k], b[k]));
|
|
107
115
|
}
|
|
108
116
|
|
|
109
117
|
return false;
|
|
@@ -135,7 +143,8 @@ function createAssertion(actual: any, negated: boolean): any {
|
|
|
135
143
|
if (!pass) {
|
|
136
144
|
let hint = '';
|
|
137
145
|
if (actual === undefined && !negated) {
|
|
138
|
-
hint =
|
|
146
|
+
hint =
|
|
147
|
+
'\n Hint: Received is undefined. This usually means the module needs to be mocked with ht.mock().';
|
|
139
148
|
}
|
|
140
149
|
throw new Error(message + hint);
|
|
141
150
|
}
|
|
@@ -146,8 +155,12 @@ function createAssertion(actual: any, negated: boolean): any {
|
|
|
146
155
|
assert(
|
|
147
156
|
actual === expected,
|
|
148
157
|
negated
|
|
149
|
-
? `expect(received).not.toBe(expected)\n\n Expected: not ${formatValue(
|
|
150
|
-
|
|
158
|
+
? `expect(received).not.toBe(expected)\n\n Expected: not ${formatValue(
|
|
159
|
+
expected,
|
|
160
|
+
)}\n Received: ${formatValue(actual)}`
|
|
161
|
+
: `expect(received).toBe(expected)\n\n Expected: ${formatValue(
|
|
162
|
+
expected,
|
|
163
|
+
)}\n Received: ${formatValue(actual)}`,
|
|
151
164
|
);
|
|
152
165
|
},
|
|
153
166
|
|
|
@@ -155,14 +168,24 @@ function createAssertion(actual: any, negated: boolean): any {
|
|
|
155
168
|
assert(
|
|
156
169
|
deepEqual(actual, expected),
|
|
157
170
|
negated
|
|
158
|
-
? `expect(received).not.toEqual(expected)\n\n Expected: not ${formatValue(
|
|
159
|
-
|
|
171
|
+
? `expect(received).not.toEqual(expected)\n\n Expected: not ${formatValue(
|
|
172
|
+
expected,
|
|
173
|
+
)}\n Received: ${formatValue(actual)}`
|
|
174
|
+
: `expect(received).toEqual(expected)\n\n Expected: ${formatValue(
|
|
175
|
+
expected,
|
|
176
|
+
)}\n Received: ${formatValue(actual)}`,
|
|
160
177
|
);
|
|
161
178
|
},
|
|
162
179
|
|
|
163
180
|
toMatchObject(expected: any) {
|
|
164
181
|
function matchesObject(a: any, b: any): boolean {
|
|
165
|
-
if (
|
|
182
|
+
if (
|
|
183
|
+
b != null &&
|
|
184
|
+
typeof b === 'object' &&
|
|
185
|
+
(b as any).__htMatcher &&
|
|
186
|
+
typeof (b as any).matches === 'function'
|
|
187
|
+
)
|
|
188
|
+
return (b as any).matches(a);
|
|
166
189
|
if (typeof b !== 'object' || b === null) return a === b;
|
|
167
190
|
if (Array.isArray(b)) {
|
|
168
191
|
if (!Array.isArray(a) || a.length < b.length) return false;
|
|
@@ -176,8 +199,12 @@ function createAssertion(actual: any, negated: boolean): any {
|
|
|
176
199
|
assert(
|
|
177
200
|
matchesObject(actual, expected),
|
|
178
201
|
negated
|
|
179
|
-
? `expect(received).not.toMatchObject(expected)\n\n Expected: not ${formatValue(
|
|
180
|
-
|
|
202
|
+
? `expect(received).not.toMatchObject(expected)\n\n Expected: not ${formatValue(
|
|
203
|
+
expected,
|
|
204
|
+
)}\n Received: ${formatValue(actual)}`
|
|
205
|
+
: `expect(received).toMatchObject(expected)\n\n Expected: ${formatValue(
|
|
206
|
+
expected,
|
|
207
|
+
)}\n Received: ${formatValue(actual)}`,
|
|
181
208
|
);
|
|
182
209
|
},
|
|
183
210
|
|
|
@@ -186,7 +213,7 @@ function createAssertion(actual: any, negated: boolean): any {
|
|
|
186
213
|
actual !== undefined,
|
|
187
214
|
negated
|
|
188
215
|
? `expect(received).not.toBeDefined()\n\n Received: ${formatValue(actual)}`
|
|
189
|
-
: `expect(received).toBeDefined()\n\n Received: undefined
|
|
216
|
+
: `expect(received).toBeDefined()\n\n Received: undefined`,
|
|
190
217
|
);
|
|
191
218
|
},
|
|
192
219
|
|
|
@@ -195,7 +222,7 @@ function createAssertion(actual: any, negated: boolean): any {
|
|
|
195
222
|
actual === undefined,
|
|
196
223
|
negated
|
|
197
224
|
? `expect(received).not.toBeUndefined()\n\n Received: ${formatValue(actual)}`
|
|
198
|
-
: `expect(received).toBeUndefined()\n\n Received: ${formatValue(actual)}
|
|
225
|
+
: `expect(received).toBeUndefined()\n\n Received: ${formatValue(actual)}`,
|
|
199
226
|
);
|
|
200
227
|
},
|
|
201
228
|
|
|
@@ -204,7 +231,7 @@ function createAssertion(actual: any, negated: boolean): any {
|
|
|
204
231
|
actual === null,
|
|
205
232
|
negated
|
|
206
233
|
? `expect(received).not.toBeNull()\n\n Received: ${formatValue(actual)}`
|
|
207
|
-
: `expect(received).toBeNull()\n\n Received: ${formatValue(actual)}
|
|
234
|
+
: `expect(received).toBeNull()\n\n Received: ${formatValue(actual)}`,
|
|
208
235
|
);
|
|
209
236
|
},
|
|
210
237
|
|
|
@@ -214,7 +241,7 @@ function createAssertion(actual: any, negated: boolean): any {
|
|
|
214
241
|
len === expected,
|
|
215
242
|
negated
|
|
216
243
|
? `expect(received).not.toHaveLength(expected)\n\n Expected: not ${expected}\n Received length: ${len}`
|
|
217
|
-
: `expect(received).toHaveLength(expected)\n\n Expected: ${expected}\n Received length: ${len}
|
|
244
|
+
: `expect(received).toHaveLength(expected)\n\n Expected: ${expected}\n Received length: ${len}`,
|
|
218
245
|
);
|
|
219
246
|
},
|
|
220
247
|
|
|
@@ -222,8 +249,12 @@ function createAssertion(actual: any, negated: boolean): any {
|
|
|
222
249
|
assert(
|
|
223
250
|
actual instanceof expected,
|
|
224
251
|
negated
|
|
225
|
-
? `expect(received).not.toBeInstanceOf(expected)\n\n Expected: not ${
|
|
226
|
-
|
|
252
|
+
? `expect(received).not.toBeInstanceOf(expected)\n\n Expected: not ${
|
|
253
|
+
expected?.name ?? expected
|
|
254
|
+
}`
|
|
255
|
+
: `expect(received).toBeInstanceOf(expected)\n\n Expected: ${
|
|
256
|
+
expected?.name ?? expected
|
|
257
|
+
}\n Received: ${formatValue(actual)}`,
|
|
227
258
|
);
|
|
228
259
|
},
|
|
229
260
|
|
|
@@ -232,7 +263,7 @@ function createAssertion(actual: any, negated: boolean): any {
|
|
|
232
263
|
!!actual,
|
|
233
264
|
negated
|
|
234
265
|
? `expect(received).not.toBeTruthy()\n\n Received: ${formatValue(actual)}`
|
|
235
|
-
: `expect(received).toBeTruthy()\n\n Received: ${formatValue(actual)}
|
|
266
|
+
: `expect(received).toBeTruthy()\n\n Received: ${formatValue(actual)}`,
|
|
236
267
|
);
|
|
237
268
|
},
|
|
238
269
|
|
|
@@ -241,7 +272,7 @@ function createAssertion(actual: any, negated: boolean): any {
|
|
|
241
272
|
!actual,
|
|
242
273
|
negated
|
|
243
274
|
? `expect(received).not.toBeFalsy()\n\n Received: ${formatValue(actual)}`
|
|
244
|
-
: `expect(received).toBeFalsy()\n\n Received: ${formatValue(actual)}
|
|
275
|
+
: `expect(received).toBeFalsy()\n\n Received: ${formatValue(actual)}`,
|
|
245
276
|
);
|
|
246
277
|
},
|
|
247
278
|
|
|
@@ -250,7 +281,7 @@ function createAssertion(actual: any, negated: boolean): any {
|
|
|
250
281
|
actual > n,
|
|
251
282
|
negated
|
|
252
283
|
? `Expected ${actual} not to be greater than ${n}`
|
|
253
|
-
: `Expected ${actual} to be greater than ${n}
|
|
284
|
+
: `Expected ${actual} to be greater than ${n}`,
|
|
254
285
|
);
|
|
255
286
|
},
|
|
256
287
|
|
|
@@ -259,7 +290,7 @@ function createAssertion(actual: any, negated: boolean): any {
|
|
|
259
290
|
actual < n,
|
|
260
291
|
negated
|
|
261
292
|
? `Expected ${actual} not to be less than ${n}`
|
|
262
|
-
: `Expected ${actual} to be less than ${n}
|
|
293
|
+
: `Expected ${actual} to be less than ${n}`,
|
|
263
294
|
);
|
|
264
295
|
},
|
|
265
296
|
|
|
@@ -267,13 +298,13 @@ function createAssertion(actual: any, negated: boolean): any {
|
|
|
267
298
|
const contains = Array.isArray(actual)
|
|
268
299
|
? actual.some((v: any) => deepEqual(v, item))
|
|
269
300
|
: typeof actual === 'string'
|
|
270
|
-
|
|
271
|
-
|
|
301
|
+
? actual.includes(item)
|
|
302
|
+
: false;
|
|
272
303
|
assert(
|
|
273
304
|
contains,
|
|
274
305
|
negated
|
|
275
306
|
? `Expected ${formatValue(actual)} not to contain ${formatValue(item)}`
|
|
276
|
-
: `Expected ${formatValue(actual)} to contain ${formatValue(item)}
|
|
307
|
+
: `Expected ${formatValue(actual)} to contain ${formatValue(item)}`,
|
|
277
308
|
);
|
|
278
309
|
},
|
|
279
310
|
|
|
@@ -283,7 +314,7 @@ function createAssertion(actual: any, negated: boolean): any {
|
|
|
283
314
|
contains,
|
|
284
315
|
negated
|
|
285
316
|
? `Expected array not to contain equal ${formatValue(item)}`
|
|
286
|
-
: `Expected array to contain equal ${formatValue(item)}, got ${formatValue(actual)}
|
|
317
|
+
: `Expected array to contain equal ${formatValue(item)}, got ${formatValue(actual)}`,
|
|
287
318
|
);
|
|
288
319
|
},
|
|
289
320
|
|
|
@@ -293,7 +324,7 @@ function createAssertion(actual: any, negated: boolean): any {
|
|
|
293
324
|
pass,
|
|
294
325
|
negated
|
|
295
326
|
? `Expected ${actual} not to be close to ${expected}`
|
|
296
|
-
: `Expected ${actual} to be close to ${expected} (precision ${precision})
|
|
327
|
+
: `Expected ${actual} to be close to ${expected} (precision ${precision})`,
|
|
297
328
|
);
|
|
298
329
|
},
|
|
299
330
|
|
|
@@ -303,7 +334,7 @@ function createAssertion(actual: any, negated: boolean): any {
|
|
|
303
334
|
regex.test(String(actual)),
|
|
304
335
|
negated
|
|
305
336
|
? `Expected ${formatValue(actual)} not to match ${pattern}`
|
|
306
|
-
: `Expected ${formatValue(actual)} to match ${pattern}
|
|
337
|
+
: `Expected ${formatValue(actual)} to match ${pattern}`,
|
|
307
338
|
);
|
|
308
339
|
},
|
|
309
340
|
|
|
@@ -322,21 +353,19 @@ function createAssertion(actual: any, negated: boolean): any {
|
|
|
322
353
|
threw,
|
|
323
354
|
negated
|
|
324
355
|
? `Expected function not to throw, but it threw ${formatValue(error)}`
|
|
325
|
-
: `Expected function to throw, but it did not
|
|
356
|
+
: `Expected function to throw, but it did not`,
|
|
326
357
|
);
|
|
327
358
|
} else {
|
|
328
359
|
const errMsg = error?.message ?? String(error ?? '');
|
|
329
360
|
const matches =
|
|
330
|
-
typeof message === 'string'
|
|
331
|
-
? errMsg.includes(message)
|
|
332
|
-
: message.test(errMsg);
|
|
361
|
+
typeof message === 'string' ? errMsg.includes(message) : message.test(errMsg);
|
|
333
362
|
assert(
|
|
334
363
|
threw && matches,
|
|
335
364
|
negated
|
|
336
365
|
? `Expected function not to throw matching ${message}`
|
|
337
366
|
: threw
|
|
338
|
-
|
|
339
|
-
|
|
367
|
+
? `Expected thrown error to match ${message}, got "${errMsg}"`
|
|
368
|
+
: `Expected function to throw, but it did not`,
|
|
340
369
|
);
|
|
341
370
|
}
|
|
342
371
|
},
|
|
@@ -346,8 +375,10 @@ function createAssertion(actual: any, negated: boolean): any {
|
|
|
346
375
|
assert(
|
|
347
376
|
(actual as Spy).callCount > 0,
|
|
348
377
|
negated
|
|
349
|
-
? `Expected spy not to have been called, but it was called ${
|
|
350
|
-
|
|
378
|
+
? `Expected spy not to have been called, but it was called ${
|
|
379
|
+
(actual as Spy).callCount
|
|
380
|
+
} times`
|
|
381
|
+
: `Expected spy to have been called, but it was never called`,
|
|
351
382
|
);
|
|
352
383
|
},
|
|
353
384
|
|
|
@@ -356,7 +387,9 @@ function createAssertion(actual: any, negated: boolean): any {
|
|
|
356
387
|
(actual as Spy).callCount === 1,
|
|
357
388
|
negated
|
|
358
389
|
? `Expected spy not to have been called once, but it was`
|
|
359
|
-
: `Expected spy to have been called once, but it was called ${
|
|
390
|
+
: `Expected spy to have been called once, but it was called ${
|
|
391
|
+
(actual as Spy).callCount
|
|
392
|
+
} times`,
|
|
360
393
|
);
|
|
361
394
|
},
|
|
362
395
|
|
|
@@ -365,7 +398,9 @@ function createAssertion(actual: any, negated: boolean): any {
|
|
|
365
398
|
(actual as Spy).callCount === n,
|
|
366
399
|
negated
|
|
367
400
|
? `Expected spy not to have been called ${n} times`
|
|
368
|
-
: `Expected spy to have been called ${n} times, but it was called ${
|
|
401
|
+
: `Expected spy to have been called ${n} times, but it was called ${
|
|
402
|
+
(actual as Spy).callCount
|
|
403
|
+
} times`,
|
|
369
404
|
);
|
|
370
405
|
},
|
|
371
406
|
|
|
@@ -376,7 +411,9 @@ function createAssertion(actual: any, negated: boolean): any {
|
|
|
376
411
|
match,
|
|
377
412
|
negated
|
|
378
413
|
? `Expected spy not to have been called with ${formatValue(args)}`
|
|
379
|
-
: `Expected spy to have been called with ${formatValue(args)}, calls: ${formatValue(
|
|
414
|
+
: `Expected spy to have been called with ${formatValue(args)}, calls: ${formatValue(
|
|
415
|
+
s.calls,
|
|
416
|
+
)}`,
|
|
380
417
|
);
|
|
381
418
|
},
|
|
382
419
|
|
|
@@ -387,7 +424,7 @@ function createAssertion(actual: any, negated: boolean): any {
|
|
|
387
424
|
deepEqual(lastCall, args),
|
|
388
425
|
negated
|
|
389
426
|
? `Expected last call not to be ${formatValue(args)}`
|
|
390
|
-
: `Expected last call to be ${formatValue(args)}, got ${formatValue(lastCall)}
|
|
427
|
+
: `Expected last call to be ${formatValue(args)}, got ${formatValue(lastCall)}`,
|
|
391
428
|
);
|
|
392
429
|
},
|
|
393
430
|
|
|
@@ -396,15 +433,25 @@ function createAssertion(actual: any, negated: boolean): any {
|
|
|
396
433
|
(actual as Spy).callCount === 0,
|
|
397
434
|
negated
|
|
398
435
|
? `Expected spy to have been called, but it was never called`
|
|
399
|
-
: `Expected spy to never have been called, but it was called ${
|
|
436
|
+
: `Expected spy to never have been called, but it was called ${
|
|
437
|
+
(actual as Spy).callCount
|
|
438
|
+
} times`,
|
|
400
439
|
);
|
|
401
440
|
},
|
|
402
441
|
|
|
403
442
|
// Jest-compatible aliases
|
|
404
|
-
toHaveBeenCalled() {
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
443
|
+
toHaveBeenCalled() {
|
|
444
|
+
return this.wasCalled();
|
|
445
|
+
},
|
|
446
|
+
toHaveBeenCalledTimes(n: number) {
|
|
447
|
+
return this.wasCalledTimes(n);
|
|
448
|
+
},
|
|
449
|
+
toHaveBeenCalledWith(...args: any[]) {
|
|
450
|
+
return this.wasCalledWith(...args);
|
|
451
|
+
},
|
|
452
|
+
toHaveBeenLastCalledWith(...args: any[]) {
|
|
453
|
+
return this.wasLastCalledWith(...args);
|
|
454
|
+
},
|
|
408
455
|
|
|
409
456
|
// --- Element matchers (for render() HTNode results) ---
|
|
410
457
|
|
|
@@ -415,20 +462,21 @@ function createAssertion(actual: any, negated: boolean): any {
|
|
|
415
462
|
isNode && el.type !== '__ROOT__',
|
|
416
463
|
negated
|
|
417
464
|
? `Expected element not to be rendered`
|
|
418
|
-
: `Expected element to be rendered, got ${formatValue(el)}
|
|
465
|
+
: `Expected element to be rendered, got ${formatValue(el)}`,
|
|
419
466
|
);
|
|
420
467
|
},
|
|
421
468
|
|
|
422
469
|
toHaveTextContent(expected: string | RegExp) {
|
|
423
470
|
const text = _getTextContent(actual);
|
|
424
|
-
const matches =
|
|
425
|
-
|
|
426
|
-
|
|
471
|
+
const matches =
|
|
472
|
+
typeof expected === 'string'
|
|
473
|
+
? text === expected || text.includes(expected)
|
|
474
|
+
: expected.test(text);
|
|
427
475
|
assert(
|
|
428
476
|
matches,
|
|
429
477
|
negated
|
|
430
478
|
? `Expected element not to have text content "${expected}", but it does`
|
|
431
|
-
: `Expected text content "${expected}", got "${text}"
|
|
479
|
+
: `Expected text content "${expected}", got "${text}"`,
|
|
432
480
|
);
|
|
433
481
|
},
|
|
434
482
|
|
|
@@ -442,7 +490,7 @@ function createAssertion(actual: any, negated: boolean): any {
|
|
|
442
490
|
_contains(actual, child),
|
|
443
491
|
negated
|
|
444
492
|
? `Expected element not to contain the given child`
|
|
445
|
-
: `Expected element to contain the given child
|
|
493
|
+
: `Expected element to contain the given child`,
|
|
446
494
|
);
|
|
447
495
|
},
|
|
448
496
|
|
|
@@ -452,7 +500,7 @@ function createAssertion(actual: any, negated: boolean): any {
|
|
|
452
500
|
empty,
|
|
453
501
|
negated
|
|
454
502
|
? `Expected element not to be empty, but it has no children`
|
|
455
|
-
: `Expected element to be empty, but it has ${actual?.children?.length} children
|
|
503
|
+
: `Expected element to be empty, but it has ${actual?.children?.length} children`,
|
|
456
504
|
);
|
|
457
505
|
},
|
|
458
506
|
|
|
@@ -463,7 +511,7 @@ function createAssertion(actual: any, negated: boolean): any {
|
|
|
463
511
|
matches,
|
|
464
512
|
negated
|
|
465
513
|
? `Expected display value not to be "${expected}"`
|
|
466
|
-
: `Expected display value "${expected}", got "${value}"
|
|
514
|
+
: `Expected display value "${expected}", got "${value}"`,
|
|
467
515
|
);
|
|
468
516
|
},
|
|
469
517
|
|
|
@@ -474,7 +522,7 @@ function createAssertion(actual: any, negated: boolean): any {
|
|
|
474
522
|
hasProp,
|
|
475
523
|
negated
|
|
476
524
|
? `Expected element not to have prop "${name}"`
|
|
477
|
-
: `Expected element to have prop "${name}"
|
|
525
|
+
: `Expected element to have prop "${name}"`,
|
|
478
526
|
);
|
|
479
527
|
} else {
|
|
480
528
|
const propVal = actual?.props?.[name];
|
|
@@ -482,7 +530,7 @@ function createAssertion(actual: any, negated: boolean): any {
|
|
|
482
530
|
hasProp && deepEqual(propVal, value),
|
|
483
531
|
negated
|
|
484
532
|
? `Expected prop "${name}" not to be ${formatValue(value)}`
|
|
485
|
-
: `Expected prop "${name}" to be ${formatValue(value)}, got ${formatValue(propVal)}
|
|
533
|
+
: `Expected prop "${name}" to be ${formatValue(value)}, got ${formatValue(propVal)}`,
|
|
486
534
|
);
|
|
487
535
|
}
|
|
488
536
|
},
|
|
@@ -495,41 +543,43 @@ function createAssertion(actual: any, negated: boolean): any {
|
|
|
495
543
|
for (const s of styles) {
|
|
496
544
|
if (s && typeof s === 'object') Object.assign(flat, s);
|
|
497
545
|
}
|
|
498
|
-
const allMatch = Object.keys(expected).every(
|
|
546
|
+
const allMatch = Object.keys(expected).every(k => deepEqual(flat[k], expected[k]));
|
|
499
547
|
const mismatches = Object.keys(expected)
|
|
500
|
-
.filter(
|
|
501
|
-
.map(
|
|
548
|
+
.filter(k => !deepEqual(flat[k], expected[k]))
|
|
549
|
+
.map(k => `${k}: expected ${formatValue(expected[k])}, got ${formatValue(flat[k])}`);
|
|
502
550
|
assert(
|
|
503
551
|
allMatch,
|
|
504
552
|
negated
|
|
505
553
|
? `Expected element not to have styles ${formatValue(expected)}`
|
|
506
|
-
: `Style mismatch: ${mismatches.join('; ')}
|
|
554
|
+
: `Style mismatch: ${mismatches.join('; ')}`,
|
|
507
555
|
);
|
|
508
556
|
},
|
|
509
557
|
|
|
510
558
|
toBeEnabled() {
|
|
511
|
-
const disabled =
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
559
|
+
const disabled =
|
|
560
|
+
actual?.props?.disabled === true ||
|
|
561
|
+
actual?.props?.editable === false ||
|
|
562
|
+
actual?.props?.accessibilityState?.disabled === true ||
|
|
563
|
+
actual?.props?.['aria-disabled'] === true;
|
|
515
564
|
assert(
|
|
516
565
|
!disabled,
|
|
517
566
|
negated
|
|
518
567
|
? `Expected element to be disabled, but it is enabled`
|
|
519
|
-
: `Expected element to be enabled, but it is disabled
|
|
568
|
+
: `Expected element to be enabled, but it is disabled`,
|
|
520
569
|
);
|
|
521
570
|
},
|
|
522
571
|
|
|
523
572
|
toBeDisabled() {
|
|
524
|
-
const disabled =
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
573
|
+
const disabled =
|
|
574
|
+
actual?.props?.disabled === true ||
|
|
575
|
+
actual?.props?.editable === false ||
|
|
576
|
+
actual?.props?.accessibilityState?.disabled === true ||
|
|
577
|
+
actual?.props?.['aria-disabled'] === true;
|
|
528
578
|
assert(
|
|
529
579
|
disabled,
|
|
530
580
|
negated
|
|
531
581
|
? `Expected element not to be disabled, but it is`
|
|
532
|
-
: `Expected element to be disabled, but it is enabled
|
|
582
|
+
: `Expected element to be disabled, but it is enabled`,
|
|
533
583
|
);
|
|
534
584
|
},
|
|
535
585
|
|
|
@@ -540,14 +590,16 @@ function createAssertion(actual: any, negated: boolean): any {
|
|
|
540
590
|
for (const s of styles) {
|
|
541
591
|
if (s && typeof s === 'object') Object.assign(flat, s);
|
|
542
592
|
}
|
|
543
|
-
const hidden =
|
|
544
|
-
|
|
545
|
-
|
|
593
|
+
const hidden =
|
|
594
|
+
flat.display === 'none' ||
|
|
595
|
+
flat.opacity === 0 ||
|
|
596
|
+
actual?.props?.accessibilityElementsHidden === true ||
|
|
597
|
+
actual?.props?.importantForAccessibility === 'no-hide-descendants';
|
|
546
598
|
assert(
|
|
547
599
|
!hidden,
|
|
548
600
|
negated
|
|
549
601
|
? `Expected element not to be visible`
|
|
550
|
-
: `Expected element to be visible, but it is hidden
|
|
602
|
+
: `Expected element to be visible, but it is hidden`,
|
|
551
603
|
);
|
|
552
604
|
},
|
|
553
605
|
|
|
@@ -576,19 +628,50 @@ export function expect(actual: any): any {
|
|
|
576
628
|
|
|
577
629
|
// resolves / rejects for promise assertions
|
|
578
630
|
base.resolves = {
|
|
579
|
-
toBeUndefined: async () => {
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
631
|
+
toBeUndefined: async () => {
|
|
632
|
+
const r = await actual;
|
|
633
|
+
if (r !== undefined) throw new Error(`Expected undefined, got ${formatValue(r)}`);
|
|
634
|
+
},
|
|
635
|
+
toBe: async (expected: any) => {
|
|
636
|
+
const r = await actual;
|
|
637
|
+
if (r !== expected)
|
|
638
|
+
throw new Error(`Expected ${formatValue(expected)}, got ${formatValue(r)}`);
|
|
639
|
+
},
|
|
640
|
+
toEqual: async (expected: any) => {
|
|
641
|
+
const r = await actual;
|
|
642
|
+
if (!deepEqual(r, expected))
|
|
643
|
+
throw new Error(`Expected deep equal to ${formatValue(expected)}, got ${formatValue(r)}`);
|
|
644
|
+
},
|
|
645
|
+
toBeDefined: async () => {
|
|
646
|
+
const r = await actual;
|
|
647
|
+
if (r === undefined) throw new Error(`Expected value to be defined`);
|
|
648
|
+
},
|
|
649
|
+
toBeTruthy: async () => {
|
|
650
|
+
const r = await actual;
|
|
651
|
+
if (!r) throw new Error(`Expected truthy, got ${formatValue(r)}`);
|
|
652
|
+
},
|
|
653
|
+
toBeFalsy: async () => {
|
|
654
|
+
const r = await actual;
|
|
655
|
+
if (r) throw new Error(`Expected falsy, got ${formatValue(r)}`);
|
|
656
|
+
},
|
|
657
|
+
toBeNull: async () => {
|
|
658
|
+
const r = await actual;
|
|
659
|
+
if (r !== null) throw new Error(`Expected null, got ${formatValue(r)}`);
|
|
660
|
+
},
|
|
586
661
|
};
|
|
587
662
|
|
|
588
663
|
base.rejects = {
|
|
589
664
|
toThrow: async (msg?: string | RegExp) => {
|
|
590
|
-
try {
|
|
591
|
-
|
|
665
|
+
try {
|
|
666
|
+
await actual;
|
|
667
|
+
throw new Error('Expected promise to reject');
|
|
668
|
+
} catch (e: any) {
|
|
669
|
+
if (msg) {
|
|
670
|
+
const m = e?.message ?? String(e);
|
|
671
|
+
const ok = typeof msg === 'string' ? m.includes(msg) : msg.test(m);
|
|
672
|
+
if (!ok) throw new Error(`Expected rejection matching ${msg}, got "${m}"`);
|
|
673
|
+
}
|
|
674
|
+
}
|
|
592
675
|
},
|
|
593
676
|
};
|
|
594
677
|
|
|
@@ -596,26 +679,31 @@ export function expect(actual: any): any {
|
|
|
596
679
|
}
|
|
597
680
|
|
|
598
681
|
// Static matchers on expect
|
|
599
|
-
expect.anything = () => makeMatcher(
|
|
600
|
-
expect.any = (ctor: any) =>
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
682
|
+
expect.anything = () => makeMatcher(v => v !== null && v !== undefined);
|
|
683
|
+
expect.any = (ctor: any) =>
|
|
684
|
+
makeMatcher(v => {
|
|
685
|
+
if (ctor === String) return typeof v === 'string';
|
|
686
|
+
if (ctor === Number) return typeof v === 'number';
|
|
687
|
+
if (ctor === Boolean) return typeof v === 'boolean';
|
|
688
|
+
if (ctor === Function) return typeof v === 'function';
|
|
689
|
+
return v instanceof ctor;
|
|
690
|
+
});
|
|
691
|
+
expect.objectContaining = (subset: Record<string, any>) =>
|
|
692
|
+
makeMatcher(v => {
|
|
693
|
+
if (typeof v !== 'object' || v === null) return false;
|
|
694
|
+
return Object.keys(subset).every(k => deepEqual(v[k], subset[k]));
|
|
695
|
+
});
|
|
696
|
+
expect.arrayContaining = (expected: any[]) =>
|
|
697
|
+
makeMatcher(v => {
|
|
698
|
+
if (!Array.isArray(v)) return false;
|
|
699
|
+
return expected.every(e => v.some((item: any) => deepEqual(item, e)));
|
|
700
|
+
});
|
|
701
|
+
expect.stringContaining = (substr: string) =>
|
|
702
|
+
makeMatcher(v => typeof v === 'string' && v.includes(substr));
|
|
703
|
+
expect.stringMatching = (pattern: RegExp | string) =>
|
|
704
|
+
makeMatcher(v => {
|
|
705
|
+
const re = typeof pattern === 'string' ? new RegExp(pattern) : pattern;
|
|
706
|
+
return typeof v === 'string' && re.test(v);
|
|
707
|
+
});
|
|
620
708
|
|
|
621
709
|
export { _setSnapshotContext };
|