as-test 1.2.0 → 1.4.0
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/CHANGELOG.md +60 -0
- package/README.md +1 -4
- package/as-test.config.schema.json +15 -0
- package/assembly/coverage.ts +22 -26
- package/assembly/index.ts +68 -47
- package/assembly/src/expectation.ts +154 -123
- package/assembly/src/fuzz.ts +10 -10
- package/assembly/src/log.ts +3 -3
- package/assembly/src/mode.ts +55 -0
- package/assembly/src/reflect.ts +122 -0
- package/assembly/src/stringify.ts +240 -0
- package/assembly/src/suite.ts +48 -27
- package/assembly/src/tests.ts +7 -7
- package/assembly/util/wipc.ts +2 -2
- package/bin/build-worker-pool.js +9 -0
- package/bin/build-worker.js +27 -3
- package/bin/commands/build-core.js +293 -86
- package/bin/commands/build.js +3 -1
- package/bin/commands/init-core.js +253 -8
- package/bin/commands/run-core.js +165 -41
- package/bin/commands/run.js +2 -1
- package/bin/commands/test.js +3 -2
- package/bin/dependency-graph.js +0 -0
- package/bin/index.js +592 -97
- package/bin/reporters/default.js +34 -0
- package/bin/types.js +7 -0
- package/bin/util.js +52 -0
- package/package.json +4 -8
- package/transform/lib/equals.js +388 -0
- package/transform/lib/index.js +28 -0
- package/transform/lib/log.js +3 -7
- package/transform/lib/types.js +4 -2
- package/transform/lib/transform.js +0 -502
|
@@ -1,15 +1,39 @@
|
|
|
1
1
|
import { visualize } from "../util/helpers";
|
|
2
2
|
import { Tests } from "./tests";
|
|
3
|
-
import { JSON } from "json-as/assembly";
|
|
4
3
|
import { namedSnapshotKey, nextUnnamedSnapshotKey } from "..";
|
|
5
4
|
import {
|
|
6
5
|
sendAssertionFailure,
|
|
7
6
|
sendWarning,
|
|
8
7
|
snapshotAssert,
|
|
9
8
|
} from "../util/wipc";
|
|
10
|
-
import {
|
|
9
|
+
import { reflectEquals } from "./reflect";
|
|
10
|
+
import { stringify, escape } from "./stringify";
|
|
11
11
|
|
|
12
12
|
let warnedToThrowDisabled = false;
|
|
13
|
+
let warnedSafeStringifyMissing = false;
|
|
14
|
+
|
|
15
|
+
function safeStringify<T>(value: T): string {
|
|
16
|
+
if (
|
|
17
|
+
isManaged<T>() &&
|
|
18
|
+
!warnedSafeStringifyMissing &&
|
|
19
|
+
changetype<usize>(value) != 0 &&
|
|
20
|
+
!isString<T>() &&
|
|
21
|
+
!isArray<T>()
|
|
22
|
+
) {
|
|
23
|
+
// @ts-expect-error: optional user-supplied serializer
|
|
24
|
+
if (!isDefined(value.toJSON)) {
|
|
25
|
+
sendWarning(
|
|
26
|
+
"Class " +
|
|
27
|
+
nameof<T>() +
|
|
28
|
+
" has no toJSON(): string method. Report values render as a `<" +
|
|
29
|
+
nameof<T>() +
|
|
30
|
+
">` placeholder. Add toJSON() returning a JSON string to serialize.",
|
|
31
|
+
);
|
|
32
|
+
warnedSafeStringifyMissing = true;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return stringify<T>(value);
|
|
36
|
+
}
|
|
13
37
|
|
|
14
38
|
export class Expectation<T> extends Tests {
|
|
15
39
|
public verdict: string = "none";
|
|
@@ -18,13 +42,11 @@ export class Expectation<T> extends Tests {
|
|
|
18
42
|
|
|
19
43
|
private _left: T;
|
|
20
44
|
|
|
21
|
-
// @ts-
|
|
45
|
+
// @ts-expect-error: used internally
|
|
22
46
|
private _right: u64 = 0;
|
|
23
47
|
|
|
24
|
-
// @ts-ignore
|
|
25
48
|
private _not: boolean = false;
|
|
26
49
|
|
|
27
|
-
// @ts-ignore
|
|
28
50
|
private _skip: boolean = false;
|
|
29
51
|
|
|
30
52
|
private _message: string = "";
|
|
@@ -57,6 +79,41 @@ export class Expectation<T> extends Tests {
|
|
|
57
79
|
return this;
|
|
58
80
|
}
|
|
59
81
|
|
|
82
|
+
/**
|
|
83
|
+
* Asserts that a custom predicate holds. Accepts either a bool or a
|
|
84
|
+
* `() => bool` lambda. Useful when the verdict isn't expressible via the
|
|
85
|
+
* built-in matchers — e.g. delegating to a hand-written comparator.
|
|
86
|
+
*
|
|
87
|
+
* expect(x).where(x > 0 && x < 10);
|
|
88
|
+
* expect(actual).where((): bool => deepEqual(GLOBAL_A, GLOBAL_B));
|
|
89
|
+
*
|
|
90
|
+
* Chains with other matchers as an independent assertion:
|
|
91
|
+
*
|
|
92
|
+
* expect(7).toBe(7).where((): bool => isFresh());
|
|
93
|
+
*
|
|
94
|
+
* Note: AssemblyScript does not implement closures, so the lambda cannot
|
|
95
|
+
* capture local variables from the enclosing scope. Use the bool form when
|
|
96
|
+
* the predicate references locals, or refer to module-level values from
|
|
97
|
+
* inside the lambda.
|
|
98
|
+
*/
|
|
99
|
+
where<W>(predicate: W, message: string = ""): Expectation<T> {
|
|
100
|
+
let passed: bool;
|
|
101
|
+
if (isFunction<W>()) {
|
|
102
|
+
passed = (predicate as () => bool)();
|
|
103
|
+
} else {
|
|
104
|
+
// @ts-ignore: W is a bool-compatible primitive in this branch
|
|
105
|
+
passed = predicate as bool;
|
|
106
|
+
}
|
|
107
|
+
this._resolve(
|
|
108
|
+
passed,
|
|
109
|
+
"where",
|
|
110
|
+
q(passed ? "true" : "false"),
|
|
111
|
+
q("true"),
|
|
112
|
+
message,
|
|
113
|
+
);
|
|
114
|
+
return this;
|
|
115
|
+
}
|
|
116
|
+
|
|
60
117
|
private _resolve(
|
|
61
118
|
passed: bool,
|
|
62
119
|
instr: string,
|
|
@@ -74,14 +131,26 @@ export class Expectation<T> extends Tests {
|
|
|
74
131
|
return;
|
|
75
132
|
}
|
|
76
133
|
const isFail = this._not ? passed : !passed;
|
|
77
|
-
this.verdict = isFail ? "fail" : "ok";
|
|
78
|
-
this.instr = instr;
|
|
79
|
-
this.left = left;
|
|
80
|
-
this.right = right;
|
|
81
134
|
const resolvedMessage = message.length ? message : this._message;
|
|
82
|
-
|
|
135
|
+
// When matchers chain, later ones must not overwrite an earlier failure's
|
|
136
|
+
// recorded state — otherwise a passing matcher after a failed one would
|
|
137
|
+
// flip the suite's verdict back to "ok". Each matcher still fires its own
|
|
138
|
+
// IPC failure independently below.
|
|
139
|
+
if (this.verdict != "fail") {
|
|
140
|
+
this.verdict = isFail ? "fail" : "ok";
|
|
141
|
+
this.instr = instr;
|
|
142
|
+
this.left = left;
|
|
143
|
+
this.right = right;
|
|
144
|
+
this.message = isFail ? resolvedMessage : "";
|
|
145
|
+
}
|
|
83
146
|
if (isFail) {
|
|
84
|
-
sendAssertionFailure(
|
|
147
|
+
sendAssertionFailure(
|
|
148
|
+
this._snapshotKey,
|
|
149
|
+
instr,
|
|
150
|
+
left,
|
|
151
|
+
right,
|
|
152
|
+
resolvedMessage,
|
|
153
|
+
);
|
|
85
154
|
// @ts-ignore
|
|
86
155
|
if (isDefined(AS_TEST_FUZZ)) {
|
|
87
156
|
// @ts-ignore
|
|
@@ -95,7 +164,7 @@ export class Expectation<T> extends Tests {
|
|
|
95
164
|
// @ts-ignore
|
|
96
165
|
__as_test_fuzz_failure_right = right;
|
|
97
166
|
// @ts-ignore
|
|
98
|
-
__as_test_fuzz_failure_message =
|
|
167
|
+
__as_test_fuzz_failure_message = resolvedMessage;
|
|
99
168
|
}
|
|
100
169
|
}
|
|
101
170
|
}
|
|
@@ -105,7 +174,7 @@ export class Expectation<T> extends Tests {
|
|
|
105
174
|
/**
|
|
106
175
|
* Tests if a == null
|
|
107
176
|
*/
|
|
108
|
-
toBeNull(message: string = ""):
|
|
177
|
+
toBeNull(message: string = ""): Expectation<T> {
|
|
109
178
|
const passed =
|
|
110
179
|
(isNullable<T>() && changetype<usize>(this._left) == 0) ||
|
|
111
180
|
(isInteger<T>() && nameof<T>() == "usize" && this._left == 0);
|
|
@@ -121,12 +190,13 @@ export class Expectation<T> extends Tests {
|
|
|
121
190
|
),
|
|
122
191
|
message,
|
|
123
192
|
);
|
|
193
|
+
return this;
|
|
124
194
|
}
|
|
125
195
|
|
|
126
196
|
/**
|
|
127
197
|
* Tests if a > b
|
|
128
198
|
*/
|
|
129
|
-
toBeGreaterThan(value: T, message: string = ""):
|
|
199
|
+
toBeGreaterThan(value: T, message: string = ""): Expectation<T> {
|
|
130
200
|
if (!isInteger<T>() && !isFloat<T>())
|
|
131
201
|
ERROR("toBeGreaterThan() can only be used on number types!");
|
|
132
202
|
|
|
@@ -144,12 +214,13 @@ export class Expectation<T> extends Tests {
|
|
|
144
214
|
),
|
|
145
215
|
message,
|
|
146
216
|
);
|
|
217
|
+
return this;
|
|
147
218
|
}
|
|
148
219
|
|
|
149
220
|
/**
|
|
150
221
|
* Tests if a >= b
|
|
151
222
|
*/
|
|
152
|
-
toBeGreaterOrEqualTo(value: T, message: string = ""):
|
|
223
|
+
toBeGreaterOrEqualTo(value: T, message: string = ""): Expectation<T> {
|
|
153
224
|
if (!isInteger<T>() && !isFloat<T>())
|
|
154
225
|
ERROR("toBeGreaterOrEqualTo() can only be used on number types!");
|
|
155
226
|
|
|
@@ -167,12 +238,13 @@ export class Expectation<T> extends Tests {
|
|
|
167
238
|
),
|
|
168
239
|
message,
|
|
169
240
|
);
|
|
241
|
+
return this;
|
|
170
242
|
}
|
|
171
243
|
|
|
172
244
|
/**
|
|
173
245
|
* Tests if a < b
|
|
174
246
|
*/
|
|
175
|
-
toBeLessThan(value: T, message: string = ""):
|
|
247
|
+
toBeLessThan(value: T, message: string = ""): Expectation<T> {
|
|
176
248
|
if (!isInteger<T>() && !isFloat<T>())
|
|
177
249
|
ERROR("toBeLessThan() can only be used on number types!");
|
|
178
250
|
|
|
@@ -190,12 +262,13 @@ export class Expectation<T> extends Tests {
|
|
|
190
262
|
),
|
|
191
263
|
message,
|
|
192
264
|
);
|
|
265
|
+
return this;
|
|
193
266
|
}
|
|
194
267
|
|
|
195
268
|
/**
|
|
196
269
|
* Tests if a <= b
|
|
197
270
|
*/
|
|
198
|
-
toBeLessThanOrEqualTo(value: T, message: string = ""):
|
|
271
|
+
toBeLessThanOrEqualTo(value: T, message: string = ""): Expectation<T> {
|
|
199
272
|
if (!isInteger<T>() && !isFloat<T>())
|
|
200
273
|
ERROR("toBeLessThanOrEqualTo() can only be used on number types!");
|
|
201
274
|
|
|
@@ -213,12 +286,13 @@ export class Expectation<T> extends Tests {
|
|
|
213
286
|
),
|
|
214
287
|
message,
|
|
215
288
|
);
|
|
289
|
+
return this;
|
|
216
290
|
}
|
|
217
291
|
|
|
218
292
|
/**
|
|
219
293
|
* Tests if a is string
|
|
220
294
|
*/
|
|
221
|
-
toBeString(message: string = ""):
|
|
295
|
+
toBeString(message: string = ""): Expectation<T> {
|
|
222
296
|
this._resolve(
|
|
223
297
|
isString<T>(),
|
|
224
298
|
"toBeString",
|
|
@@ -226,12 +300,13 @@ export class Expectation<T> extends Tests {
|
|
|
226
300
|
q("string"),
|
|
227
301
|
message,
|
|
228
302
|
);
|
|
303
|
+
return this;
|
|
229
304
|
}
|
|
230
305
|
|
|
231
306
|
/**
|
|
232
307
|
* Tests if a is boolean
|
|
233
308
|
*/
|
|
234
|
-
toBeBoolean(message: string = ""):
|
|
309
|
+
toBeBoolean(message: string = ""): Expectation<T> {
|
|
235
310
|
this._resolve(
|
|
236
311
|
isBoolean<T>(),
|
|
237
312
|
"toBeBoolean",
|
|
@@ -239,12 +314,13 @@ export class Expectation<T> extends Tests {
|
|
|
239
314
|
q("boolean"),
|
|
240
315
|
message,
|
|
241
316
|
);
|
|
317
|
+
return this;
|
|
242
318
|
}
|
|
243
319
|
|
|
244
320
|
/**
|
|
245
321
|
* Tests if a is array
|
|
246
322
|
*/
|
|
247
|
-
toBeArray(message: string = ""):
|
|
323
|
+
toBeArray(message: string = ""): Expectation<T> {
|
|
248
324
|
this._resolve(
|
|
249
325
|
isArray<T>(),
|
|
250
326
|
"toBeArray",
|
|
@@ -252,12 +328,13 @@ export class Expectation<T> extends Tests {
|
|
|
252
328
|
q("Array<any>"),
|
|
253
329
|
message,
|
|
254
330
|
);
|
|
331
|
+
return this;
|
|
255
332
|
}
|
|
256
333
|
|
|
257
334
|
/**
|
|
258
335
|
* Tests if a is number
|
|
259
336
|
*/
|
|
260
|
-
toBeNumber(message: string = ""):
|
|
337
|
+
toBeNumber(message: string = ""): Expectation<T> {
|
|
261
338
|
this._resolve(
|
|
262
339
|
isFloat<T>() || isInteger<T>(),
|
|
263
340
|
"toBeNumber",
|
|
@@ -265,12 +342,13 @@ export class Expectation<T> extends Tests {
|
|
|
265
342
|
q("number"),
|
|
266
343
|
message,
|
|
267
344
|
);
|
|
345
|
+
return this;
|
|
268
346
|
}
|
|
269
347
|
|
|
270
348
|
/**
|
|
271
349
|
* Tests if a is integer
|
|
272
350
|
*/
|
|
273
|
-
toBeInteger(message: string = ""):
|
|
351
|
+
toBeInteger(message: string = ""): Expectation<T> {
|
|
274
352
|
this._resolve(
|
|
275
353
|
isInteger<T>(),
|
|
276
354
|
"toBeInteger",
|
|
@@ -278,12 +356,13 @@ export class Expectation<T> extends Tests {
|
|
|
278
356
|
q("integer"),
|
|
279
357
|
message,
|
|
280
358
|
);
|
|
359
|
+
return this;
|
|
281
360
|
}
|
|
282
361
|
|
|
283
362
|
/**
|
|
284
363
|
* Tests if a is float
|
|
285
364
|
*/
|
|
286
|
-
toBeFloat(message: string = ""):
|
|
365
|
+
toBeFloat(message: string = ""): Expectation<T> {
|
|
287
366
|
this._resolve(
|
|
288
367
|
isFloat<T>(),
|
|
289
368
|
"toBeFloat",
|
|
@@ -291,21 +370,23 @@ export class Expectation<T> extends Tests {
|
|
|
291
370
|
q("float"),
|
|
292
371
|
message,
|
|
293
372
|
);
|
|
373
|
+
return this;
|
|
294
374
|
}
|
|
295
375
|
|
|
296
376
|
/**
|
|
297
377
|
* Tests if a is finite
|
|
298
378
|
*/
|
|
299
|
-
toBeFinite(message: string = ""):
|
|
379
|
+
toBeFinite(message: string = ""): Expectation<T> {
|
|
300
380
|
// @ts-ignore
|
|
301
381
|
const passed = (isFloat<T>() || isInteger<T>()) && isFinite(this._left);
|
|
302
382
|
this._resolve(passed, "toBeFinite", q("Infinity"), q("Finite"), message);
|
|
383
|
+
return this;
|
|
303
384
|
}
|
|
304
385
|
|
|
305
386
|
/**
|
|
306
387
|
* Tests if a value is truthy
|
|
307
388
|
*/
|
|
308
|
-
toBeTruthy(message: string = ""):
|
|
389
|
+
toBeTruthy(message: string = ""): Expectation<T> {
|
|
309
390
|
this._resolve(
|
|
310
391
|
isTruthy<T>(this._left),
|
|
311
392
|
"toBeTruthy",
|
|
@@ -313,12 +394,13 @@ export class Expectation<T> extends Tests {
|
|
|
313
394
|
q("truthy"),
|
|
314
395
|
message,
|
|
315
396
|
);
|
|
397
|
+
return this;
|
|
316
398
|
}
|
|
317
399
|
|
|
318
400
|
/**
|
|
319
401
|
* Tests if a value is falsy
|
|
320
402
|
*/
|
|
321
|
-
toBeFalsy(message: string = ""):
|
|
403
|
+
toBeFalsy(message: string = ""): Expectation<T> {
|
|
322
404
|
this._resolve(
|
|
323
405
|
!isTruthy<T>(this._left),
|
|
324
406
|
"toBeFalsy",
|
|
@@ -326,12 +408,14 @@ export class Expectation<T> extends Tests {
|
|
|
326
408
|
q("falsy"),
|
|
327
409
|
message,
|
|
328
410
|
);
|
|
411
|
+
return this;
|
|
329
412
|
}
|
|
330
413
|
|
|
331
414
|
/**
|
|
332
415
|
* Tests if a floating-point number is close to expected
|
|
333
416
|
*/
|
|
334
|
-
|
|
417
|
+
// prettier-ignore
|
|
418
|
+
toBeCloseTo(expected: T, precision: i32 = 2, message: string = ""): Expectation<T> {
|
|
335
419
|
if (!isFloat<T>() && !isInteger<T>())
|
|
336
420
|
ERROR("toBeCloseTo() can only be used on number types!");
|
|
337
421
|
const factor = Math.pow(10, precision as f64);
|
|
@@ -344,12 +428,13 @@ export class Expectation<T> extends Tests {
|
|
|
344
428
|
visualize<T>(expected),
|
|
345
429
|
message,
|
|
346
430
|
);
|
|
431
|
+
return this;
|
|
347
432
|
}
|
|
348
433
|
|
|
349
434
|
/**
|
|
350
435
|
* Tests if a string contains substring
|
|
351
436
|
*/
|
|
352
|
-
toMatch(value: string, message: string = ""):
|
|
437
|
+
toMatch(value: string, message: string = ""): Expectation<T> {
|
|
353
438
|
if (!isString<T>()) ERROR("toMatch() can only be used on string types!");
|
|
354
439
|
// @ts-ignore
|
|
355
440
|
const passed = this._left.indexOf(value) >= 0;
|
|
@@ -361,36 +446,39 @@ export class Expectation<T> extends Tests {
|
|
|
361
446
|
q(value),
|
|
362
447
|
message,
|
|
363
448
|
);
|
|
449
|
+
return this;
|
|
364
450
|
}
|
|
365
451
|
|
|
366
452
|
/**
|
|
367
453
|
* Tests if a string starts with the provided prefix.
|
|
368
454
|
*/
|
|
369
|
-
toStartWith(value: string, message: string = ""):
|
|
455
|
+
toStartWith(value: string, message: string = ""): Expectation<T> {
|
|
370
456
|
if (!isString<T>())
|
|
371
457
|
ERROR("toStartWith() can only be used on string types!");
|
|
372
458
|
// @ts-ignore
|
|
373
459
|
const left = this._left as string;
|
|
374
460
|
const passed = left.indexOf(value) == 0;
|
|
375
461
|
this._resolve(passed, "toStartWith", q(left), q(value), message);
|
|
462
|
+
return this;
|
|
376
463
|
}
|
|
377
464
|
|
|
378
465
|
/**
|
|
379
466
|
* Tests if a string ends with the provided suffix.
|
|
380
467
|
*/
|
|
381
|
-
toEndWith(value: string, message: string = ""):
|
|
468
|
+
toEndWith(value: string, message: string = ""): Expectation<T> {
|
|
382
469
|
if (!isString<T>()) ERROR("toEndWith() can only be used on string types!");
|
|
383
470
|
// @ts-ignore
|
|
384
471
|
const left = this._left as string;
|
|
385
472
|
const idx = left.lastIndexOf(value);
|
|
386
473
|
const passed = idx >= 0 && idx + value.length == left.length;
|
|
387
474
|
this._resolve(passed, "toEndWith", q(left), q(value), message);
|
|
475
|
+
return this;
|
|
388
476
|
}
|
|
389
477
|
|
|
390
478
|
/**
|
|
391
479
|
* Tests if an array has length x
|
|
392
480
|
*/
|
|
393
|
-
toHaveLength(value: i32, message: string = ""):
|
|
481
|
+
toHaveLength(value: i32, message: string = ""): Expectation<T> {
|
|
394
482
|
// @ts-ignore
|
|
395
483
|
const leftLen = this._left.length as i32;
|
|
396
484
|
// @ts-ignore
|
|
@@ -402,13 +490,14 @@ export class Expectation<T> extends Tests {
|
|
|
402
490
|
value.toString(),
|
|
403
491
|
message,
|
|
404
492
|
);
|
|
493
|
+
return this;
|
|
405
494
|
}
|
|
406
495
|
|
|
407
496
|
/**
|
|
408
497
|
* Tests if an array or string contains a value
|
|
409
498
|
*/
|
|
410
499
|
// @ts-ignore
|
|
411
|
-
toContain(value: valueof<T>, message: string = ""):
|
|
500
|
+
toContain(value: valueof<T>, message: string = ""): Expectation<T> {
|
|
412
501
|
if (isString<T>()) {
|
|
413
502
|
// @ts-ignore
|
|
414
503
|
const left = this._left as string;
|
|
@@ -416,7 +505,7 @@ export class Expectation<T> extends Tests {
|
|
|
416
505
|
const needle = value as string;
|
|
417
506
|
const passed = left.indexOf(needle) >= 0;
|
|
418
507
|
this._resolve(passed, "toContain", q(left), q(needle), message);
|
|
419
|
-
return;
|
|
508
|
+
return this;
|
|
420
509
|
}
|
|
421
510
|
|
|
422
511
|
if (isArray<T>()) {
|
|
@@ -425,35 +514,37 @@ export class Expectation<T> extends Tests {
|
|
|
425
514
|
this._resolve(
|
|
426
515
|
passed,
|
|
427
516
|
"toContain",
|
|
428
|
-
|
|
429
|
-
|
|
517
|
+
safeStringify<T>(this._left),
|
|
518
|
+
safeStringify<valueof<T>>(value),
|
|
430
519
|
message,
|
|
431
520
|
);
|
|
432
|
-
return;
|
|
521
|
+
return this;
|
|
433
522
|
}
|
|
434
523
|
|
|
435
524
|
ERROR("toContain() can only be used on string and array types!");
|
|
525
|
+
return this;
|
|
436
526
|
}
|
|
437
527
|
|
|
438
528
|
/**
|
|
439
529
|
* Alias for toContain().
|
|
440
530
|
*/
|
|
441
531
|
// @ts-ignore
|
|
442
|
-
toContains(value: valueof<T>, message: string = ""):
|
|
443
|
-
this.toContain(value, message);
|
|
532
|
+
toContains(value: valueof<T>, message: string = ""): Expectation<T> {
|
|
533
|
+
return this.toContain(value, message);
|
|
444
534
|
}
|
|
445
535
|
|
|
446
536
|
/**
|
|
447
537
|
* Tests if serialized value matches stored snapshot.
|
|
448
538
|
*/
|
|
449
|
-
toMatchSnapshot(name: string = "", message: string = ""):
|
|
539
|
+
toMatchSnapshot(name: string = "", message: string = ""): Expectation<T> {
|
|
450
540
|
let key = name.length
|
|
451
541
|
? namedSnapshotKey(this._snapshotKey, name)
|
|
452
542
|
: nextUnnamedSnapshotKey(this._snapshotKey);
|
|
453
543
|
|
|
454
|
-
const actual =
|
|
544
|
+
const actual = safeStringify<T>(this._left);
|
|
455
545
|
const res = snapshotAssert(key, actual);
|
|
456
546
|
this._resolve(res.ok, "toMatchSnapshot", actual, res.expected, message);
|
|
547
|
+
return this;
|
|
457
548
|
}
|
|
458
549
|
|
|
459
550
|
/**
|
|
@@ -466,7 +557,7 @@ export class Expectation<T> extends Tests {
|
|
|
466
557
|
* `.toThrow()` on a non-function value records a failure that explains the
|
|
467
558
|
* usage.
|
|
468
559
|
*/
|
|
469
|
-
toThrow(message: string = ""):
|
|
560
|
+
toThrow(message: string = ""): Expectation<T> {
|
|
470
561
|
// @ts-ignore
|
|
471
562
|
if (!isDefined(AS_TEST_TRY_AS)) {
|
|
472
563
|
if (!warnedToThrowDisabled) {
|
|
@@ -476,7 +567,7 @@ export class Expectation<T> extends Tests {
|
|
|
476
567
|
warnedToThrowDisabled = true;
|
|
477
568
|
}
|
|
478
569
|
this._resolve(true, "toThrow", q("disabled"), q("disabled"), message);
|
|
479
|
-
return;
|
|
570
|
+
return this;
|
|
480
571
|
}
|
|
481
572
|
|
|
482
573
|
if (!isFunction<T>()) {
|
|
@@ -489,7 +580,7 @@ export class Expectation<T> extends Tests {
|
|
|
489
580
|
? message
|
|
490
581
|
: "toThrow() requires a function: expect((): void => { ... }).toThrow()",
|
|
491
582
|
);
|
|
492
|
-
return;
|
|
583
|
+
return this;
|
|
493
584
|
}
|
|
494
585
|
|
|
495
586
|
// try-as rewrites the throw inside the callback to bump
|
|
@@ -515,111 +606,51 @@ export class Expectation<T> extends Tests {
|
|
|
515
606
|
q("throws"),
|
|
516
607
|
message,
|
|
517
608
|
);
|
|
609
|
+
return this;
|
|
518
610
|
}
|
|
519
611
|
|
|
520
612
|
/**
|
|
521
613
|
* Tests for equality
|
|
522
614
|
*/
|
|
523
|
-
toBe(equals: T, message: string = ""):
|
|
524
|
-
|
|
525
|
-
|
|
615
|
+
toBe(equals: T, message: string = ""): Expectation<T> {
|
|
616
|
+
// Deep structural equality for managed values; `===` semantics for
|
|
617
|
+
// primitives and strings (reflectEquals does the dispatch).
|
|
618
|
+
// `toEqual` is kept below as a Jest-familiarity alias.
|
|
619
|
+
const passed = reflectEquals<T>(this._left, equals, [], false);
|
|
526
620
|
this._resolve(
|
|
527
621
|
passed,
|
|
528
622
|
"toBe",
|
|
529
|
-
|
|
530
|
-
|
|
623
|
+
safeStringify<T>(this._left),
|
|
624
|
+
safeStringify<T>(equals),
|
|
531
625
|
message,
|
|
532
626
|
);
|
|
627
|
+
return this;
|
|
533
628
|
}
|
|
534
629
|
|
|
535
630
|
/**
|
|
536
|
-
*
|
|
631
|
+
* Alias of `toBe` retained for Jest familiarity.
|
|
537
632
|
*/
|
|
538
|
-
toEqual(equals: T, message: string = ""):
|
|
539
|
-
|
|
540
|
-
this._resolve(
|
|
541
|
-
passed,
|
|
542
|
-
"toEqual",
|
|
543
|
-
JSON.stringify<T>(this._left),
|
|
544
|
-
JSON.stringify<T>(equals),
|
|
545
|
-
message,
|
|
546
|
-
);
|
|
633
|
+
toEqual(equals: T, message: string = ""): Expectation<T> {
|
|
634
|
+
return this.toBe(equals, message);
|
|
547
635
|
}
|
|
548
636
|
|
|
549
637
|
/**
|
|
550
|
-
*
|
|
638
|
+
* Like `toBe` but also requires the runtime type (rtId) of the
|
|
639
|
+
* operands to match for managed values.
|
|
551
640
|
*/
|
|
552
|
-
toStrictEqual(equals: T, message: string = ""):
|
|
553
|
-
const passed =
|
|
641
|
+
toStrictEqual(equals: T, message: string = ""): Expectation<T> {
|
|
642
|
+
const passed = reflectEquals<T>(this._left, equals, [], true);
|
|
554
643
|
this._resolve(
|
|
555
644
|
passed,
|
|
556
645
|
"toStrictEqual",
|
|
557
|
-
|
|
558
|
-
|
|
646
|
+
safeStringify<T>(this._left),
|
|
647
|
+
safeStringify<T>(equals),
|
|
559
648
|
message,
|
|
560
649
|
);
|
|
650
|
+
return this;
|
|
561
651
|
}
|
|
562
652
|
}
|
|
563
653
|
|
|
564
|
-
function arrayEquals<T>(a: T[], b: T[], strict: bool): boolean {
|
|
565
|
-
if (a.length != b.length) return false;
|
|
566
|
-
for (let i = 0; i < a.length; i++) {
|
|
567
|
-
if (!valueEquals<T>(unchecked(a[i]), unchecked(b[i]), strict)) {
|
|
568
|
-
return false;
|
|
569
|
-
}
|
|
570
|
-
}
|
|
571
|
-
return true;
|
|
572
|
-
}
|
|
573
|
-
|
|
574
|
-
function valueEquals<T>(left: T, right: T, strict: bool): bool {
|
|
575
|
-
if (isBoolean<T>() || isString<T>() || isInteger<T>() || isFloat<T>()) {
|
|
576
|
-
return left === right;
|
|
577
|
-
}
|
|
578
|
-
|
|
579
|
-
if (isNullable<T>()) {
|
|
580
|
-
const leftPtr = changetype<usize>(left);
|
|
581
|
-
const rightPtr = changetype<usize>(right);
|
|
582
|
-
if (leftPtr == 0 || rightPtr == 0) return leftPtr == rightPtr;
|
|
583
|
-
}
|
|
584
|
-
|
|
585
|
-
if (isArray<T>()) {
|
|
586
|
-
return arrayEquals<valueof<T>>(
|
|
587
|
-
changetype<valueof<T>[]>(left),
|
|
588
|
-
changetype<valueof<T>[]>(right),
|
|
589
|
-
strict,
|
|
590
|
-
);
|
|
591
|
-
}
|
|
592
|
-
|
|
593
|
-
if (isManaged<T>()) {
|
|
594
|
-
return managedEquals<T>(left, right, strict);
|
|
595
|
-
}
|
|
596
|
-
|
|
597
|
-
abort(
|
|
598
|
-
`Unsupported equality matcher for ${nameof<T>()}. Use toBe() for identity or compare fields explicitly.`,
|
|
599
|
-
);
|
|
600
|
-
return false;
|
|
601
|
-
}
|
|
602
|
-
|
|
603
|
-
export function __as_test_deep_equal<T>(left: T, right: T, strict: bool): bool {
|
|
604
|
-
return valueEquals<T>(left, right, strict);
|
|
605
|
-
}
|
|
606
|
-
|
|
607
|
-
function managedEquals<T>(left: T, right: T, strict: bool): bool {
|
|
608
|
-
const leftPtr = changetype<usize>(left);
|
|
609
|
-
const rightPtr = changetype<usize>(right);
|
|
610
|
-
if (leftPtr == rightPtr) return true;
|
|
611
|
-
if (leftPtr == 0 || rightPtr == 0) return false;
|
|
612
|
-
|
|
613
|
-
if (strict) {
|
|
614
|
-
const leftObject = changetype<OBJECT>(leftPtr - TOTAL_OVERHEAD);
|
|
615
|
-
const rightObject = changetype<OBJECT>(rightPtr - TOTAL_OVERHEAD);
|
|
616
|
-
if (leftObject.rtId != rightObject.rtId) return false;
|
|
617
|
-
}
|
|
618
|
-
|
|
619
|
-
// @ts-ignore
|
|
620
|
-
return left.__as_test_equals(right, strict);
|
|
621
|
-
}
|
|
622
|
-
|
|
623
654
|
function isTruthy<T>(value: T): bool {
|
|
624
655
|
if (isBoolean<T>()) {
|
|
625
656
|
return value as bool;
|
|
@@ -641,5 +672,5 @@ function isTruthy<T>(value: T): bool {
|
|
|
641
672
|
}
|
|
642
673
|
|
|
643
674
|
function q(value: string): string {
|
|
644
|
-
return
|
|
675
|
+
return escape(value);
|
|
645
676
|
}
|