@juit/lib-fetch-mock 1.0.0 → 1.0.2
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/index.cjs +12 -8
- package/dist/index.cjs.map +2 -2
- package/dist/index.d.ts +24 -9
- package/dist/index.mjs +12 -14
- package/dist/index.mjs.map +2 -2
- package/package.json +2 -2
- package/src/index.ts +71 -12
package/dist/index.cjs
CHANGED
|
@@ -40,20 +40,23 @@ module.exports = __toCommonJS(src_exports);
|
|
|
40
40
|
var import_node_http = require("node:http");
|
|
41
41
|
var import_node_assert = __toESM(require("node:assert"));
|
|
42
42
|
var mockSymbol = Symbol.for("juit.fetch.mock");
|
|
43
|
-
|
|
43
|
+
process.on("exit", () => process.exit(process.exitCode));
|
|
44
|
+
var FetchMockImpl = class {
|
|
44
45
|
_handlers = [];
|
|
45
|
-
|
|
46
|
+
_fetch;
|
|
46
47
|
_baseurl;
|
|
47
48
|
constructor(baseurl) {
|
|
48
49
|
this._baseurl = new URL(baseurl || "http://test/");
|
|
49
50
|
}
|
|
50
51
|
/* === FETCH ============================================================== */
|
|
51
|
-
async
|
|
52
|
-
(0, import_node_assert.default)(this.
|
|
52
|
+
async $fetch(info, init) {
|
|
53
|
+
(0, import_node_assert.default)(this._fetch, "Global `fetch` not available (mock not enabled?)");
|
|
54
|
+
const realFetch = this._fetch;
|
|
55
|
+
const fetchWrapper = (info2, init2) => realFetch.call(globalThis, info2, init2);
|
|
53
56
|
const request = info instanceof URL || typeof info === "string" ? new Request(new URL(info, this._baseurl), init) : new Request(info, init);
|
|
54
57
|
let response = void 0;
|
|
55
58
|
for (const handler of this._handlers) {
|
|
56
|
-
const result = await handler(request,
|
|
59
|
+
const result = await handler(request, fetchWrapper);
|
|
57
60
|
if (result === void 0 || result === null)
|
|
58
61
|
continue;
|
|
59
62
|
response = typeof result === "number" ? sendStatus(result) : result;
|
|
@@ -109,8 +112,8 @@ var FetchMock = class {
|
|
|
109
112
|
return this;
|
|
110
113
|
import_node_assert.default.fail("Global `fetch` already mocked");
|
|
111
114
|
}
|
|
112
|
-
this.
|
|
113
|
-
globalThis.fetch = this.
|
|
115
|
+
this._fetch = globalThis.fetch;
|
|
116
|
+
globalThis.fetch = this.$fetch.bind(this);
|
|
114
117
|
Object.defineProperty(globalThis.fetch, mockSymbol, { value: this });
|
|
115
118
|
return this;
|
|
116
119
|
}
|
|
@@ -119,9 +122,10 @@ var FetchMock = class {
|
|
|
119
122
|
return;
|
|
120
123
|
const instance = globalThis.fetch[mockSymbol];
|
|
121
124
|
(0, import_node_assert.default)(instance === this, "Attempting to disable non-enabled mock instance");
|
|
122
|
-
globalThis.fetch = this.
|
|
125
|
+
globalThis.fetch = this._fetch;
|
|
123
126
|
}
|
|
124
127
|
};
|
|
128
|
+
var FetchMock = FetchMockImpl;
|
|
125
129
|
var Deferred = class {
|
|
126
130
|
promise;
|
|
127
131
|
resolve;
|
package/dist/index.cjs.map
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/index.ts"],
|
|
4
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,uBAA6B;AAC7B,yBAAmB;AAEnB,IAAM,aAAa,OAAO,IAAI,iBAAiB;
|
|
5
|
-
"names": ["assert"]
|
|
4
|
+
"mappings": "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",
|
|
5
|
+
"names": ["assert", "info", "init"]
|
|
6
6
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -2,19 +2,28 @@ type FetchFunction = typeof globalThis.fetch;
|
|
|
2
2
|
type FetchArguments = Parameters<FetchFunction>;
|
|
3
3
|
type FetchHandlerResult = Response | number | void | null | undefined;
|
|
4
4
|
type FetchHandler = (request: Request, fetch: FetchFunction) => FetchHandlerResult | Promise<FetchHandlerResult>;
|
|
5
|
-
export
|
|
6
|
-
|
|
7
|
-
private __fetch?;
|
|
8
|
-
private _baseurl;
|
|
9
|
-
constructor(baseurl?: string | URL | undefined);
|
|
10
|
-
private _fetch;
|
|
5
|
+
export interface FetchMock {
|
|
6
|
+
/** Handle requests a specific method and path with the specified handler callback */
|
|
11
7
|
on(method: string, path: string | RegExp, handler: FetchHandler): this;
|
|
8
|
+
/** Handle all requests with the specified handler callback */
|
|
12
9
|
handle(handler: FetchHandler): this;
|
|
13
|
-
|
|
10
|
+
/** Intercept mocked requests with an interceptor */
|
|
14
11
|
intercept(): () => Promise<DeferredRequest>;
|
|
12
|
+
/** Reset all handlers and interceptors for this instance */
|
|
13
|
+
reset(): this;
|
|
14
|
+
/** Install this instance as the global `fetch` mock handler */
|
|
15
15
|
install(): this;
|
|
16
|
+
/** Ensure that the mocked `fetch` is restored to its original value */
|
|
16
17
|
destroy(): void;
|
|
17
18
|
}
|
|
19
|
+
export interface FetchMockConstructor {
|
|
20
|
+
/**
|
|
21
|
+
* Create a new {@link FetchMock} instance, optionally resolving relative
|
|
22
|
+
* request URLs against the specified _base url_.
|
|
23
|
+
*/
|
|
24
|
+
new (baseurl?: string | URL | undefined): FetchMock;
|
|
25
|
+
}
|
|
26
|
+
export declare const FetchMock: FetchMockConstructor;
|
|
18
27
|
/**
|
|
19
28
|
* A `DeferredRequest` is an utility class deferring the `Response` sent for
|
|
20
29
|
* an _intercepted_ `Request`.
|
|
@@ -26,15 +35,21 @@ export interface DeferredRequest extends Readonly<Request> {
|
|
|
26
35
|
readonly fetch: (...args: FetchArguments) => void;
|
|
27
36
|
/** Respond to the `Request` with an optional `Response` (defaults to an empty 200 `Response`) */
|
|
28
37
|
readonly send: (response?: Response | PromiseLike<Response>) => void;
|
|
29
|
-
/** Respond to the `Request`
|
|
38
|
+
/** Respond to the `Request` with the specified status and an empty body */
|
|
30
39
|
readonly sendStatus: (status: number) => void;
|
|
31
|
-
/** Respond to the `Request`
|
|
40
|
+
/** Respond to the `Request` with the specified JSON body and an optional status */
|
|
32
41
|
readonly sendJson: (json: any, status?: number) => void;
|
|
42
|
+
/** Respond to the `Request` with the specified text body and an optional status */
|
|
33
43
|
readonly sendText: (text: string, status?: number) => void;
|
|
44
|
+
/** Respond to the `Request` with the specified binary body and an optional status */
|
|
34
45
|
readonly sendData: (data: Uint8Array, status?: number) => void;
|
|
35
46
|
}
|
|
47
|
+
/** Create a `Response` with the specified status and an empty body */
|
|
36
48
|
export declare function sendStatus(status: number, statusText?: string | undefined): Response;
|
|
49
|
+
/** Create a `Response` with the specified text body and an optional status */
|
|
37
50
|
export declare function sendText(text: string, status?: number): Response;
|
|
51
|
+
/** Create a `Response` with the specified JSON body and an optional status */
|
|
38
52
|
export declare function sendJson(data: unknown, status?: number): Response;
|
|
53
|
+
/** Create a `Response` with the specified binary body and an optional status */
|
|
39
54
|
export declare function sendData(data: Uint8Array, status?: number): Response;
|
|
40
55
|
export {};
|
package/dist/index.mjs
CHANGED
|
@@ -1,27 +1,24 @@
|
|
|
1
|
-
;const __$$_esm_paths_helper = await (async() => {
|
|
2
|
-
const __filename = (await import("node:url")).fileURLToPath(import.meta.url);
|
|
3
|
-
const __dirname = (await import("node:path")).dirname(__filename);
|
|
4
|
-
return { __filename, __dirname };
|
|
5
|
-
})();
|
|
6
|
-
|
|
7
1
|
// index.ts
|
|
8
2
|
import { STATUS_CODES } from "node:http";
|
|
9
3
|
import assert from "node:assert";
|
|
10
4
|
var mockSymbol = Symbol.for("juit.fetch.mock");
|
|
11
|
-
|
|
5
|
+
process.on("exit", () => process.exit(process.exitCode));
|
|
6
|
+
var FetchMockImpl = class {
|
|
12
7
|
_handlers = [];
|
|
13
|
-
|
|
8
|
+
_fetch;
|
|
14
9
|
_baseurl;
|
|
15
10
|
constructor(baseurl) {
|
|
16
11
|
this._baseurl = new URL(baseurl || "http://test/");
|
|
17
12
|
}
|
|
18
13
|
/* === FETCH ============================================================== */
|
|
19
|
-
async
|
|
20
|
-
assert(this.
|
|
14
|
+
async $fetch(info, init) {
|
|
15
|
+
assert(this._fetch, "Global `fetch` not available (mock not enabled?)");
|
|
16
|
+
const realFetch = this._fetch;
|
|
17
|
+
const fetchWrapper = (info2, init2) => realFetch.call(globalThis, info2, init2);
|
|
21
18
|
const request = info instanceof URL || typeof info === "string" ? new Request(new URL(info, this._baseurl), init) : new Request(info, init);
|
|
22
19
|
let response = void 0;
|
|
23
20
|
for (const handler of this._handlers) {
|
|
24
|
-
const result = await handler(request,
|
|
21
|
+
const result = await handler(request, fetchWrapper);
|
|
25
22
|
if (result === void 0 || result === null)
|
|
26
23
|
continue;
|
|
27
24
|
response = typeof result === "number" ? sendStatus(result) : result;
|
|
@@ -77,8 +74,8 @@ var FetchMock = class {
|
|
|
77
74
|
return this;
|
|
78
75
|
assert.fail("Global `fetch` already mocked");
|
|
79
76
|
}
|
|
80
|
-
this.
|
|
81
|
-
globalThis.fetch = this.
|
|
77
|
+
this._fetch = globalThis.fetch;
|
|
78
|
+
globalThis.fetch = this.$fetch.bind(this);
|
|
82
79
|
Object.defineProperty(globalThis.fetch, mockSymbol, { value: this });
|
|
83
80
|
return this;
|
|
84
81
|
}
|
|
@@ -87,9 +84,10 @@ var FetchMock = class {
|
|
|
87
84
|
return;
|
|
88
85
|
const instance = globalThis.fetch[mockSymbol];
|
|
89
86
|
assert(instance === this, "Attempting to disable non-enabled mock instance");
|
|
90
|
-
globalThis.fetch = this.
|
|
87
|
+
globalThis.fetch = this._fetch;
|
|
91
88
|
}
|
|
92
89
|
};
|
|
90
|
+
var FetchMock = FetchMockImpl;
|
|
93
91
|
var Deferred = class {
|
|
94
92
|
promise;
|
|
95
93
|
resolve;
|
package/dist/index.mjs.map
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/index.ts"],
|
|
4
|
-
"mappings": "
|
|
5
|
-
"names": []
|
|
4
|
+
"mappings": "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",
|
|
5
|
+
"names": ["info", "init"]
|
|
6
6
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@juit/lib-fetch-mock",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"description": "Easy Mocking of Node.js' own `fetch`",
|
|
5
5
|
"main": "./dist/index.cjs",
|
|
6
6
|
"module": "./dist/index.mjs",
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
"author": "Juit Developers <developers@juit.com>",
|
|
29
29
|
"license": "Apache-2.0",
|
|
30
30
|
"devDependencies": {
|
|
31
|
-
"@plugjs/build": "^0.4.
|
|
31
|
+
"@plugjs/build": "^0.4.7",
|
|
32
32
|
"typescript": "^5.0.4"
|
|
33
33
|
},
|
|
34
34
|
"files": [
|
package/src/index.ts
CHANGED
|
@@ -9,9 +9,52 @@ type FetchArguments = Parameters<FetchFunction>
|
|
|
9
9
|
type FetchHandlerResult = Response | number | void | null | undefined
|
|
10
10
|
type FetchHandler = (request: Request, fetch: FetchFunction) => FetchHandlerResult | Promise<FetchHandlerResult>
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
|
|
13
|
+
// This is an interesting bug somewhere: when using _fetch_ a number of times
|
|
14
|
+
// (the real _fetch_), some resources are left open and the testing framework
|
|
15
|
+
// never exits.
|
|
16
|
+
//
|
|
17
|
+
// ON MAC, if we only keep a _hard reference_ to resources (and to the
|
|
18
|
+
// created `Response` objects) until the tests end (see `process.on("exit")`
|
|
19
|
+
// below) then everything exits gracefully...
|
|
20
|
+
//
|
|
21
|
+
// ON LINUX, on the other hand, things simply "hang"
|
|
22
|
+
//
|
|
23
|
+
// I don't like the current "process.exit()" solution, but somehow it seems
|
|
24
|
+
// to be the only workable option across platforms...
|
|
25
|
+
process.on('exit', () => process.exit(process.exitCode))
|
|
26
|
+
|
|
27
|
+
/* ========================================================================== *
|
|
28
|
+
* FETCH MOCK IMPLEMENTATION *
|
|
29
|
+
* ========================================================================== */
|
|
30
|
+
|
|
31
|
+
export interface FetchMock {
|
|
32
|
+
/** Handle requests a specific method and path with the specified handler callback */
|
|
33
|
+
on(method: string, path: string | RegExp, handler: FetchHandler): this
|
|
34
|
+
/** Handle all requests with the specified handler callback */
|
|
35
|
+
handle(handler: FetchHandler): this
|
|
36
|
+
/** Intercept mocked requests with an interceptor */
|
|
37
|
+
intercept(): () => Promise<DeferredRequest>
|
|
38
|
+
/** Reset all handlers and interceptors for this instance */
|
|
39
|
+
reset(): this
|
|
40
|
+
|
|
41
|
+
/** Install this instance as the global `fetch` mock handler */
|
|
42
|
+
install(): this
|
|
43
|
+
/** Ensure that the mocked `fetch` is restored to its original value */
|
|
44
|
+
destroy(): void
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export interface FetchMockConstructor {
|
|
48
|
+
/**
|
|
49
|
+
* Create a new {@link FetchMock} instance, optionally resolving relative
|
|
50
|
+
* request URLs against the specified _base url_.
|
|
51
|
+
*/
|
|
52
|
+
new (baseurl?: string | URL | undefined): FetchMock
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
class FetchMockImpl implements FetchMock {
|
|
13
56
|
private _handlers: FetchHandler[] = []
|
|
14
|
-
private
|
|
57
|
+
private _fetch?: FetchFunction
|
|
15
58
|
private _baseurl: URL
|
|
16
59
|
|
|
17
60
|
constructor(baseurl?: string | URL | undefined) {
|
|
@@ -20,11 +63,21 @@ export class FetchMock {
|
|
|
20
63
|
|
|
21
64
|
/* === FETCH ============================================================== */
|
|
22
65
|
|
|
23
|
-
private async
|
|
66
|
+
private async $fetch(
|
|
24
67
|
info: URL | RequestInfo,
|
|
25
68
|
init?: RequestInit | undefined,
|
|
26
69
|
): Promise<Response> {
|
|
27
|
-
assert(this.
|
|
70
|
+
assert(this._fetch, 'Global `fetch` not available (mock not enabled?)')
|
|
71
|
+
|
|
72
|
+
// This has to do with async hooks and resources... By wrapping the real
|
|
73
|
+
// fetch, we create a new promise (a new resource) associated with the
|
|
74
|
+
// current async context... If we don't do this, sometimes, the process
|
|
75
|
+
// won't exit waiting for _something_ (dunno what, yet)!
|
|
76
|
+
const realFetch = this._fetch
|
|
77
|
+
const fetchWrapper = (
|
|
78
|
+
info: URL | RequestInfo,
|
|
79
|
+
init?: RequestInit | undefined,
|
|
80
|
+
): Promise<Response> => realFetch.call(globalThis, info, init)
|
|
28
81
|
|
|
29
82
|
const request = (info instanceof URL) || (typeof info === 'string') ?
|
|
30
83
|
new Request(new URL(info, this._baseurl), init) :
|
|
@@ -33,7 +86,7 @@ export class FetchMock {
|
|
|
33
86
|
let response: Response | undefined = undefined
|
|
34
87
|
|
|
35
88
|
for (const handler of this._handlers) {
|
|
36
|
-
const result = await handler(request,
|
|
89
|
+
const result = await handler(request, fetchWrapper)
|
|
37
90
|
if ((result === undefined) || (result === null)) continue
|
|
38
91
|
|
|
39
92
|
response = (typeof result === 'number') ? sendStatus(result) : result
|
|
@@ -104,9 +157,9 @@ export class FetchMock {
|
|
|
104
157
|
assert.fail('Global `fetch` already mocked')
|
|
105
158
|
}
|
|
106
159
|
|
|
107
|
-
this.
|
|
160
|
+
this._fetch = globalThis.fetch
|
|
108
161
|
|
|
109
|
-
globalThis.fetch = this.
|
|
162
|
+
globalThis.fetch = this.$fetch.bind(this)
|
|
110
163
|
Object.defineProperty(globalThis.fetch, mockSymbol, { value: this })
|
|
111
164
|
return this
|
|
112
165
|
}
|
|
@@ -115,10 +168,12 @@ export class FetchMock {
|
|
|
115
168
|
if (! (mockSymbol in globalThis.fetch)) return
|
|
116
169
|
const instance = (globalThis as any).fetch[mockSymbol]
|
|
117
170
|
assert(instance === this, 'Attempting to disable non-enabled mock instance')
|
|
118
|
-
globalThis.fetch = this.
|
|
171
|
+
globalThis.fetch = this._fetch!
|
|
119
172
|
}
|
|
120
173
|
}
|
|
121
174
|
|
|
175
|
+
export const FetchMock: FetchMockConstructor = FetchMockImpl
|
|
176
|
+
|
|
122
177
|
/* ========================================================================== *
|
|
123
178
|
* DEFERRED REQUESTS *
|
|
124
179
|
* ========================================================================== */
|
|
@@ -134,13 +189,13 @@ export interface DeferredRequest extends Readonly<Request> {
|
|
|
134
189
|
readonly fetch: (...args: FetchArguments) => void,
|
|
135
190
|
/** Respond to the `Request` with an optional `Response` (defaults to an empty 200 `Response`) */
|
|
136
191
|
readonly send: (response?: Response | PromiseLike<Response>) => void,
|
|
137
|
-
/** Respond to the `Request`
|
|
192
|
+
/** Respond to the `Request` with the specified status and an empty body */
|
|
138
193
|
readonly sendStatus: (status: number) => void,
|
|
139
|
-
/** Respond to the `Request`
|
|
194
|
+
/** Respond to the `Request` with the specified JSON body and an optional status */
|
|
140
195
|
readonly sendJson: (json: any, status?: number) => void,
|
|
141
|
-
|
|
196
|
+
/** Respond to the `Request` with the specified text body and an optional status */
|
|
142
197
|
readonly sendText: (text: string, status?: number) => void,
|
|
143
|
-
|
|
198
|
+
/** Respond to the `Request` with the specified binary body and an optional status */
|
|
144
199
|
readonly sendData: (data: Uint8Array, status?: number) => void,
|
|
145
200
|
}
|
|
146
201
|
|
|
@@ -209,6 +264,7 @@ class DeferredRequestImpl extends Request implements DeferredRequest {
|
|
|
209
264
|
* EASY RESPONSES *
|
|
210
265
|
* ========================================================================== */
|
|
211
266
|
|
|
267
|
+
/** Create a `Response` with the specified status and an empty body */
|
|
212
268
|
export function sendStatus(
|
|
213
269
|
status: number,
|
|
214
270
|
statusText = STATUS_CODES[status],
|
|
@@ -216,6 +272,7 @@ export function sendStatus(
|
|
|
216
272
|
return new Response(undefined, { status, statusText })
|
|
217
273
|
}
|
|
218
274
|
|
|
275
|
+
/** Create a `Response` with the specified text body and an optional status */
|
|
219
276
|
export function sendText(text: string, status = 200): Response {
|
|
220
277
|
return new Response(text, {
|
|
221
278
|
headers: { 'content-type': 'text/plain; charset=utf-8' },
|
|
@@ -224,6 +281,7 @@ export function sendText(text: string, status = 200): Response {
|
|
|
224
281
|
})
|
|
225
282
|
}
|
|
226
283
|
|
|
284
|
+
/** Create a `Response` with the specified JSON body and an optional status */
|
|
227
285
|
export function sendJson(data: unknown, status = 200): Response {
|
|
228
286
|
return new Response(JSON.stringify(data), {
|
|
229
287
|
headers: { 'content-type': 'application/json; charset=utf-8' },
|
|
@@ -232,6 +290,7 @@ export function sendJson(data: unknown, status = 200): Response {
|
|
|
232
290
|
})
|
|
233
291
|
}
|
|
234
292
|
|
|
293
|
+
/** Create a `Response` with the specified binary body and an optional status */
|
|
235
294
|
export function sendData(data: Uint8Array, status = 200): Response {
|
|
236
295
|
return new Response(data, {
|
|
237
296
|
headers: { 'content-type': 'application/octet-stream' },
|