@unrift/core 0.5.0 → 0.5.1
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/dist/esm/expect.d.ts +4 -1
- package/dist/esm/expect.d.ts.map +1 -1
- package/dist/esm/expect.js +57 -26
- package/dist/esm/matchers.d.ts.map +1 -1
- package/dist/esm/matchers.js +5 -2
- package/dist/esm/types.d.ts +2 -0
- package/dist/esm/types.d.ts.map +1 -1
- package/dist/esm/utils/helpers.d.ts +7 -0
- package/dist/esm/utils/helpers.d.ts.map +1 -1
- package/dist/esm/utils/helpers.js +30 -0
- package/dist/esm/utils/toThrow.d.ts +5 -0
- package/dist/esm/utils/toThrow.d.ts.map +1 -1
- package/dist/esm/utils/toThrow.js +44 -15
- package/package.json +1 -1
package/dist/esm/expect.d.ts
CHANGED
|
@@ -43,7 +43,7 @@ export interface Matchers<T> {
|
|
|
43
43
|
toHaveFetched(urlOrMatcher: string | RegExp | ((req: Request) => boolean)): void | Promise<void>;
|
|
44
44
|
toHaveFetchedTimes(expected: number): void | Promise<void>;
|
|
45
45
|
readonly not: Matchers<T>;
|
|
46
|
-
readonly resolves: Matchers<
|
|
46
|
+
readonly resolves: Matchers<Settled<T>>;
|
|
47
47
|
readonly rejects: Matchers<unknown>;
|
|
48
48
|
}
|
|
49
49
|
export interface Matchers<T> {
|
|
@@ -53,5 +53,8 @@ export interface ExpectInterface {
|
|
|
53
53
|
extend<M extends MatcherMap>(m: M): void;
|
|
54
54
|
readonly matchers: Readonly<MatcherMap>;
|
|
55
55
|
}
|
|
56
|
+
/** What `.resolves` sees: a function's returned promise, or the promise itself. */
|
|
57
|
+
type Settled<T> = Awaited<T extends (...args: never[]) => infer R ? R : T>;
|
|
56
58
|
export declare const expect: ExpectInterface;
|
|
59
|
+
export {};
|
|
57
60
|
//# sourceMappingURL=expect.d.ts.map
|
package/dist/esm/expect.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"expect.d.ts","sourceRoot":"","sources":["../../src/expect.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAkB,UAAU,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"expect.d.ts","sourceRoot":"","sources":["../../src/expect.ts"],"names":[],"mappings":"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"}
|
package/dist/esm/expect.js
CHANGED
|
@@ -1,14 +1,24 @@
|
|
|
1
1
|
import { formatDiff } from "./utils/diff.js";
|
|
2
|
+
import { isErrorLike, safeString } from "./utils/helpers.js";
|
|
2
3
|
const matcherRegistry = Object.create(null);
|
|
3
4
|
export function extendMatchers(newMatchers) {
|
|
4
5
|
for (const key in newMatchers)
|
|
5
6
|
matcherRegistry[key] = newMatchers[key];
|
|
6
7
|
}
|
|
8
|
+
function describeError(value) {
|
|
9
|
+
return isErrorLike(value) ? value.message : safeString(value);
|
|
10
|
+
}
|
|
11
|
+
function isThenable(value) {
|
|
12
|
+
return (value != null &&
|
|
13
|
+
(typeof value === "object" || typeof value === "function") &&
|
|
14
|
+
typeof value.then === "function");
|
|
15
|
+
}
|
|
7
16
|
export const expect = (() => {
|
|
8
17
|
function expectFn(received) {
|
|
9
18
|
function makeExpectation(isNot) {
|
|
10
19
|
const ctx = {
|
|
11
20
|
isNot,
|
|
21
|
+
promise: "",
|
|
12
22
|
diff(a, b) {
|
|
13
23
|
return formatDiff(a, b);
|
|
14
24
|
},
|
|
@@ -18,9 +28,10 @@ export const expect = (() => {
|
|
|
18
28
|
const fn = matcherRegistry[name];
|
|
19
29
|
matcherFns[name] = (...args) => fn.call(ctx, received, ...args);
|
|
20
30
|
}
|
|
21
|
-
function makeAsyncProxy(getActual, asyncIsNot) {
|
|
31
|
+
function makeAsyncProxy(getActual, asyncIsNot, promise) {
|
|
22
32
|
const asyncCtx = {
|
|
23
33
|
isNot: asyncIsNot,
|
|
34
|
+
promise,
|
|
24
35
|
diff(a, b) {
|
|
25
36
|
return formatDiff(a, b);
|
|
26
37
|
},
|
|
@@ -28,15 +39,14 @@ export const expect = (() => {
|
|
|
28
39
|
const asyncFns = {};
|
|
29
40
|
for (const name in matcherRegistry) {
|
|
30
41
|
const fn = matcherRegistry[name];
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
};
|
|
42
|
+
// Not async: getActual() runs now, so a bad received value (a sync
|
|
43
|
+
// throw, a non-promise) throws immediately like Jest, even unawaited.
|
|
44
|
+
asyncFns[name] = (...args) => getActual().then((actual) => fn.call(asyncCtx, actual, ...args));
|
|
35
45
|
}
|
|
36
46
|
return new Proxy(asyncFns, {
|
|
37
47
|
get(target, prop) {
|
|
38
48
|
if (prop === "not") {
|
|
39
|
-
return makeAsyncProxy(getActual, !asyncIsNot);
|
|
49
|
+
return makeAsyncProxy(getActual, !asyncIsNot, promise);
|
|
40
50
|
}
|
|
41
51
|
if (typeof prop === "string" && !(prop in target)) {
|
|
42
52
|
throw new Error(`Unknown matcher: ${prop}`);
|
|
@@ -49,30 +59,51 @@ export const expect = (() => {
|
|
|
49
59
|
get(target, prop) {
|
|
50
60
|
if (prop === "not")
|
|
51
61
|
return makeExpectation(!isNot);
|
|
62
|
+
// Same as Jest: a function is called and must return a promise. A
|
|
63
|
+
// sync throw from it isn't a rejection, it fails the assertion.
|
|
64
|
+
const toPromise = (modifier) => {
|
|
65
|
+
const value = typeof received === "function"
|
|
66
|
+
? received()
|
|
67
|
+
: received;
|
|
68
|
+
if (!isThenable(value)) {
|
|
69
|
+
throw new TypeError(`.${modifier}: received value must be a promise or a function returning a promise, got ${describeError(value)}`);
|
|
70
|
+
}
|
|
71
|
+
return value;
|
|
72
|
+
};
|
|
52
73
|
if (prop === "resolves") {
|
|
53
|
-
return makeAsyncProxy(
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
74
|
+
return makeAsyncProxy(() => {
|
|
75
|
+
const pending = toPromise("resolves");
|
|
76
|
+
return (async () => {
|
|
77
|
+
try {
|
|
78
|
+
return await pending;
|
|
79
|
+
}
|
|
80
|
+
catch (err) {
|
|
81
|
+
throw new Error(`Expected promise to resolve, but it rejected with: ${describeError(err)}`);
|
|
82
|
+
}
|
|
83
|
+
})();
|
|
84
|
+
}, isNot, "resolves");
|
|
61
85
|
}
|
|
62
86
|
if (prop === "rejects") {
|
|
63
|
-
return makeAsyncProxy(
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
87
|
+
return makeAsyncProxy(() => {
|
|
88
|
+
const pending = toPromise("rejects");
|
|
89
|
+
return (async () => {
|
|
90
|
+
// Tracked with a flag, not by error message, so a promise that
|
|
91
|
+
// rejects with that same text is still treated as a rejection.
|
|
92
|
+
let resolved = false;
|
|
93
|
+
let reason;
|
|
94
|
+
try {
|
|
95
|
+
await pending;
|
|
96
|
+
resolved = true;
|
|
97
|
+
}
|
|
98
|
+
catch (err) {
|
|
99
|
+
reason = err;
|
|
100
|
+
}
|
|
101
|
+
if (resolved) {
|
|
102
|
+
throw new Error("Expected promise to reject, but it resolved");
|
|
72
103
|
}
|
|
73
|
-
return
|
|
74
|
-
}
|
|
75
|
-
}, isNot);
|
|
104
|
+
return reason;
|
|
105
|
+
})();
|
|
106
|
+
}, isNot, "rejects");
|
|
76
107
|
}
|
|
77
108
|
if (typeof prop === "string" && !(prop in target)) {
|
|
78
109
|
throw new Error(`Unknown matcher: ${prop}`);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"matchers.d.ts","sourceRoot":"","sources":["../../src/matchers.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"matchers.d.ts","sourceRoot":"","sources":["../../src/matchers.ts"],"names":[],"mappings":"AA6GA,wBAAgB,sBAAsB,SAMrC;AAED,wBAAgB,aAAa,SAE5B"}
|
package/dist/esm/matchers.js
CHANGED
|
@@ -4,7 +4,7 @@ import { isFetchMock } from "./mock/fetch.js";
|
|
|
4
4
|
import { deepEqual } from "./utils/deepEqual.js";
|
|
5
5
|
import { looseEqual } from "./utils/looseEqual.js";
|
|
6
6
|
import { regexTest } from "./utils/helpers.js";
|
|
7
|
-
import { toThrow } from "./utils/toThrow.js";
|
|
7
|
+
import { toThrow, toThrowFromPromise, } from "./utils/toThrow.js";
|
|
8
8
|
let matchersRegistered = false;
|
|
9
9
|
function ensureSpy(received, matcherName) {
|
|
10
10
|
if (!isSpy(received)) {
|
|
@@ -223,7 +223,10 @@ function registerCoreMatchers() {
|
|
|
223
223
|
}
|
|
224
224
|
},
|
|
225
225
|
toThrow(received, expected) {
|
|
226
|
-
|
|
226
|
+
// Under .resolves/.rejects, `received` is the settled value itself.
|
|
227
|
+
const { pass, message } = this.promise
|
|
228
|
+
? toThrowFromPromise(received, expected, this.isNot, this.promise)
|
|
229
|
+
: toThrow(received, expected, this.isNot);
|
|
227
230
|
if (!pass)
|
|
228
231
|
throw new Error(message());
|
|
229
232
|
},
|
package/dist/esm/types.d.ts
CHANGED
|
@@ -16,6 +16,8 @@ export declare enum TaskMode {
|
|
|
16
16
|
}
|
|
17
17
|
export interface MatcherContext {
|
|
18
18
|
isNot: boolean;
|
|
19
|
+
/** "resolves" or "rejects" under those modifiers, otherwise "" (same as Jest). */
|
|
20
|
+
promise: "" | "resolves" | "rejects";
|
|
19
21
|
diff(a: unknown, b: unknown): string;
|
|
20
22
|
}
|
|
21
23
|
export type MatcherFn = (this: MatcherContext, received: unknown, ...args: readonly unknown[]) => void | Promise<void>;
|
package/dist/esm/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,UAAU,CAAC,CAAC,IAAI,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;AAE3C,MAAM,MAAM,YAAY,CAAC,CAAC,IAAI,MAAM,UAAU,CAAC,CAAC,CAAC,CAAC;AAElD,oBAAY,UAAU;IACpB,OAAO,YAAY;IACnB,OAAO,YAAY;IACnB,IAAI,SAAS;IACb,IAAI,SAAS;IACb,OAAO,YAAY;IACnB,IAAI,SAAS;CACd;AAED,oBAAY,QAAQ;IAClB,OAAO,YAAY;IACnB,IAAI,SAAS;IACb,IAAI,SAAS;IACb,IAAI,SAAS;CACd;AAED,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,OAAO,CAAC;IACf,IAAI,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;CACtC;AAED,MAAM,MAAM,SAAS,GAAG,CACtB,IAAI,EAAE,cAAc,EACpB,QAAQ,EAAE,OAAO,EACjB,GAAG,IAAI,EAAE,SAAS,OAAO,EAAE,KACxB,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AAE1B,MAAM,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC"}
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,UAAU,CAAC,CAAC,IAAI,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;AAE3C,MAAM,MAAM,YAAY,CAAC,CAAC,IAAI,MAAM,UAAU,CAAC,CAAC,CAAC,CAAC;AAElD,oBAAY,UAAU;IACpB,OAAO,YAAY;IACnB,OAAO,YAAY;IACnB,IAAI,SAAS;IACb,IAAI,SAAS;IACb,OAAO,YAAY;IACnB,IAAI,SAAS;CACd;AAED,oBAAY,QAAQ;IAClB,OAAO,YAAY;IACnB,IAAI,SAAS;IACb,IAAI,SAAS;IACb,IAAI,SAAS;CACd;AAED,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,OAAO,CAAC;IACf,kFAAkF;IAClF,OAAO,EAAE,EAAE,GAAG,UAAU,GAAG,SAAS,CAAC;IACrC,IAAI,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;CACtC;AAED,MAAM,MAAM,SAAS,GAAG,CACtB,IAAI,EAAE,cAAc,EACpB,QAAQ,EAAE,OAAO,EACjB,GAAG,IAAI,EAAE,SAAS,OAAO,EAAE,KACxB,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AAE1B,MAAM,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC"}
|
|
@@ -32,5 +32,12 @@ export declare function regexTest(re: RegExp, value: string): boolean;
|
|
|
32
32
|
export declare function sameValue(a: unknown, b: unknown): boolean;
|
|
33
33
|
/** Throws unless `retries` is undefined or a non-negative integer. */
|
|
34
34
|
export declare function assertValidRetries(retries: unknown, where: string): void;
|
|
35
|
+
/** String() throws for e.g. null-prototype objects; fall back to the tag. */
|
|
36
|
+
export declare function safeString(value: unknown): string;
|
|
37
|
+
/**
|
|
38
|
+
* Error check that also works across realms (vm, workers, jsdom), where
|
|
39
|
+
* `instanceof Error` is false. Same test Jest uses.
|
|
40
|
+
*/
|
|
41
|
+
export declare function isErrorLike(value: unknown): value is Error;
|
|
35
42
|
export {};
|
|
36
43
|
//# sourceMappingURL=helpers.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../../src/utils/helpers.ts"],"names":[],"mappings":"AAAA,KAAK,SAAS,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,CAAC;AAEhF,MAAM,MAAM,UAAU,GAClB,UAAU,GACV,SAAS,GACT,WAAW,GACX,UAAU,GACV,WAAW,GACX,UAAU,GACV,YAAY,GACZ,YAAY,GACZ,aAAa,GACb,cAAc,CAAC;AAEnB,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,SAAS,CAY9D;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAE5D;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,UAAU,CAEhE;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAEtD;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAyDhD;AAED,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAOjD;AAED;;;;;;;;GAQG;AACH,wBAAgB,SAAS,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAG5D;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,GAAG,OAAO,CASzD;AAED,sEAAsE;AACtE,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CASxE"}
|
|
1
|
+
{"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../../src/utils/helpers.ts"],"names":[],"mappings":"AAAA,KAAK,SAAS,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,CAAC;AAEhF,MAAM,MAAM,UAAU,GAClB,UAAU,GACV,SAAS,GACT,WAAW,GACX,UAAU,GACV,WAAW,GACX,UAAU,GACV,YAAY,GACZ,YAAY,GACZ,aAAa,GACb,cAAc,CAAC;AAEnB,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,SAAS,CAY9D;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAE5D;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,UAAU,CAEhE;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAEtD;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAyDhD;AAED,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAOjD;AAED;;;;;;;;GAQG;AACH,wBAAgB,SAAS,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAG5D;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,GAAG,OAAO,CASzD;AAED,sEAAsE;AACtE,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CASxE;AAED,6EAA6E;AAC7E,wBAAgB,UAAU,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAWjD;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,KAAK,CAW1D"}
|
|
@@ -131,3 +131,33 @@ export function assertValidRetries(retries, where) {
|
|
|
131
131
|
throw new TypeError(`${where}: retries must be a non-negative integer, got ${typeof retries === "string" ? JSON.stringify(retries) : String(retries)}`);
|
|
132
132
|
}
|
|
133
133
|
}
|
|
134
|
+
/** String() throws for e.g. null-prototype objects; fall back to the tag. */
|
|
135
|
+
export function safeString(value) {
|
|
136
|
+
try {
|
|
137
|
+
return String(value);
|
|
138
|
+
}
|
|
139
|
+
catch {
|
|
140
|
+
// The tag lookup can throw too (a throwing Symbol.toStringTag getter).
|
|
141
|
+
try {
|
|
142
|
+
return Object.prototype.toString.call(value);
|
|
143
|
+
}
|
|
144
|
+
catch {
|
|
145
|
+
return "[unprintable value]";
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Error check that also works across realms (vm, workers, jsdom), where
|
|
151
|
+
* `instanceof Error` is false. Same test Jest uses.
|
|
152
|
+
*/
|
|
153
|
+
export function isErrorLike(value) {
|
|
154
|
+
// Both checks can throw (Proxy traps, a throwing Symbol.toStringTag getter).
|
|
155
|
+
// A value that can't be inspected isn't treated as an Error.
|
|
156
|
+
try {
|
|
157
|
+
return (value instanceof Error ||
|
|
158
|
+
Object.prototype.toString.call(value) === "[object Error]");
|
|
159
|
+
}
|
|
160
|
+
catch {
|
|
161
|
+
return false;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
@@ -7,5 +7,10 @@ interface MatchResult {
|
|
|
7
7
|
message: () => string;
|
|
8
8
|
}
|
|
9
9
|
export declare function toThrow(received: unknown, expected?: ToThrowExpected, isNot?: boolean): MatchResult;
|
|
10
|
+
/**
|
|
11
|
+
* toThrow under `.resolves` / `.rejects`. `received` is the settled value, not
|
|
12
|
+
* a function. Same as Jest: it only counts as thrown if it's an Error.
|
|
13
|
+
*/
|
|
14
|
+
export declare function toThrowFromPromise(received: unknown, expected: ToThrowExpected, isNot: boolean, promise: "resolves" | "rejects"): MatchResult;
|
|
10
15
|
export {};
|
|
11
16
|
//# sourceMappingURL=toThrow.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"toThrow.d.ts","sourceRoot":"","sources":["../../../src/utils/toThrow.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,eAAe,GACvB,SAAS,GACT,MAAM,GACN,MAAM,GACN,CAAC,KAAK,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,KAAK,CAAC,GACnC;IAAE,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAEjD,UAAU,WAAW;IACnB,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,MAAM,MAAM,CAAC;CACvB;
|
|
1
|
+
{"version":3,"file":"toThrow.d.ts","sourceRoot":"","sources":["../../../src/utils/toThrow.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,eAAe,GACvB,SAAS,GACT,MAAM,GACN,MAAM,GACN,CAAC,KAAK,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,KAAK,CAAC,GACnC;IAAE,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAEjD,UAAU,WAAW;IACnB,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,MAAM,MAAM,CAAC;CACvB;AA4ED,wBAAgB,OAAO,CACrB,QAAQ,EAAE,OAAO,EACjB,QAAQ,CAAC,EAAE,eAAe,EAC1B,KAAK,UAAQ,GACZ,WAAW,CAwDb;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAChC,QAAQ,EAAE,OAAO,EACjB,QAAQ,EAAE,eAAe,EACzB,KAAK,EAAE,OAAO,EACd,OAAO,EAAE,UAAU,GAAG,SAAS,GAC9B,WAAW,CAyBb"}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { regexTest } from "./helpers.js";
|
|
1
|
+
import { isErrorLike, regexTest, safeString } from "./helpers.js";
|
|
2
2
|
function isErrorConstructor(err) {
|
|
3
3
|
return typeof err === "function";
|
|
4
4
|
}
|
|
5
5
|
function formatThrown(thrown) {
|
|
6
|
-
if (thrown
|
|
6
|
+
if (isErrorLike(thrown)) {
|
|
7
7
|
const name = thrown.name || "Error";
|
|
8
8
|
const msg = thrown.message ?? "";
|
|
9
9
|
return msg ? `${name}: ${msg}` : name;
|
|
@@ -12,13 +12,22 @@ function formatThrown(thrown) {
|
|
|
12
12
|
return typeof thrown === "string" ? thrown : JSON.stringify(thrown);
|
|
13
13
|
}
|
|
14
14
|
catch {
|
|
15
|
-
return
|
|
15
|
+
return safeString(thrown);
|
|
16
16
|
}
|
|
17
17
|
}
|
|
18
|
+
function formatExpected(expected) {
|
|
19
|
+
return typeof expected === "string"
|
|
20
|
+
? `"${expected}"`
|
|
21
|
+
: expected instanceof RegExp
|
|
22
|
+
? expected.toString()
|
|
23
|
+
: isErrorConstructor(expected)
|
|
24
|
+
? expected.name || "[AnonymousErrorConstructor]"
|
|
25
|
+
: JSON.stringify(expected, (_key, value) => value instanceof RegExp ? value.toString() : value);
|
|
26
|
+
}
|
|
18
27
|
function matchThrown(thrown, expected) {
|
|
19
28
|
if (expected === undefined)
|
|
20
29
|
return true;
|
|
21
|
-
const msg = thrown
|
|
30
|
+
const msg = isErrorLike(thrown) ? thrown.message : safeString(thrown);
|
|
22
31
|
// toThrow("substring")
|
|
23
32
|
if (typeof expected === "string") {
|
|
24
33
|
return msg.includes(expected);
|
|
@@ -34,7 +43,7 @@ function matchThrown(thrown, expected) {
|
|
|
34
43
|
// toThrow({ name?, message? })
|
|
35
44
|
if (expected && typeof expected === "object") {
|
|
36
45
|
if (expected.name) {
|
|
37
|
-
const thrownName = thrown
|
|
46
|
+
const thrownName = isErrorLike(thrown) ? thrown.name : undefined;
|
|
38
47
|
if (thrownName !== expected.name)
|
|
39
48
|
return false;
|
|
40
49
|
}
|
|
@@ -44,7 +53,7 @@ function matchThrown(thrown, expected) {
|
|
|
44
53
|
return false;
|
|
45
54
|
}
|
|
46
55
|
else {
|
|
47
|
-
if (!expected.message
|
|
56
|
+
if (!regexTest(expected.message, msg))
|
|
48
57
|
return false;
|
|
49
58
|
}
|
|
50
59
|
}
|
|
@@ -73,7 +82,8 @@ export function toThrow(received, expected, isNot = false) {
|
|
|
73
82
|
result != null &&
|
|
74
83
|
typeof result.then === "function") {
|
|
75
84
|
// Suppress the unhandled rejection from the returned promise
|
|
76
|
-
|
|
85
|
+
// Promise.resolve so plain thenables without .catch work too
|
|
86
|
+
Promise.resolve(result).catch(() => { });
|
|
77
87
|
return {
|
|
78
88
|
pass: false,
|
|
79
89
|
message: () => "toThrow() received an async function. Use expect(fn).rejects.toThrow() for async errors.",
|
|
@@ -92,14 +102,33 @@ export function toThrow(received, expected, isNot = false) {
|
|
|
92
102
|
if (expected === undefined) {
|
|
93
103
|
return `Expected function ${expectation}, but it threw: ${thrownStr}`;
|
|
94
104
|
}
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
105
|
+
return `Expected function ${expectation} ${formatExpected(expected)}, but it threw: ${thrownStr}`;
|
|
106
|
+
},
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* toThrow under `.resolves` / `.rejects`. `received` is the settled value, not
|
|
111
|
+
* a function. Same as Jest: it only counts as thrown if it's an Error.
|
|
112
|
+
*/
|
|
113
|
+
export function toThrowFromPromise(received, expected, isNot, promise) {
|
|
114
|
+
// Same as Jest: a non-Error function is called and treated like a sync
|
|
115
|
+
// toThrow, so `resolves.toThrow()` works on a promise of a function.
|
|
116
|
+
if (typeof received === "function" && !isErrorLike(received)) {
|
|
117
|
+
return toThrow(received, expected, isNot);
|
|
118
|
+
}
|
|
119
|
+
const isError = isErrorLike(received);
|
|
120
|
+
const matched = isError && matchThrown(received, expected);
|
|
121
|
+
const pass = isNot ? !matched : matched;
|
|
122
|
+
return {
|
|
123
|
+
pass,
|
|
124
|
+
message: () => {
|
|
125
|
+
const verb = promise === "rejects" ? "reject" : "resolve";
|
|
126
|
+
const past = promise === "rejects" ? "rejected" : "resolved";
|
|
127
|
+
const target = expected === undefined ? "an Error" : formatExpected(expected);
|
|
128
|
+
const got = isError
|
|
129
|
+
? formatThrown(received)
|
|
130
|
+
: `a non-Error value: ${formatThrown(received)}`;
|
|
131
|
+
return `Expected promise ${isNot ? "not " : ""}to ${verb} with ${target}, but it ${past} with ${got}`;
|
|
103
132
|
},
|
|
104
133
|
};
|
|
105
134
|
}
|