@unrift/core 0.3.0 → 0.5.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/bin/unrift.mjs +2 -1
- package/dist/esm/cli.js +19 -1
- package/dist/esm/expect.d.ts +14 -0
- package/dist/esm/expect.d.ts.map +1 -1
- package/dist/esm/index.d.ts +3 -1
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +2 -0
- package/dist/esm/interface.d.ts +7 -3
- package/dist/esm/interface.d.ts.map +1 -1
- package/dist/esm/interface.js +9 -5
- package/dist/esm/matchers.d.ts.map +1 -1
- package/dist/esm/matchers.js +195 -1
- package/dist/esm/mock/auto.d.ts +27 -0
- package/dist/esm/mock/auto.d.ts.map +1 -0
- package/dist/esm/mock/auto.js +108 -0
- package/dist/esm/mock/fetch.d.ts +47 -0
- package/dist/esm/mock/fetch.d.ts.map +1 -0
- package/dist/esm/mock/fetch.js +149 -0
- package/dist/esm/mock/fs.d.ts +54 -0
- package/dist/esm/mock/fs.d.ts.map +1 -0
- package/dist/esm/mock/fs.js +125 -0
- package/dist/esm/mock/index.d.ts +70 -0
- package/dist/esm/mock/index.d.ts.map +1 -0
- package/dist/esm/mock/index.js +70 -0
- package/dist/esm/mock/module-loader.d.ts +66 -0
- package/dist/esm/mock/module-loader.d.ts.map +1 -0
- package/dist/esm/mock/module-loader.js +123 -0
- package/dist/esm/mock/module.d.ts +99 -0
- package/dist/esm/mock/module.d.ts.map +1 -0
- package/dist/esm/mock/module.js +198 -0
- package/dist/esm/mock/register-loader.d.ts +17 -0
- package/dist/esm/mock/register-loader.d.ts.map +1 -0
- package/dist/esm/mock/register-loader.js +45 -0
- package/dist/esm/mock/spy.d.ts +73 -0
- package/dist/esm/mock/spy.d.ts.map +1 -0
- package/dist/esm/mock/spy.js +307 -0
- package/dist/esm/mock/stub.d.ts +26 -0
- package/dist/esm/mock/stub.d.ts.map +1 -0
- package/dist/esm/mock/stub.js +82 -0
- package/dist/esm/mock/timers.d.ts +51 -0
- package/dist/esm/mock/timers.d.ts.map +1 -0
- package/dist/esm/mock/timers.js +581 -0
- package/dist/esm/run.d.ts +4 -7
- package/dist/esm/run.d.ts.map +1 -1
- package/dist/esm/run.js +6 -2
- package/dist/esm/runner.d.ts +1 -0
- package/dist/esm/runner.d.ts.map +1 -1
- package/dist/esm/runner.js +21 -10
- package/dist/esm/suite.d.ts +24 -6
- package/dist/esm/suite.d.ts.map +1 -1
- package/dist/esm/suite.js +114 -20
- package/dist/esm/test.d.ts +5 -1
- package/dist/esm/test.d.ts.map +1 -1
- package/dist/esm/test.js +20 -6
- package/dist/esm/utils/compareEngine.js +3 -3
- package/dist/esm/utils/defineConfig.d.ts +1 -0
- package/dist/esm/utils/defineConfig.d.ts.map +1 -1
- package/dist/esm/utils/discoverTestFiles.js +1 -1
- package/dist/esm/utils/helpers.d.ts +12 -0
- package/dist/esm/utils/helpers.d.ts.map +1 -1
- package/dist/esm/utils/helpers.js +20 -0
- package/dist/esm/utils/toThrow.d.ts.map +1 -1
- package/dist/esm/utils/toThrow.js +2 -1
- package/package.json +4 -3
package/bin/unrift.mjs
CHANGED
package/dist/esm/cli.js
CHANGED
|
@@ -2,8 +2,13 @@
|
|
|
2
2
|
import { readFileSync } from "node:fs";
|
|
3
3
|
import { dirname, resolve } from "node:path";
|
|
4
4
|
import { fileURLToPath } from "node:url";
|
|
5
|
+
import { registerModuleLoader } from "./mock/register-loader.js";
|
|
5
6
|
import { runTestsCLI, watchTestsCLI } from "./runner.js";
|
|
6
7
|
import { safeRegExp } from "./utils/helpers.js";
|
|
8
|
+
// Install the module-mock loader before any test file is imported. Both the
|
|
9
|
+
// core bin and the unrift wrapper bin run this CLI, so this is the single
|
|
10
|
+
// place module mocking is bootstrapped.
|
|
11
|
+
registerModuleLoader();
|
|
7
12
|
const __cliDir = dirname(fileURLToPath(import.meta.url));
|
|
8
13
|
function readVersion() {
|
|
9
14
|
// Walk up from current file to find package.json (works from both src/ and dist/esm/)
|
|
@@ -31,6 +36,7 @@ Usage:
|
|
|
31
36
|
|
|
32
37
|
Options:
|
|
33
38
|
-c, --config <path> Path to config file
|
|
39
|
+
-g, --grep <pattern> Only run tests whose full name matches (regex)
|
|
34
40
|
-b, --bail Stop on first test failure
|
|
35
41
|
-t, --timeout <ms> Default test timeout in milliseconds
|
|
36
42
|
-w, --watch Re-run tests on file changes
|
|
@@ -44,6 +50,7 @@ Options:
|
|
|
44
50
|
Examples:
|
|
45
51
|
unrift
|
|
46
52
|
unrift math
|
|
53
|
+
unrift --grep "adds numbers"
|
|
47
54
|
unrift -c test/config.ts --bail
|
|
48
55
|
unrift --timeout 10000
|
|
49
56
|
unrift --watch
|
|
@@ -52,6 +59,7 @@ Examples:
|
|
|
52
59
|
function parseArgs(argv) {
|
|
53
60
|
let configPath;
|
|
54
61
|
let pattern;
|
|
62
|
+
let grep;
|
|
55
63
|
let timeoutMs;
|
|
56
64
|
let bail;
|
|
57
65
|
let debug = false;
|
|
@@ -80,6 +88,14 @@ function parseArgs(argv) {
|
|
|
80
88
|
i++;
|
|
81
89
|
continue;
|
|
82
90
|
}
|
|
91
|
+
if (a === "--grep" || a === "-g") {
|
|
92
|
+
const next = argv[i + 1];
|
|
93
|
+
if (!next)
|
|
94
|
+
throw new Error(`${a} requires a pattern`);
|
|
95
|
+
grep = safeRegExp(next);
|
|
96
|
+
i++;
|
|
97
|
+
continue;
|
|
98
|
+
}
|
|
83
99
|
if (a === "--bail" || a === "-b") {
|
|
84
100
|
bail = true;
|
|
85
101
|
continue;
|
|
@@ -122,6 +138,7 @@ function parseArgs(argv) {
|
|
|
122
138
|
return {
|
|
123
139
|
configPath,
|
|
124
140
|
pattern,
|
|
141
|
+
grep,
|
|
125
142
|
timeoutMs,
|
|
126
143
|
bail,
|
|
127
144
|
debug,
|
|
@@ -133,7 +150,7 @@ function parseArgs(argv) {
|
|
|
133
150
|
showVersion,
|
|
134
151
|
};
|
|
135
152
|
}
|
|
136
|
-
const { configPath, pattern, timeoutMs, bail, debug, list, json, cacheClean, watch, help, showVersion, } = parseArgs(process.argv.slice(2));
|
|
153
|
+
const { configPath, pattern, grep, timeoutMs, bail, debug, list, json, cacheClean, watch, help, showVersion, } = parseArgs(process.argv.slice(2));
|
|
137
154
|
if (showVersion) {
|
|
138
155
|
console.log(version);
|
|
139
156
|
process.exit(0);
|
|
@@ -144,6 +161,7 @@ if (help) {
|
|
|
144
161
|
}
|
|
145
162
|
const runOpts = {
|
|
146
163
|
pattern,
|
|
164
|
+
grep,
|
|
147
165
|
configPath,
|
|
148
166
|
timeoutMs,
|
|
149
167
|
bail,
|
package/dist/esm/expect.d.ts
CHANGED
|
@@ -17,6 +17,7 @@ export interface Matchers<T> {
|
|
|
17
17
|
prototype: unknown;
|
|
18
18
|
}): void | Promise<void>;
|
|
19
19
|
toContain(expected: unknown): void | Promise<void>;
|
|
20
|
+
toContainEqual(expected: unknown): void | Promise<void>;
|
|
20
21
|
toEqual(expected: unknown): void | Promise<void>;
|
|
21
22
|
toHaveLength(expected: number): void | Promise<void>;
|
|
22
23
|
toMatch(expected: RegExp | string): void | Promise<void>;
|
|
@@ -24,10 +25,23 @@ export interface Matchers<T> {
|
|
|
24
25
|
toThrow(expected?: unknown): void | Promise<void>;
|
|
25
26
|
toBeGreaterThanOrEqual(expected: number): void | Promise<void>;
|
|
26
27
|
toBeLessThanOrEqual(expected: number): void | Promise<void>;
|
|
28
|
+
toBeCloseTo(expected: number, precision?: number): void | Promise<void>;
|
|
27
29
|
toBeNaN(): void | Promise<void>;
|
|
28
30
|
toBeFinite(): void | Promise<void>;
|
|
29
31
|
toMatchObject(expected: Record<string, unknown>): void | Promise<void>;
|
|
30
32
|
toHaveProperty(path: string | readonly string[], value?: unknown): void | Promise<void>;
|
|
33
|
+
toHaveBeenCalled(): void | Promise<void>;
|
|
34
|
+
toHaveBeenCalledTimes(expected: number): void | Promise<void>;
|
|
35
|
+
toHaveBeenCalledWith(...args: unknown[]): void | Promise<void>;
|
|
36
|
+
toHaveBeenLastCalledWith(...args: unknown[]): void | Promise<void>;
|
|
37
|
+
toHaveBeenNthCalledWith(n: number, ...args: unknown[]): void | Promise<void>;
|
|
38
|
+
toHaveReturned(): void | Promise<void>;
|
|
39
|
+
toHaveReturnedTimes(expected: number): void | Promise<void>;
|
|
40
|
+
toHaveReturnedWith(expected: unknown): void | Promise<void>;
|
|
41
|
+
toHaveLastReturnedWith(expected: unknown): void | Promise<void>;
|
|
42
|
+
toHaveNthReturnedWith(n: number, expected: unknown): void | Promise<void>;
|
|
43
|
+
toHaveFetched(urlOrMatcher: string | RegExp | ((req: Request) => boolean)): void | Promise<void>;
|
|
44
|
+
toHaveFetchedTimes(expected: number): void | Promise<void>;
|
|
31
45
|
readonly not: Matchers<T>;
|
|
32
46
|
readonly resolves: Matchers<Awaited<T>>;
|
|
33
47
|
readonly rejects: Matchers<unknown>;
|
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;AAK1D,wBAAgB,cAAc,CAAC,WAAW,EAAE,UAAU,QAErD;AAED;;;GAGG;AACH,MAAM,WAAW,QAAQ,CAAC,CAAC;IACzB,IAAI,CAAC,QAAQ,EAAE,CAAC,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACxC,WAAW,IAAI,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACpC,SAAS,IAAI,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAClC,QAAQ,IAAI,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACjC,UAAU,IAAI,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACnC,aAAa,IAAI,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACtC,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACxD,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACrD,cAAc,CAAC,QAAQ,EAAE;QAAE,SAAS,EAAE,OAAO,CAAA;KAAE,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACvE,SAAS,CAAC,QAAQ,EAAE,OAAO,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACnD,OAAO,CAAC,QAAQ,EAAE,OAAO,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACjD,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACrD,OAAO,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACzD,aAAa,CAAC,QAAQ,EAAE,OAAO,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACvD,OAAO,CAAC,QAAQ,CAAC,EAAE,OAAO,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAClD,sBAAsB,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/D,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5D,OAAO,IAAI,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAChC,UAAU,IAAI,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACnC,aAAa,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACvE,cAAc,CACZ,IAAI,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,EAChC,KAAK,CAAC,EAAE,OAAO,GACd,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"expect.d.ts","sourceRoot":"","sources":["../../src/expect.ts"],"names":[],"mappings":"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"}
|
package/dist/esm/index.d.ts
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
export { beforeEach, afterEach, beforeAll, afterAll } from "./hooks";
|
|
2
2
|
export { defineConfig, type UnriftConfigOptions } from "./utils/defineConfig";
|
|
3
|
-
export { describe, it, test } from "./interface";
|
|
3
|
+
export { describe, it, test, type TestOptions } from "./interface";
|
|
4
4
|
export { expect, extendMatchers } from "./expect";
|
|
5
5
|
export type { Matchers, ExpectInterface } from "./expect";
|
|
6
6
|
export type { MatcherContext, MatcherFn, MatcherMap, Promisable, } from "./types";
|
|
7
7
|
export { runEngine } from "./run";
|
|
8
8
|
export type { RunEngineResult } from "./run";
|
|
9
|
+
export { mock, spy, spyOn, isSpy, mockObject, mockClass, stub, mockGlobal, mockFetch, mockFetchOnce, useFakeTimers, useRealTimers, advanceTimersByTime, advanceTimersByTimeAsync, runAllTimers, runAllTimersAsync, runOnlyPendingTimers, runOnlyPendingTimersAsync, getTimerCount, setSystemTime, getRealSystemTime, doMock, unmock, listMockedSpecs, fromModule, mockFs, clearAllMocks, resetAllMocks, restoreAllMocks, } from "./mock/index";
|
|
10
|
+
export type { Spy, MockState, MockResult, MockFetch, FetchMatcher, MockResponseInit, MockFetchResponse, UseFakeTimersOptions, FakeableApi, LoaderMessage, FakeFsHandle, FakeFsState, } from "./mock/index";
|
|
9
11
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/esm/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACrE,OAAO,EAAE,YAAY,EAAE,KAAK,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAC9E,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACrE,OAAO,EAAE,YAAY,EAAE,KAAK,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAC9E,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,WAAW,EAAE,MAAM,aAAa,CAAC;AACnE,OAAO,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAElD,YAAY,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAC1D,YAAY,EACV,cAAc,EACd,SAAS,EACT,UAAU,EACV,UAAU,GACX,MAAM,SAAS,CAAC;AACjB,OAAO,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAClC,YAAY,EAAE,eAAe,EAAE,MAAM,OAAO,CAAC;AAG7C,OAAO,EACL,IAAI,EACJ,GAAG,EACH,KAAK,EACL,KAAK,EACL,UAAU,EACV,SAAS,EACT,IAAI,EACJ,UAAU,EACV,SAAS,EACT,aAAa,EACb,aAAa,EACb,aAAa,EACb,mBAAmB,EACnB,wBAAwB,EACxB,YAAY,EACZ,iBAAiB,EACjB,oBAAoB,EACpB,yBAAyB,EACzB,aAAa,EACb,aAAa,EACb,iBAAiB,EACjB,MAAM,EACN,MAAM,EACN,eAAe,EACf,UAAU,EACV,MAAM,EACN,aAAa,EACb,aAAa,EACb,eAAe,GAChB,MAAM,cAAc,CAAC;AACtB,YAAY,EACV,GAAG,EACH,SAAS,EACT,UAAU,EACV,SAAS,EACT,YAAY,EACZ,gBAAgB,EAChB,iBAAiB,EACjB,oBAAoB,EACpB,WAAW,EACX,aAAa,EACb,YAAY,EACZ,WAAW,GACZ,MAAM,cAAc,CAAC"}
|
package/dist/esm/index.js
CHANGED
|
@@ -3,3 +3,5 @@ export { defineConfig } from "./utils/defineConfig.js";
|
|
|
3
3
|
export { describe, it, test } from "./interface.js";
|
|
4
4
|
export { expect, extendMatchers } from "./expect.js";
|
|
5
5
|
export { runEngine } from "./run.js";
|
|
6
|
+
// Mocking suite
|
|
7
|
+
export { mock, spy, spyOn, isSpy, mockObject, mockClass, stub, mockGlobal, mockFetch, mockFetchOnce, useFakeTimers, useRealTimers, advanceTimersByTime, advanceTimersByTimeAsync, runAllTimers, runAllTimersAsync, runOnlyPendingTimers, runOnlyPendingTimersAsync, getTimerCount, setSystemTime, getRealSystemTime, doMock, unmock, listMockedSpecs, fromModule, mockFs, clearAllMocks, resetAllMocks, restoreAllMocks, } from "./mock/index.js";
|
package/dist/esm/interface.d.ts
CHANGED
|
@@ -8,10 +8,14 @@ type DescribeFn = {
|
|
|
8
8
|
skip: (description: string, fn: () => void) => void;
|
|
9
9
|
todo: (description: string) => void;
|
|
10
10
|
};
|
|
11
|
+
export interface TestOptions {
|
|
12
|
+
timeout?: number;
|
|
13
|
+
retries?: number;
|
|
14
|
+
}
|
|
11
15
|
type ItFn = {
|
|
12
|
-
(description: string, fn: PromisableFn<void>,
|
|
13
|
-
only: (description: string, fn: PromisableFn<void>,
|
|
14
|
-
skip: (description: string, fn: PromisableFn<void>,
|
|
16
|
+
(description: string, fn: PromisableFn<void>, options?: number | TestOptions): void;
|
|
17
|
+
only: (description: string, fn: PromisableFn<void>, options?: number | TestOptions) => void;
|
|
18
|
+
skip: (description: string, fn: PromisableFn<void>, options?: number | TestOptions) => void;
|
|
15
19
|
todo: (description: string) => void;
|
|
16
20
|
};
|
|
17
21
|
declare const describe: DescribeFn;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"interface.d.ts","sourceRoot":"","sources":["../../src/interface.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,YAAY,EAAY,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"interface.d.ts","sourceRoot":"","sources":["../../src/interface.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,YAAY,EAAY,MAAM,SAAS,CAAC;AAGtD;;GAEG;AAEH,KAAK,UAAU,GAAG;IAChB,CAAC,WAAW,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,IAAI,GAAG,IAAI,CAAC;IAC5C,IAAI,EAAE,CAAC,WAAW,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,IAAI,KAAK,IAAI,CAAC;IACpD,IAAI,EAAE,CAAC,WAAW,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,IAAI,KAAK,IAAI,CAAC;IACpD,IAAI,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;CACrC,CAAC;AAEF,MAAM,WAAW,WAAW;IAC1B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,KAAK,IAAI,GAAG;IACV,CACE,WAAW,EAAE,MAAM,EACnB,EAAE,EAAE,YAAY,CAAC,IAAI,CAAC,EACtB,OAAO,CAAC,EAAE,MAAM,GAAG,WAAW,GAC7B,IAAI,CAAC;IACR,IAAI,EAAE,CACJ,WAAW,EAAE,MAAM,EACnB,EAAE,EAAE,YAAY,CAAC,IAAI,CAAC,EACtB,OAAO,CAAC,EAAE,MAAM,GAAG,WAAW,KAC3B,IAAI,CAAC;IACV,IAAI,EAAE,CACJ,WAAW,EAAE,MAAM,EACnB,EAAE,EAAE,YAAY,CAAC,IAAI,CAAC,EACtB,OAAO,CAAC,EAAE,MAAM,GAAG,WAAW,KAC3B,IAAI,CAAC;IACV,IAAI,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;CACrC,CAAC;AA6BF,QAAA,MAAM,QAAQ,EAAE,UAC8B,CAAC;AAyB/C,QAAA,MAAM,EAAE,EAAE,IACuC,CAAC;AAOlD,QAAA,MAAM,IAAI,EAAE,IAAS,CAAC;AAEtB,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC"}
|
package/dist/esm/interface.js
CHANGED
|
@@ -2,6 +2,7 @@ import { assertRegisterState, unriftGlobalContext } from "./context.js";
|
|
|
2
2
|
import { getCurrentSuite, Suite } from "./suite.js";
|
|
3
3
|
import { Test } from "./test.js";
|
|
4
4
|
import { TaskMode } from "./types.js";
|
|
5
|
+
import { assertValidRetries } from "./utils/helpers.js";
|
|
5
6
|
function _describe(description, fn, mode) {
|
|
6
7
|
assertRegisterState("describe");
|
|
7
8
|
const parent = getCurrentSuite();
|
|
@@ -24,14 +25,17 @@ const describe = (description, fn) => _describe(description, fn, TaskMode.Defaul
|
|
|
24
25
|
describe.only = (description, fn) => _describe(description, fn, TaskMode.Only);
|
|
25
26
|
describe.skip = (description, fn) => _describe(description, fn, TaskMode.Skip);
|
|
26
27
|
describe.todo = (description) => _describe(description, () => { }, TaskMode.Todo);
|
|
27
|
-
function _it(description, fn, mode,
|
|
28
|
+
function _it(description, fn, mode, options) {
|
|
28
29
|
assertRegisterState("it");
|
|
29
|
-
|
|
30
|
+
// A bare number is the timeout, kept for backwards compatibility.
|
|
31
|
+
const { timeout, retries } = typeof options === "number" ? { timeout: options } : (options ?? {});
|
|
32
|
+
assertValidRetries(retries, `it("${description}")`);
|
|
33
|
+
const test = new Test(description, fn, mode, timeout, retries);
|
|
30
34
|
getCurrentSuite().addTest(test);
|
|
31
35
|
}
|
|
32
|
-
const it = (description, fn,
|
|
33
|
-
it.only = (description, fn,
|
|
34
|
-
it.skip = (description, fn,
|
|
36
|
+
const it = (description, fn, options) => _it(description, fn, TaskMode.Default, options);
|
|
37
|
+
it.only = (description, fn, options) => _it(description, fn, TaskMode.Only, options);
|
|
38
|
+
it.skip = (description, fn, options) => _it(description, fn, TaskMode.Skip, options);
|
|
35
39
|
it.todo = (description) => _it(description, () => { }, TaskMode.Todo);
|
|
36
40
|
const test = it;
|
|
37
41
|
export { describe, it, test };
|
|
@@ -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":"AAyGA,wBAAgB,sBAAsB,SAMrC;AAED,wBAAgB,aAAa,SAE5B"}
|
package/dist/esm/matchers.js
CHANGED
|
@@ -1,8 +1,41 @@
|
|
|
1
1
|
import { expect } from "./expect.js";
|
|
2
|
+
import { isSpy } from "./mock/spy.js";
|
|
3
|
+
import { isFetchMock } from "./mock/fetch.js";
|
|
2
4
|
import { deepEqual } from "./utils/deepEqual.js";
|
|
3
5
|
import { looseEqual } from "./utils/looseEqual.js";
|
|
6
|
+
import { regexTest } from "./utils/helpers.js";
|
|
4
7
|
import { toThrow } from "./utils/toThrow.js";
|
|
5
8
|
let matchersRegistered = false;
|
|
9
|
+
function ensureSpy(received, matcherName) {
|
|
10
|
+
if (!isSpy(received)) {
|
|
11
|
+
throw new Error(`${matcherName}() requires a spy or mock function (created via spy() or spyOn()), ` +
|
|
12
|
+
`but received ${typeof received === "object" ? Object.prototype.toString.call(received) : typeof received}`);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
function ensureFetchMock(received, matcherName) {
|
|
16
|
+
if (!isFetchMock(received)) {
|
|
17
|
+
throw new Error(`${matcherName}() requires \`mock.fetch\` as the received value, ` +
|
|
18
|
+
`but received ${typeof received === "object" ? Object.prototype.toString.call(received) : typeof received}`);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
function matchesFetchTarget(req, target) {
|
|
22
|
+
if (typeof target === "string")
|
|
23
|
+
return req.url === target;
|
|
24
|
+
if (target instanceof RegExp)
|
|
25
|
+
return regexTest(target, req.url);
|
|
26
|
+
if (typeof target === "function")
|
|
27
|
+
return Boolean(target(req));
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
function argsEqual(a, b) {
|
|
31
|
+
if (a.length !== b.length)
|
|
32
|
+
return false;
|
|
33
|
+
for (let i = 0; i < a.length; i++) {
|
|
34
|
+
if (!looseEqual(a[i], b[i]))
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
return true;
|
|
38
|
+
}
|
|
6
39
|
function partialMatch(received, expected) {
|
|
7
40
|
if (expected === null || typeof expected !== "object") {
|
|
8
41
|
return looseEqual(received, expected);
|
|
@@ -132,6 +165,22 @@ function registerCoreMatchers() {
|
|
|
132
165
|
throw new Error(this.diff(received, expected));
|
|
133
166
|
}
|
|
134
167
|
},
|
|
168
|
+
toContainEqual(received, expected) {
|
|
169
|
+
if (!Array.isArray(received)) {
|
|
170
|
+
throw new Error(this.diff(received, "expected an array for toContainEqual()"));
|
|
171
|
+
}
|
|
172
|
+
// for...of visits sparse holes as undefined; Array.some would skip them.
|
|
173
|
+
let pass = false;
|
|
174
|
+
for (const item of received) {
|
|
175
|
+
if (looseEqual(item, expected)) {
|
|
176
|
+
pass = true;
|
|
177
|
+
break;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
if (this.isNot ? pass : !pass) {
|
|
181
|
+
throw new Error(this.diff(received, expected));
|
|
182
|
+
}
|
|
183
|
+
},
|
|
135
184
|
toEqual(received, expected) {
|
|
136
185
|
const pass = looseEqual(received, expected);
|
|
137
186
|
if (this.isNot ? pass : !pass) {
|
|
@@ -163,7 +212,7 @@ function registerCoreMatchers() {
|
|
|
163
212
|
}
|
|
164
213
|
const pass = typeof expected === "string"
|
|
165
214
|
? received.includes(expected)
|
|
166
|
-
: expected
|
|
215
|
+
: regexTest(expected, received);
|
|
167
216
|
if (this.isNot ? pass : !pass)
|
|
168
217
|
throw new Error(this.diff(received, expected));
|
|
169
218
|
},
|
|
@@ -196,6 +245,24 @@ function registerCoreMatchers() {
|
|
|
196
245
|
throw new Error(this.diff(received, `<= ${expected}`));
|
|
197
246
|
}
|
|
198
247
|
},
|
|
248
|
+
toBeCloseTo(received, expected, precision = 2) {
|
|
249
|
+
if (typeof received !== "number") {
|
|
250
|
+
throw new Error(this.diff(received, "expected a number"));
|
|
251
|
+
}
|
|
252
|
+
if (typeof expected !== "number") {
|
|
253
|
+
throw new Error(this.diff(expected, "a number for expected"));
|
|
254
|
+
}
|
|
255
|
+
if (!Number.isFinite(precision)) {
|
|
256
|
+
throw new Error(this.diff(precision, "a finite number for precision"));
|
|
257
|
+
}
|
|
258
|
+
// Same-signed infinities are equal; the subtraction below would be NaN.
|
|
259
|
+
// Finite values always go through the tolerance check.
|
|
260
|
+
const pass = (!Number.isFinite(received) && received === expected) ||
|
|
261
|
+
Math.abs(received - expected) < 10 ** -precision / 2;
|
|
262
|
+
if (this.isNot ? pass : !pass) {
|
|
263
|
+
throw new Error(this.diff(received, `${expected} (precision ${precision})`));
|
|
264
|
+
}
|
|
265
|
+
},
|
|
199
266
|
toBeNaN(received) {
|
|
200
267
|
const pass = Number.isNaN(received);
|
|
201
268
|
if (this.isNot ? pass : !pass) {
|
|
@@ -219,6 +286,133 @@ function registerCoreMatchers() {
|
|
|
219
286
|
throw new Error(this.diff(received, expected));
|
|
220
287
|
}
|
|
221
288
|
},
|
|
289
|
+
toHaveBeenCalled(received) {
|
|
290
|
+
ensureSpy(received, "toHaveBeenCalled");
|
|
291
|
+
const pass = received.mock.calls.length > 0;
|
|
292
|
+
if (this.isNot ? pass : !pass) {
|
|
293
|
+
throw new Error(this.diff(`${received.getMockName()} called ${received.mock.calls.length} time(s)`, "to have been called"));
|
|
294
|
+
}
|
|
295
|
+
},
|
|
296
|
+
toHaveBeenCalledTimes(received, expected) {
|
|
297
|
+
ensureSpy(received, "toHaveBeenCalledTimes");
|
|
298
|
+
if (typeof expected !== "number" || !Number.isFinite(expected)) {
|
|
299
|
+
throw new Error(this.diff(expected, "toHaveBeenCalledTimes() requires a finite number"));
|
|
300
|
+
}
|
|
301
|
+
const actual = received.mock.calls.length;
|
|
302
|
+
const pass = actual === expected;
|
|
303
|
+
if (this.isNot ? pass : !pass) {
|
|
304
|
+
throw new Error(this.diff(actual, expected));
|
|
305
|
+
}
|
|
306
|
+
},
|
|
307
|
+
toHaveBeenCalledWith(received, ...expectedArgs) {
|
|
308
|
+
ensureSpy(received, "toHaveBeenCalledWith");
|
|
309
|
+
const pass = received.mock.calls.some((call) => argsEqual(call, expectedArgs));
|
|
310
|
+
if (this.isNot ? pass : !pass) {
|
|
311
|
+
throw new Error(this.diff(received.mock.calls, expectedArgs));
|
|
312
|
+
}
|
|
313
|
+
},
|
|
314
|
+
toHaveBeenLastCalledWith(received, ...expectedArgs) {
|
|
315
|
+
ensureSpy(received, "toHaveBeenLastCalledWith");
|
|
316
|
+
const last = received.mock.lastCall;
|
|
317
|
+
const pass = last !== undefined && argsEqual(last, expectedArgs);
|
|
318
|
+
if (this.isNot ? pass : !pass) {
|
|
319
|
+
throw new Error(this.diff(last ?? "no calls", expectedArgs));
|
|
320
|
+
}
|
|
321
|
+
},
|
|
322
|
+
toHaveBeenNthCalledWith(received, n, ...expectedArgs) {
|
|
323
|
+
ensureSpy(received, "toHaveBeenNthCalledWith");
|
|
324
|
+
if (typeof n !== "number" || !Number.isInteger(n) || n < 1) {
|
|
325
|
+
throw new Error(this.diff(n, "toHaveBeenNthCalledWith() requires a 1-indexed integer"));
|
|
326
|
+
}
|
|
327
|
+
const call = received.mock.calls[n - 1];
|
|
328
|
+
const pass = call !== undefined && argsEqual(call, expectedArgs);
|
|
329
|
+
if (this.isNot ? pass : !pass) {
|
|
330
|
+
throw new Error(this.diff(call ?? `call #${n} not found`, expectedArgs));
|
|
331
|
+
}
|
|
332
|
+
},
|
|
333
|
+
toHaveReturned(received) {
|
|
334
|
+
ensureSpy(received, "toHaveReturned");
|
|
335
|
+
const pass = received.mock.results.some((r) => r.type === "return");
|
|
336
|
+
if (this.isNot ? pass : !pass) {
|
|
337
|
+
throw new Error(this.diff(`${received.mock.results.length} result(s)`, "at least one successful return"));
|
|
338
|
+
}
|
|
339
|
+
},
|
|
340
|
+
toHaveReturnedTimes(received, expected) {
|
|
341
|
+
ensureSpy(received, "toHaveReturnedTimes");
|
|
342
|
+
if (typeof expected !== "number" || !Number.isFinite(expected)) {
|
|
343
|
+
throw new Error(this.diff(expected, "toHaveReturnedTimes() requires a finite number"));
|
|
344
|
+
}
|
|
345
|
+
const actual = received.mock.results.filter((r) => r.type === "return").length;
|
|
346
|
+
const pass = actual === expected;
|
|
347
|
+
if (this.isNot ? pass : !pass) {
|
|
348
|
+
throw new Error(this.diff(actual, expected));
|
|
349
|
+
}
|
|
350
|
+
},
|
|
351
|
+
toHaveReturnedWith(received, expected) {
|
|
352
|
+
ensureSpy(received, "toHaveReturnedWith");
|
|
353
|
+
const pass = received.mock.results.some((r) => r.type === "return" && looseEqual(r.value, expected));
|
|
354
|
+
if (this.isNot ? pass : !pass) {
|
|
355
|
+
const returnValues = received.mock.results
|
|
356
|
+
.filter((r) => r.type === "return")
|
|
357
|
+
.map((r) => r.value);
|
|
358
|
+
throw new Error(this.diff(returnValues, expected));
|
|
359
|
+
}
|
|
360
|
+
},
|
|
361
|
+
toHaveLastReturnedWith(received, expected) {
|
|
362
|
+
ensureSpy(received, "toHaveLastReturnedWith");
|
|
363
|
+
const results = received.mock.results;
|
|
364
|
+
const last = results[results.length - 1];
|
|
365
|
+
const pass = last !== undefined &&
|
|
366
|
+
last.type === "return" &&
|
|
367
|
+
looseEqual(last.value, expected);
|
|
368
|
+
if (this.isNot ? pass : !pass) {
|
|
369
|
+
if (last === undefined) {
|
|
370
|
+
throw new Error(this.diff("no calls", expected));
|
|
371
|
+
}
|
|
372
|
+
if (last.type === "throw") {
|
|
373
|
+
throw new Error(this.diff("last call threw", expected));
|
|
374
|
+
}
|
|
375
|
+
throw new Error(this.diff(last.value, expected));
|
|
376
|
+
}
|
|
377
|
+
},
|
|
378
|
+
toHaveNthReturnedWith(received, n, expected) {
|
|
379
|
+
ensureSpy(received, "toHaveNthReturnedWith");
|
|
380
|
+
if (typeof n !== "number" || !Number.isInteger(n) || n < 1) {
|
|
381
|
+
throw new Error(this.diff(n, "toHaveNthReturnedWith() requires a 1-indexed integer"));
|
|
382
|
+
}
|
|
383
|
+
const result = received.mock.results[n - 1];
|
|
384
|
+
const pass = result !== undefined &&
|
|
385
|
+
result.type === "return" &&
|
|
386
|
+
looseEqual(result.value, expected);
|
|
387
|
+
if (this.isNot ? pass : !pass) {
|
|
388
|
+
if (result === undefined) {
|
|
389
|
+
throw new Error(this.diff(`call #${n} not found`, expected));
|
|
390
|
+
}
|
|
391
|
+
if (result.type === "throw") {
|
|
392
|
+
throw new Error(this.diff(`call #${n} threw`, expected));
|
|
393
|
+
}
|
|
394
|
+
throw new Error(this.diff(result.value, expected));
|
|
395
|
+
}
|
|
396
|
+
},
|
|
397
|
+
toHaveFetched(received, target) {
|
|
398
|
+
ensureFetchMock(received, "toHaveFetched");
|
|
399
|
+
const pass = received.calls.some((req) => matchesFetchTarget(req, target));
|
|
400
|
+
if (this.isNot ? pass : !pass) {
|
|
401
|
+
const urls = received.calls.map((r) => `${r.method} ${r.url}`);
|
|
402
|
+
throw new Error(this.diff(urls, target));
|
|
403
|
+
}
|
|
404
|
+
},
|
|
405
|
+
toHaveFetchedTimes(received, expected) {
|
|
406
|
+
ensureFetchMock(received, "toHaveFetchedTimes");
|
|
407
|
+
if (typeof expected !== "number" || !Number.isFinite(expected)) {
|
|
408
|
+
throw new Error(this.diff(expected, "toHaveFetchedTimes() requires a finite number"));
|
|
409
|
+
}
|
|
410
|
+
const actual = received.calls.length;
|
|
411
|
+
const pass = actual === expected;
|
|
412
|
+
if (this.isNot ? pass : !pass) {
|
|
413
|
+
throw new Error(this.diff(actual, expected));
|
|
414
|
+
}
|
|
415
|
+
},
|
|
222
416
|
toHaveProperty(received, path, ...rest) {
|
|
223
417
|
if (received === null || typeof received !== "object") {
|
|
224
418
|
throw new Error(this.diff(received, "expected an object for toHaveProperty()"));
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auto-mocking helpers: `mock.object` and `mock.class`.
|
|
3
|
+
*
|
|
4
|
+
* Both walk own + prototype methods and replace each function with a spy.
|
|
5
|
+
* Restoration uses the same registry as `spyOn`, so `mock.restoreAll()`
|
|
6
|
+
* cleans up auto mocks too.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Replace every method on `obj` (own + inherited, excluding Object.prototype)
|
|
10
|
+
* with a spy. Returns the same reference, mutated in place.
|
|
11
|
+
*
|
|
12
|
+
* Cleanup happens via `mock.restoreAll()` - auto-mock spies share the same
|
|
13
|
+
* restorer registry as `spyOn`.
|
|
14
|
+
*/
|
|
15
|
+
export declare function mockObject<T extends object>(obj: T): T;
|
|
16
|
+
/**
|
|
17
|
+
* Wrap a constructor so every instance is auto-mocked, and so static
|
|
18
|
+
* methods on the constructor itself are spied too. Returns a Proxy that
|
|
19
|
+
* is `instanceof`-compatible with the original.
|
|
20
|
+
*
|
|
21
|
+
* Instance methods are spied as OWN properties on each instance (shadowing
|
|
22
|
+
* the prototype), NOT by mutating the shared prototype. This keeps call
|
|
23
|
+
* state per-instance (a.run and b.run are separate spies) and leaves the
|
|
24
|
+
* class prototype untouched - nothing to restore, nothing to leak.
|
|
25
|
+
*/
|
|
26
|
+
export declare function mockClass<T extends new (...args: any[]) => any>(Ctor: T): T;
|
|
27
|
+
//# sourceMappingURL=auto.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auto.d.ts","sourceRoot":"","sources":["../../../src/mock/auto.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AA+CH;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,CAAC,SAAS,MAAM,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,CAatD;AAED;;;;;;;;;GASG;AACH,wBAAgB,SAAS,CAEvB,CAAC,SAAS,KAAK,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,EACrC,IAAI,EAAE,CAAC,GAAG,CAAC,CA8BZ"}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auto-mocking helpers: `mock.object` and `mock.class`.
|
|
3
|
+
*
|
|
4
|
+
* Both walk own + prototype methods and replace each function with a spy.
|
|
5
|
+
* Restoration uses the same registry as `spyOn`, so `mock.restoreAll()`
|
|
6
|
+
* cleans up auto mocks too.
|
|
7
|
+
*/
|
|
8
|
+
import { spy, spyOn } from "./spy.js";
|
|
9
|
+
/**
|
|
10
|
+
* Walks the chain from `target` up to (but not including) the built in
|
|
11
|
+
* `Object.prototype` and `Function.prototype`, yielding every own method
|
|
12
|
+
* key encountered. Spying on built in prototypes (`apply`, `call`, etc.)
|
|
13
|
+
* would recurse into the spy machinery itself.
|
|
14
|
+
*/
|
|
15
|
+
function* enumerableMethodKeys(target) {
|
|
16
|
+
const seen = new Set();
|
|
17
|
+
let current = target;
|
|
18
|
+
while (current &&
|
|
19
|
+
current !== Object.prototype &&
|
|
20
|
+
current !== Function.prototype) {
|
|
21
|
+
for (const key of Reflect.ownKeys(current)) {
|
|
22
|
+
if (seen.has(key))
|
|
23
|
+
continue;
|
|
24
|
+
// Skip the `constructor` property, replacing it would break
|
|
25
|
+
// `instance.constructor` checks and is rarely what callers want.
|
|
26
|
+
if (key === "constructor")
|
|
27
|
+
continue;
|
|
28
|
+
// Built in `Function` properties on a constructor we don't want to
|
|
29
|
+
// wrap (length / name are non-writable; prototype is structural).
|
|
30
|
+
if (key === "length" || key === "name" || key === "prototype")
|
|
31
|
+
continue;
|
|
32
|
+
const descriptor = Object.getOwnPropertyDescriptor(current, key);
|
|
33
|
+
if (!descriptor)
|
|
34
|
+
continue;
|
|
35
|
+
// Skip getters/setters: spyOn would invoke the getter to read the
|
|
36
|
+
// current value, which can have side effects. Track separately.
|
|
37
|
+
if (descriptor.get || descriptor.set)
|
|
38
|
+
continue;
|
|
39
|
+
if (typeof descriptor.value !== "function")
|
|
40
|
+
continue;
|
|
41
|
+
if (descriptor.configurable === false)
|
|
42
|
+
continue;
|
|
43
|
+
seen.add(key);
|
|
44
|
+
yield { host: current, key };
|
|
45
|
+
}
|
|
46
|
+
current = Object.getPrototypeOf(current);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Replace every method on `obj` (own + inherited, excluding Object.prototype)
|
|
51
|
+
* with a spy. Returns the same reference, mutated in place.
|
|
52
|
+
*
|
|
53
|
+
* Cleanup happens via `mock.restoreAll()` - auto-mock spies share the same
|
|
54
|
+
* restorer registry as `spyOn`.
|
|
55
|
+
*/
|
|
56
|
+
export function mockObject(obj) {
|
|
57
|
+
for (const { host, key } of enumerableMethodKeys(obj)) {
|
|
58
|
+
try {
|
|
59
|
+
spyOn(host, key);
|
|
60
|
+
}
|
|
61
|
+
catch {
|
|
62
|
+
/** Non-configurable properties (e.g. some built ins), skip silently.
|
|
63
|
+
* Test code targeting these would fail clearly when the spy methods
|
|
64
|
+
* aren't found. We don't want auto mock to throw on the first such key.
|
|
65
|
+
*/
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
return obj;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Wrap a constructor so every instance is auto-mocked, and so static
|
|
72
|
+
* methods on the constructor itself are spied too. Returns a Proxy that
|
|
73
|
+
* is `instanceof`-compatible with the original.
|
|
74
|
+
*
|
|
75
|
+
* Instance methods are spied as OWN properties on each instance (shadowing
|
|
76
|
+
* the prototype), NOT by mutating the shared prototype. This keeps call
|
|
77
|
+
* state per-instance (a.run and b.run are separate spies) and leaves the
|
|
78
|
+
* class prototype untouched - nothing to restore, nothing to leak.
|
|
79
|
+
*/
|
|
80
|
+
export function mockClass(Ctor) {
|
|
81
|
+
// Spy static methods on the constructor itself (mutates Ctor in place;
|
|
82
|
+
// statics are own properties of Ctor, so spyOn restores them normally).
|
|
83
|
+
mockObject(Ctor);
|
|
84
|
+
return new Proxy(Ctor, {
|
|
85
|
+
construct(target, args, newTarget) {
|
|
86
|
+
const instance = Reflect.construct(target, args, newTarget);
|
|
87
|
+
for (const { host, key } of enumerableMethodKeys(instance)) {
|
|
88
|
+
if (host === instance) {
|
|
89
|
+
// Own method (assigned in the constructor): spy in place.
|
|
90
|
+
spyOn(instance, key);
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
// Inherited method: shadow it with an own-property spy that passes
|
|
94
|
+
// through to the prototype implementation. The prototype itself is
|
|
95
|
+
// never modified.
|
|
96
|
+
const protoMethod = host[key];
|
|
97
|
+
Object.defineProperty(instance, key, {
|
|
98
|
+
value: spy(protoMethod),
|
|
99
|
+
writable: true,
|
|
100
|
+
configurable: true,
|
|
101
|
+
enumerable: false,
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return instance;
|
|
106
|
+
},
|
|
107
|
+
});
|
|
108
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `mock.fetch` - stub `globalThis.fetch` for HTTP testing.
|
|
3
|
+
*
|
|
4
|
+
* Handlers are matched against requests in registration order; the first
|
|
5
|
+
* matching handler wins. `mock.fetchOnce()` registers a single-use handler
|
|
6
|
+
* that's consumed after its first match.
|
|
7
|
+
*
|
|
8
|
+
* Restoration:
|
|
9
|
+
* - `mock.fetch.restore()` un-patches global fetch and clears handlers
|
|
10
|
+
* - `mock.restoreAll()` does the same as part of bulk cleanup
|
|
11
|
+
*/
|
|
12
|
+
/** Brand applied to `mock.fetch` so matchers can verify their received value. */
|
|
13
|
+
export declare const FETCH_MOCK_BRAND: unique symbol;
|
|
14
|
+
/**
|
|
15
|
+
* Derive WebFetch helper types from the runtime constructors so we don't
|
|
16
|
+
* have to widen the project's `lib` config to include `dom` types. These
|
|
17
|
+
* match what the platform actually accepts.
|
|
18
|
+
*/
|
|
19
|
+
type HeadersInitLike = ConstructorParameters<typeof Headers>[0];
|
|
20
|
+
type BodyInitLike = ConstructorParameters<typeof Response>[0];
|
|
21
|
+
/** What can be passed as the first argument to `mock.fetch(matcher, ...)`. */
|
|
22
|
+
export type FetchMatcher = string | RegExp | ((req: Request) => boolean | Promise<boolean>);
|
|
23
|
+
export interface MockResponseInit {
|
|
24
|
+
status?: number;
|
|
25
|
+
statusText?: string;
|
|
26
|
+
headers?: HeadersInitLike;
|
|
27
|
+
body?: BodyInitLike | null;
|
|
28
|
+
json?: unknown;
|
|
29
|
+
}
|
|
30
|
+
export type MockFetchResponse = Response | MockResponseInit | ((req: Request) => Response | MockResponseInit | Promise<Response | MockResponseInit>);
|
|
31
|
+
/**
|
|
32
|
+
* Public surface for `mock.fetch`. Callable to register a handler, with
|
|
33
|
+
* attached helpers for inspection and cleanup.
|
|
34
|
+
*/
|
|
35
|
+
export interface MockFetch {
|
|
36
|
+
(matcher: FetchMatcher, response: MockFetchResponse): void;
|
|
37
|
+
once(matcher: FetchMatcher, response: MockFetchResponse): void;
|
|
38
|
+
readonly calls: Request[];
|
|
39
|
+
reset(): void;
|
|
40
|
+
restore(): void;
|
|
41
|
+
readonly [FETCH_MOCK_BRAND]: true;
|
|
42
|
+
}
|
|
43
|
+
export declare function isFetchMock(value: unknown): value is MockFetch;
|
|
44
|
+
export declare const mockFetch: MockFetch;
|
|
45
|
+
export declare function mockFetchOnce(matcher: FetchMatcher, response: MockFetchResponse): void;
|
|
46
|
+
export {};
|
|
47
|
+
//# sourceMappingURL=fetch.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fetch.d.ts","sourceRoot":"","sources":["../../../src/mock/fetch.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAKH,iFAAiF;AACjF,eAAO,MAAM,gBAAgB,EAAE,OAAO,MAAuC,CAAC;AAE9E;;;;GAIG;AACH,KAAK,eAAe,GAAG,qBAAqB,CAAC,OAAO,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;AAChE,KAAK,YAAY,GAAG,qBAAqB,CAAC,OAAO,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;AAG9D,8EAA8E;AAC9E,MAAM,MAAM,YAAY,GACpB,MAAM,GACN,MAAM,GACN,CAAC,CAAC,GAAG,EAAE,OAAO,KAAK,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC;AAGnD,MAAM,WAAW,gBAAgB;IAC/B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,eAAe,CAAC;IAC1B,IAAI,CAAC,EAAE,YAAY,GAAG,IAAI,CAAC;IAC3B,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAGD,MAAM,MAAM,iBAAiB,GACzB,QAAQ,GACR,gBAAgB,GAChB,CAAC,CACC,GAAG,EAAE,OAAO,KACT,QAAQ,GAAG,gBAAgB,GAAG,OAAO,CAAC,QAAQ,GAAG,gBAAgB,CAAC,CAAC,CAAC;AAuI7E;;;GAGG;AACH,MAAM,WAAW,SAAS;IAExB,CAAC,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,iBAAiB,GAAG,IAAI,CAAC;IAE3D,IAAI,CAAC,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,iBAAiB,GAAG,IAAI,CAAC;IAE/D,QAAQ,CAAC,KAAK,EAAE,OAAO,EAAE,CAAC;IAE1B,KAAK,IAAI,IAAI,CAAC;IAEd,OAAO,IAAI,IAAI,CAAC;IAEhB,QAAQ,CAAC,CAAC,gBAAgB,CAAC,EAAE,IAAI,CAAC;CACnC;AAGD,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,SAAS,CAK9D;AA2BD,eAAO,MAAM,SAAS,EAAE,SAAyB,CAAC;AAElD,wBAAgB,aAAa,CAC3B,OAAO,EAAE,YAAY,EACrB,QAAQ,EAAE,iBAAiB,GAC1B,IAAI,CAEN"}
|