@mswjs/interceptors 0.22.3 → 0.22.4
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/lib/browser/interceptors/XMLHttpRequest/index.js +54 -26
- package/lib/browser/interceptors/XMLHttpRequest/index.mjs +54 -26
- package/lib/browser/interceptors/fetch/index.js +20 -9
- package/lib/browser/interceptors/fetch/index.mjs +20 -9
- package/lib/node/RemoteHttpInterceptor.js +2 -2
- package/lib/node/RemoteHttpInterceptor.mjs +1 -1
- package/lib/node/{chunk-CYWTKHFI.mjs → chunk-P7NKDCFD.mjs} +54 -26
- package/lib/node/{chunk-GGD5JOGB.js → chunk-RVLLS44W.js} +54 -26
- package/lib/node/interceptors/XMLHttpRequest/index.js +2 -2
- package/lib/node/interceptors/XMLHttpRequest/index.mjs +1 -1
- package/lib/node/interceptors/fetch/index.js +20 -9
- package/lib/node/interceptors/fetch/index.mjs +20 -9
- package/package.json +2 -2
- package/src/interceptors/XMLHttpRequest/XMLHttpRequestController.ts +30 -29
- package/src/interceptors/XMLHttpRequest/XMLHttpRequestProxy.ts +20 -2
- package/src/interceptors/XMLHttpRequest/utils/createResponse.ts +1 -1
- package/src/interceptors/fetch/index.ts +22 -9
- package/src/utils/createProxy.test.ts +149 -0
- package/src/utils/createProxy.ts +27 -6
|
@@ -121,12 +121,28 @@ function optionsToProxyHandler(options) {
|
|
|
121
121
|
return constructorCall.call(newTarget, args, next);
|
|
122
122
|
};
|
|
123
123
|
}
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
const
|
|
127
|
-
|
|
124
|
+
handler.set = function(target, propertyName, nextValue, receiver) {
|
|
125
|
+
const next = () => {
|
|
126
|
+
const ownDescriptors = Reflect.getOwnPropertyDescriptor(
|
|
127
|
+
target,
|
|
128
|
+
propertyName
|
|
129
|
+
);
|
|
130
|
+
if (typeof (ownDescriptors == null ? void 0 : ownDescriptors.set) !== "undefined") {
|
|
131
|
+
ownDescriptors.set.apply(target, [nextValue]);
|
|
132
|
+
return true;
|
|
133
|
+
}
|
|
134
|
+
return Reflect.defineProperty(target, propertyName, {
|
|
135
|
+
writable: true,
|
|
136
|
+
enumerable: true,
|
|
137
|
+
configurable: true,
|
|
138
|
+
value: nextValue
|
|
139
|
+
});
|
|
128
140
|
};
|
|
129
|
-
|
|
141
|
+
if (typeof setProperty !== "undefined") {
|
|
142
|
+
return setProperty.call(target, [propertyName, nextValue], next);
|
|
143
|
+
}
|
|
144
|
+
return next();
|
|
145
|
+
};
|
|
130
146
|
handler.get = function(target, propertyName, receiver) {
|
|
131
147
|
const next = () => target[propertyName];
|
|
132
148
|
const value = typeof getProperty !== "undefined" ? getProperty.call(target, [propertyName, receiver], next) : next();
|
|
@@ -191,11 +207,25 @@ var XMLHttpRequestController = class {
|
|
|
191
207
|
this.responseBuffer = new Uint8Array();
|
|
192
208
|
this.request = createProxy(initialRequest, {
|
|
193
209
|
setProperty: ([propertyName, nextValue], invoke) => {
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
210
|
+
switch (propertyName) {
|
|
211
|
+
case "onabort":
|
|
212
|
+
case "onerror":
|
|
213
|
+
case "onload":
|
|
214
|
+
case "onloadend":
|
|
215
|
+
case "onloadstart":
|
|
216
|
+
case "onprogress":
|
|
217
|
+
case "ontimeout":
|
|
218
|
+
case "onreadystatechange": {
|
|
219
|
+
const eventName = propertyName.slice(
|
|
220
|
+
2
|
|
221
|
+
);
|
|
222
|
+
this.request.addEventListener(eventName, nextValue);
|
|
223
|
+
return invoke();
|
|
224
|
+
}
|
|
225
|
+
default: {
|
|
226
|
+
return invoke();
|
|
227
|
+
}
|
|
197
228
|
}
|
|
198
|
-
return invoke();
|
|
199
229
|
},
|
|
200
230
|
methodCall: ([methodName, args], invoke) => {
|
|
201
231
|
var _a;
|
|
@@ -259,21 +289,6 @@ var XMLHttpRequestController = class {
|
|
|
259
289
|
});
|
|
260
290
|
break;
|
|
261
291
|
}
|
|
262
|
-
case "onabort":
|
|
263
|
-
case "onerror":
|
|
264
|
-
case "onload":
|
|
265
|
-
case "onloadend":
|
|
266
|
-
case "onloadstart":
|
|
267
|
-
case "onprogress":
|
|
268
|
-
case "ontimeout":
|
|
269
|
-
case "onreadystatechange": {
|
|
270
|
-
const [listener] = args;
|
|
271
|
-
this.registerEvent(
|
|
272
|
-
methodName,
|
|
273
|
-
listener
|
|
274
|
-
);
|
|
275
|
-
return invoke();
|
|
276
|
-
}
|
|
277
292
|
default: {
|
|
278
293
|
return invoke();
|
|
279
294
|
}
|
|
@@ -326,14 +341,17 @@ var XMLHttpRequestController = class {
|
|
|
326
341
|
Object.defineProperties(this.request, {
|
|
327
342
|
response: {
|
|
328
343
|
enumerable: true,
|
|
344
|
+
configurable: false,
|
|
329
345
|
get: () => this.response
|
|
330
346
|
},
|
|
331
347
|
responseText: {
|
|
332
348
|
enumerable: true,
|
|
349
|
+
configurable: false,
|
|
333
350
|
get: () => this.responseText
|
|
334
351
|
},
|
|
335
352
|
responseXML: {
|
|
336
353
|
enumerable: true,
|
|
354
|
+
configurable: false,
|
|
337
355
|
get: () => this.responseXML
|
|
338
356
|
}
|
|
339
357
|
});
|
|
@@ -547,9 +565,19 @@ function createXMLHttpRequestProxy({
|
|
|
547
565
|
log
|
|
548
566
|
}) {
|
|
549
567
|
const XMLHttpRequestProxy = new Proxy(globalThis.XMLHttpRequest, {
|
|
550
|
-
construct(target, args) {
|
|
568
|
+
construct(target, args, newTarget) {
|
|
551
569
|
log("constructed new XMLHttpRequest");
|
|
552
|
-
const originalRequest = Reflect.construct(target, args);
|
|
570
|
+
const originalRequest = Reflect.construct(target, args, newTarget);
|
|
571
|
+
const prototypeDescriptors = Object.getOwnPropertyDescriptors(
|
|
572
|
+
target.prototype
|
|
573
|
+
);
|
|
574
|
+
for (const propertyName in prototypeDescriptors) {
|
|
575
|
+
Reflect.defineProperty(
|
|
576
|
+
originalRequest,
|
|
577
|
+
propertyName,
|
|
578
|
+
prototypeDescriptors[propertyName]
|
|
579
|
+
);
|
|
580
|
+
}
|
|
553
581
|
const requestController = new XMLHttpRequestController(
|
|
554
582
|
originalRequest,
|
|
555
583
|
log
|
|
@@ -121,12 +121,28 @@ function optionsToProxyHandler(options) {
|
|
|
121
121
|
return constructorCall.call(newTarget, args, next);
|
|
122
122
|
};
|
|
123
123
|
}
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
const
|
|
127
|
-
|
|
124
|
+
handler.set = function(target, propertyName, nextValue, receiver) {
|
|
125
|
+
const next = () => {
|
|
126
|
+
const ownDescriptors = Reflect.getOwnPropertyDescriptor(
|
|
127
|
+
target,
|
|
128
|
+
propertyName
|
|
129
|
+
);
|
|
130
|
+
if (typeof (ownDescriptors == null ? void 0 : ownDescriptors.set) !== "undefined") {
|
|
131
|
+
ownDescriptors.set.apply(target, [nextValue]);
|
|
132
|
+
return true;
|
|
133
|
+
}
|
|
134
|
+
return Reflect.defineProperty(target, propertyName, {
|
|
135
|
+
writable: true,
|
|
136
|
+
enumerable: true,
|
|
137
|
+
configurable: true,
|
|
138
|
+
value: nextValue
|
|
139
|
+
});
|
|
128
140
|
};
|
|
129
|
-
|
|
141
|
+
if (typeof setProperty !== "undefined") {
|
|
142
|
+
return setProperty.call(target, [propertyName, nextValue], next);
|
|
143
|
+
}
|
|
144
|
+
return next();
|
|
145
|
+
};
|
|
130
146
|
handler.get = function(target, propertyName, receiver) {
|
|
131
147
|
const next = () => target[propertyName];
|
|
132
148
|
const value = typeof getProperty !== "undefined" ? getProperty.call(target, [propertyName, receiver], next) : next();
|
|
@@ -191,11 +207,25 @@ var XMLHttpRequestController = class {
|
|
|
191
207
|
this.responseBuffer = new Uint8Array();
|
|
192
208
|
this.request = createProxy(initialRequest, {
|
|
193
209
|
setProperty: ([propertyName, nextValue], invoke) => {
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
210
|
+
switch (propertyName) {
|
|
211
|
+
case "onabort":
|
|
212
|
+
case "onerror":
|
|
213
|
+
case "onload":
|
|
214
|
+
case "onloadend":
|
|
215
|
+
case "onloadstart":
|
|
216
|
+
case "onprogress":
|
|
217
|
+
case "ontimeout":
|
|
218
|
+
case "onreadystatechange": {
|
|
219
|
+
const eventName = propertyName.slice(
|
|
220
|
+
2
|
|
221
|
+
);
|
|
222
|
+
this.request.addEventListener(eventName, nextValue);
|
|
223
|
+
return invoke();
|
|
224
|
+
}
|
|
225
|
+
default: {
|
|
226
|
+
return invoke();
|
|
227
|
+
}
|
|
197
228
|
}
|
|
198
|
-
return invoke();
|
|
199
229
|
},
|
|
200
230
|
methodCall: ([methodName, args], invoke) => {
|
|
201
231
|
var _a;
|
|
@@ -259,21 +289,6 @@ var XMLHttpRequestController = class {
|
|
|
259
289
|
});
|
|
260
290
|
break;
|
|
261
291
|
}
|
|
262
|
-
case "onabort":
|
|
263
|
-
case "onerror":
|
|
264
|
-
case "onload":
|
|
265
|
-
case "onloadend":
|
|
266
|
-
case "onloadstart":
|
|
267
|
-
case "onprogress":
|
|
268
|
-
case "ontimeout":
|
|
269
|
-
case "onreadystatechange": {
|
|
270
|
-
const [listener] = args;
|
|
271
|
-
this.registerEvent(
|
|
272
|
-
methodName,
|
|
273
|
-
listener
|
|
274
|
-
);
|
|
275
|
-
return invoke();
|
|
276
|
-
}
|
|
277
292
|
default: {
|
|
278
293
|
return invoke();
|
|
279
294
|
}
|
|
@@ -326,14 +341,17 @@ var XMLHttpRequestController = class {
|
|
|
326
341
|
Object.defineProperties(this.request, {
|
|
327
342
|
response: {
|
|
328
343
|
enumerable: true,
|
|
344
|
+
configurable: false,
|
|
329
345
|
get: () => this.response
|
|
330
346
|
},
|
|
331
347
|
responseText: {
|
|
332
348
|
enumerable: true,
|
|
349
|
+
configurable: false,
|
|
333
350
|
get: () => this.responseText
|
|
334
351
|
},
|
|
335
352
|
responseXML: {
|
|
336
353
|
enumerable: true,
|
|
354
|
+
configurable: false,
|
|
337
355
|
get: () => this.responseXML
|
|
338
356
|
}
|
|
339
357
|
});
|
|
@@ -547,9 +565,19 @@ function createXMLHttpRequestProxy({
|
|
|
547
565
|
log
|
|
548
566
|
}) {
|
|
549
567
|
const XMLHttpRequestProxy = new Proxy(globalThis.XMLHttpRequest, {
|
|
550
|
-
construct(target, args) {
|
|
568
|
+
construct(target, args, newTarget) {
|
|
551
569
|
log("constructed new XMLHttpRequest");
|
|
552
|
-
const originalRequest = Reflect.construct(target, args);
|
|
570
|
+
const originalRequest = Reflect.construct(target, args, newTarget);
|
|
571
|
+
const prototypeDescriptors = Object.getOwnPropertyDescriptors(
|
|
572
|
+
target.prototype
|
|
573
|
+
);
|
|
574
|
+
for (const propertyName in prototypeDescriptors) {
|
|
575
|
+
Reflect.defineProperty(
|
|
576
|
+
originalRequest,
|
|
577
|
+
propertyName,
|
|
578
|
+
prototypeDescriptors[propertyName]
|
|
579
|
+
);
|
|
580
|
+
}
|
|
553
581
|
const requestController = new XMLHttpRequestController(
|
|
554
582
|
originalRequest,
|
|
555
583
|
log
|
|
@@ -9,6 +9,7 @@ var _chunkQWL3EOEYjs = require('../../chunk-QWL3EOEY.js');
|
|
|
9
9
|
|
|
10
10
|
// src/interceptors/fetch/index.ts
|
|
11
11
|
var _outvariant = require('outvariant');
|
|
12
|
+
var _until = require('@open-draft/until');
|
|
12
13
|
var _FetchInterceptor = class extends _chunkQWL3EOEYjs.Interceptor {
|
|
13
14
|
constructor() {
|
|
14
15
|
super(_FetchInterceptor.symbol);
|
|
@@ -33,15 +34,25 @@ var _FetchInterceptor = class extends _chunkQWL3EOEYjs.Interceptor {
|
|
|
33
34
|
);
|
|
34
35
|
this.emitter.emit("request", interactiveRequest, requestId);
|
|
35
36
|
this.log("awaiting for the mocked response...");
|
|
36
|
-
await
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
37
|
+
const [middlewareException, mockedResponse] = await _until.until.call(void 0, async () => {
|
|
38
|
+
await this.emitter.untilIdle(
|
|
39
|
+
"request",
|
|
40
|
+
({ args: [, pendingRequestId] }) => {
|
|
41
|
+
return pendingRequestId === requestId;
|
|
42
|
+
}
|
|
43
|
+
);
|
|
44
|
+
this.log("all request listeners have been resolved!");
|
|
45
|
+
const [mockedResponse2] = await interactiveRequest.respondWith.invoked();
|
|
46
|
+
this.log("event.respondWith called with:", mockedResponse2);
|
|
47
|
+
return mockedResponse2;
|
|
48
|
+
});
|
|
49
|
+
if (middlewareException) {
|
|
50
|
+
console.error(`${request.method} ${request.url} net::ERR_FAILED`);
|
|
51
|
+
const error = Object.assign(new TypeError("Failed to fetch"), {
|
|
52
|
+
cause: middlewareException
|
|
53
|
+
});
|
|
54
|
+
return Promise.reject(error);
|
|
55
|
+
}
|
|
45
56
|
if (mockedResponse) {
|
|
46
57
|
this.log("received mocked response:", mockedResponse);
|
|
47
58
|
const responseCloine = mockedResponse.clone();
|
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
|
|
10
10
|
// src/interceptors/fetch/index.ts
|
|
11
11
|
import { invariant } from "outvariant";
|
|
12
|
+
import { until } from "@open-draft/until";
|
|
12
13
|
var _FetchInterceptor = class extends Interceptor {
|
|
13
14
|
constructor() {
|
|
14
15
|
super(_FetchInterceptor.symbol);
|
|
@@ -33,15 +34,25 @@ var _FetchInterceptor = class extends Interceptor {
|
|
|
33
34
|
);
|
|
34
35
|
this.emitter.emit("request", interactiveRequest, requestId);
|
|
35
36
|
this.log("awaiting for the mocked response...");
|
|
36
|
-
await
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
37
|
+
const [middlewareException, mockedResponse] = await until(async () => {
|
|
38
|
+
await this.emitter.untilIdle(
|
|
39
|
+
"request",
|
|
40
|
+
({ args: [, pendingRequestId] }) => {
|
|
41
|
+
return pendingRequestId === requestId;
|
|
42
|
+
}
|
|
43
|
+
);
|
|
44
|
+
this.log("all request listeners have been resolved!");
|
|
45
|
+
const [mockedResponse2] = await interactiveRequest.respondWith.invoked();
|
|
46
|
+
this.log("event.respondWith called with:", mockedResponse2);
|
|
47
|
+
return mockedResponse2;
|
|
48
|
+
});
|
|
49
|
+
if (middlewareException) {
|
|
50
|
+
console.error(`${request.method} ${request.url} net::ERR_FAILED`);
|
|
51
|
+
const error = Object.assign(new TypeError("Failed to fetch"), {
|
|
52
|
+
cause: middlewareException
|
|
53
|
+
});
|
|
54
|
+
return Promise.reject(error);
|
|
55
|
+
}
|
|
45
56
|
if (mockedResponse) {
|
|
46
57
|
this.log("received mocked response:", mockedResponse);
|
|
47
58
|
const responseCloine = mockedResponse.clone();
|
|
@@ -6,7 +6,7 @@ var _chunkQ56TMOP5js = require('./chunk-Q56TMOP5.js');
|
|
|
6
6
|
var _chunkXLZJAPVSjs = require('./chunk-XLZJAPVS.js');
|
|
7
7
|
|
|
8
8
|
|
|
9
|
-
var
|
|
9
|
+
var _chunkRVLLS44Wjs = require('./chunk-RVLLS44W.js');
|
|
10
10
|
require('./chunk-SNNL2EXF.js');
|
|
11
11
|
require('./chunk-VQ4DZOBB.js');
|
|
12
12
|
|
|
@@ -24,7 +24,7 @@ var RemoteHttpInterceptor = class extends _chunkQ56TMOP5js.BatchInterceptor {
|
|
|
24
24
|
name: "remote-interceptor",
|
|
25
25
|
interceptors: [
|
|
26
26
|
new (0, _chunkXLZJAPVSjs.ClientRequestInterceptor)(),
|
|
27
|
-
new (0,
|
|
27
|
+
new (0, _chunkRVLLS44Wjs.XMLHttpRequestInterceptor)()
|
|
28
28
|
]
|
|
29
29
|
});
|
|
30
30
|
}
|
|
@@ -123,12 +123,28 @@ function optionsToProxyHandler(options) {
|
|
|
123
123
|
return constructorCall.call(newTarget, args, next);
|
|
124
124
|
};
|
|
125
125
|
}
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
const
|
|
129
|
-
|
|
126
|
+
handler.set = function(target, propertyName, nextValue, receiver) {
|
|
127
|
+
const next = () => {
|
|
128
|
+
const ownDescriptors = Reflect.getOwnPropertyDescriptor(
|
|
129
|
+
target,
|
|
130
|
+
propertyName
|
|
131
|
+
);
|
|
132
|
+
if (typeof (ownDescriptors == null ? void 0 : ownDescriptors.set) !== "undefined") {
|
|
133
|
+
ownDescriptors.set.apply(target, [nextValue]);
|
|
134
|
+
return true;
|
|
135
|
+
}
|
|
136
|
+
return Reflect.defineProperty(target, propertyName, {
|
|
137
|
+
writable: true,
|
|
138
|
+
enumerable: true,
|
|
139
|
+
configurable: true,
|
|
140
|
+
value: nextValue
|
|
141
|
+
});
|
|
130
142
|
};
|
|
131
|
-
|
|
143
|
+
if (typeof setProperty !== "undefined") {
|
|
144
|
+
return setProperty.call(target, [propertyName, nextValue], next);
|
|
145
|
+
}
|
|
146
|
+
return next();
|
|
147
|
+
};
|
|
132
148
|
handler.get = function(target, propertyName, receiver) {
|
|
133
149
|
const next = () => target[propertyName];
|
|
134
150
|
const value = typeof getProperty !== "undefined" ? getProperty.call(target, [propertyName, receiver], next) : next();
|
|
@@ -193,11 +209,25 @@ var XMLHttpRequestController = class {
|
|
|
193
209
|
this.responseBuffer = new Uint8Array();
|
|
194
210
|
this.request = createProxy(initialRequest, {
|
|
195
211
|
setProperty: ([propertyName, nextValue], invoke) => {
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
212
|
+
switch (propertyName) {
|
|
213
|
+
case "onabort":
|
|
214
|
+
case "onerror":
|
|
215
|
+
case "onload":
|
|
216
|
+
case "onloadend":
|
|
217
|
+
case "onloadstart":
|
|
218
|
+
case "onprogress":
|
|
219
|
+
case "ontimeout":
|
|
220
|
+
case "onreadystatechange": {
|
|
221
|
+
const eventName = propertyName.slice(
|
|
222
|
+
2
|
|
223
|
+
);
|
|
224
|
+
this.request.addEventListener(eventName, nextValue);
|
|
225
|
+
return invoke();
|
|
226
|
+
}
|
|
227
|
+
default: {
|
|
228
|
+
return invoke();
|
|
229
|
+
}
|
|
199
230
|
}
|
|
200
|
-
return invoke();
|
|
201
231
|
},
|
|
202
232
|
methodCall: ([methodName, args], invoke) => {
|
|
203
233
|
var _a;
|
|
@@ -261,21 +291,6 @@ var XMLHttpRequestController = class {
|
|
|
261
291
|
});
|
|
262
292
|
break;
|
|
263
293
|
}
|
|
264
|
-
case "onabort":
|
|
265
|
-
case "onerror":
|
|
266
|
-
case "onload":
|
|
267
|
-
case "onloadend":
|
|
268
|
-
case "onloadstart":
|
|
269
|
-
case "onprogress":
|
|
270
|
-
case "ontimeout":
|
|
271
|
-
case "onreadystatechange": {
|
|
272
|
-
const [listener] = args;
|
|
273
|
-
this.registerEvent(
|
|
274
|
-
methodName,
|
|
275
|
-
listener
|
|
276
|
-
);
|
|
277
|
-
return invoke();
|
|
278
|
-
}
|
|
279
294
|
default: {
|
|
280
295
|
return invoke();
|
|
281
296
|
}
|
|
@@ -328,14 +343,17 @@ var XMLHttpRequestController = class {
|
|
|
328
343
|
Object.defineProperties(this.request, {
|
|
329
344
|
response: {
|
|
330
345
|
enumerable: true,
|
|
346
|
+
configurable: false,
|
|
331
347
|
get: () => this.response
|
|
332
348
|
},
|
|
333
349
|
responseText: {
|
|
334
350
|
enumerable: true,
|
|
351
|
+
configurable: false,
|
|
335
352
|
get: () => this.responseText
|
|
336
353
|
},
|
|
337
354
|
responseXML: {
|
|
338
355
|
enumerable: true,
|
|
356
|
+
configurable: false,
|
|
339
357
|
get: () => this.responseXML
|
|
340
358
|
}
|
|
341
359
|
});
|
|
@@ -549,9 +567,19 @@ function createXMLHttpRequestProxy({
|
|
|
549
567
|
log
|
|
550
568
|
}) {
|
|
551
569
|
const XMLHttpRequestProxy = new Proxy(globalThis.XMLHttpRequest, {
|
|
552
|
-
construct(target, args) {
|
|
570
|
+
construct(target, args, newTarget) {
|
|
553
571
|
log("constructed new XMLHttpRequest");
|
|
554
|
-
const originalRequest = Reflect.construct(target, args);
|
|
572
|
+
const originalRequest = Reflect.construct(target, args, newTarget);
|
|
573
|
+
const prototypeDescriptors = Object.getOwnPropertyDescriptors(
|
|
574
|
+
target.prototype
|
|
575
|
+
);
|
|
576
|
+
for (const propertyName in prototypeDescriptors) {
|
|
577
|
+
Reflect.defineProperty(
|
|
578
|
+
originalRequest,
|
|
579
|
+
propertyName,
|
|
580
|
+
prototypeDescriptors[propertyName]
|
|
581
|
+
);
|
|
582
|
+
}
|
|
555
583
|
const requestController = new XMLHttpRequestController(
|
|
556
584
|
originalRequest,
|
|
557
585
|
log
|
|
@@ -123,12 +123,28 @@ function optionsToProxyHandler(options) {
|
|
|
123
123
|
return constructorCall.call(newTarget, args, next);
|
|
124
124
|
};
|
|
125
125
|
}
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
const
|
|
129
|
-
|
|
126
|
+
handler.set = function(target, propertyName, nextValue, receiver) {
|
|
127
|
+
const next = () => {
|
|
128
|
+
const ownDescriptors = Reflect.getOwnPropertyDescriptor(
|
|
129
|
+
target,
|
|
130
|
+
propertyName
|
|
131
|
+
);
|
|
132
|
+
if (typeof (ownDescriptors == null ? void 0 : ownDescriptors.set) !== "undefined") {
|
|
133
|
+
ownDescriptors.set.apply(target, [nextValue]);
|
|
134
|
+
return true;
|
|
135
|
+
}
|
|
136
|
+
return Reflect.defineProperty(target, propertyName, {
|
|
137
|
+
writable: true,
|
|
138
|
+
enumerable: true,
|
|
139
|
+
configurable: true,
|
|
140
|
+
value: nextValue
|
|
141
|
+
});
|
|
130
142
|
};
|
|
131
|
-
|
|
143
|
+
if (typeof setProperty !== "undefined") {
|
|
144
|
+
return setProperty.call(target, [propertyName, nextValue], next);
|
|
145
|
+
}
|
|
146
|
+
return next();
|
|
147
|
+
};
|
|
132
148
|
handler.get = function(target, propertyName, receiver) {
|
|
133
149
|
const next = () => target[propertyName];
|
|
134
150
|
const value = typeof getProperty !== "undefined" ? getProperty.call(target, [propertyName, receiver], next) : next();
|
|
@@ -193,11 +209,25 @@ var XMLHttpRequestController = class {
|
|
|
193
209
|
this.responseBuffer = new Uint8Array();
|
|
194
210
|
this.request = createProxy(initialRequest, {
|
|
195
211
|
setProperty: ([propertyName, nextValue], invoke) => {
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
212
|
+
switch (propertyName) {
|
|
213
|
+
case "onabort":
|
|
214
|
+
case "onerror":
|
|
215
|
+
case "onload":
|
|
216
|
+
case "onloadend":
|
|
217
|
+
case "onloadstart":
|
|
218
|
+
case "onprogress":
|
|
219
|
+
case "ontimeout":
|
|
220
|
+
case "onreadystatechange": {
|
|
221
|
+
const eventName = propertyName.slice(
|
|
222
|
+
2
|
|
223
|
+
);
|
|
224
|
+
this.request.addEventListener(eventName, nextValue);
|
|
225
|
+
return invoke();
|
|
226
|
+
}
|
|
227
|
+
default: {
|
|
228
|
+
return invoke();
|
|
229
|
+
}
|
|
199
230
|
}
|
|
200
|
-
return invoke();
|
|
201
231
|
},
|
|
202
232
|
methodCall: ([methodName, args], invoke) => {
|
|
203
233
|
var _a;
|
|
@@ -261,21 +291,6 @@ var XMLHttpRequestController = class {
|
|
|
261
291
|
});
|
|
262
292
|
break;
|
|
263
293
|
}
|
|
264
|
-
case "onabort":
|
|
265
|
-
case "onerror":
|
|
266
|
-
case "onload":
|
|
267
|
-
case "onloadend":
|
|
268
|
-
case "onloadstart":
|
|
269
|
-
case "onprogress":
|
|
270
|
-
case "ontimeout":
|
|
271
|
-
case "onreadystatechange": {
|
|
272
|
-
const [listener] = args;
|
|
273
|
-
this.registerEvent(
|
|
274
|
-
methodName,
|
|
275
|
-
listener
|
|
276
|
-
);
|
|
277
|
-
return invoke();
|
|
278
|
-
}
|
|
279
294
|
default: {
|
|
280
295
|
return invoke();
|
|
281
296
|
}
|
|
@@ -328,14 +343,17 @@ var XMLHttpRequestController = class {
|
|
|
328
343
|
Object.defineProperties(this.request, {
|
|
329
344
|
response: {
|
|
330
345
|
enumerable: true,
|
|
346
|
+
configurable: false,
|
|
331
347
|
get: () => this.response
|
|
332
348
|
},
|
|
333
349
|
responseText: {
|
|
334
350
|
enumerable: true,
|
|
351
|
+
configurable: false,
|
|
335
352
|
get: () => this.responseText
|
|
336
353
|
},
|
|
337
354
|
responseXML: {
|
|
338
355
|
enumerable: true,
|
|
356
|
+
configurable: false,
|
|
339
357
|
get: () => this.responseXML
|
|
340
358
|
}
|
|
341
359
|
});
|
|
@@ -549,9 +567,19 @@ function createXMLHttpRequestProxy({
|
|
|
549
567
|
log
|
|
550
568
|
}) {
|
|
551
569
|
const XMLHttpRequestProxy = new Proxy(globalThis.XMLHttpRequest, {
|
|
552
|
-
construct(target, args) {
|
|
570
|
+
construct(target, args, newTarget) {
|
|
553
571
|
log("constructed new XMLHttpRequest");
|
|
554
|
-
const originalRequest = Reflect.construct(target, args);
|
|
572
|
+
const originalRequest = Reflect.construct(target, args, newTarget);
|
|
573
|
+
const prototypeDescriptors = Object.getOwnPropertyDescriptors(
|
|
574
|
+
target.prototype
|
|
575
|
+
);
|
|
576
|
+
for (const propertyName in prototypeDescriptors) {
|
|
577
|
+
Reflect.defineProperty(
|
|
578
|
+
originalRequest,
|
|
579
|
+
propertyName,
|
|
580
|
+
prototypeDescriptors[propertyName]
|
|
581
|
+
);
|
|
582
|
+
}
|
|
555
583
|
const requestController = new XMLHttpRequestController(
|
|
556
584
|
originalRequest,
|
|
557
585
|
log
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
"use strict";Object.defineProperty(exports, "__esModule", {value: true});
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var _chunkRVLLS44Wjs = require('../../chunk-RVLLS44W.js');
|
|
4
4
|
require('../../chunk-SNNL2EXF.js');
|
|
5
5
|
require('../../chunk-VQ4DZOBB.js');
|
|
6
6
|
require('../../chunk-ZJOF5MEZ.js');
|
|
7
7
|
require('../../chunk-WWHITCCI.js');
|
|
8
8
|
|
|
9
9
|
|
|
10
|
-
exports.XMLHttpRequestInterceptor =
|
|
10
|
+
exports.XMLHttpRequestInterceptor = _chunkRVLLS44Wjs.XMLHttpRequestInterceptor;
|
|
@@ -11,6 +11,7 @@ var _chunkWWHITCCIjs = require('../../chunk-WWHITCCI.js');
|
|
|
11
11
|
|
|
12
12
|
// src/interceptors/fetch/index.ts
|
|
13
13
|
var _outvariant = require('outvariant');
|
|
14
|
+
var _until = require('@open-draft/until');
|
|
14
15
|
var _FetchInterceptor = class extends _chunkWWHITCCIjs.Interceptor {
|
|
15
16
|
constructor() {
|
|
16
17
|
super(_FetchInterceptor.symbol);
|
|
@@ -35,15 +36,25 @@ var _FetchInterceptor = class extends _chunkWWHITCCIjs.Interceptor {
|
|
|
35
36
|
);
|
|
36
37
|
this.emitter.emit("request", interactiveRequest, requestId);
|
|
37
38
|
this.log("awaiting for the mocked response...");
|
|
38
|
-
await
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
39
|
+
const [middlewareException, mockedResponse] = await _until.until.call(void 0, async () => {
|
|
40
|
+
await this.emitter.untilIdle(
|
|
41
|
+
"request",
|
|
42
|
+
({ args: [, pendingRequestId] }) => {
|
|
43
|
+
return pendingRequestId === requestId;
|
|
44
|
+
}
|
|
45
|
+
);
|
|
46
|
+
this.log("all request listeners have been resolved!");
|
|
47
|
+
const [mockedResponse2] = await interactiveRequest.respondWith.invoked();
|
|
48
|
+
this.log("event.respondWith called with:", mockedResponse2);
|
|
49
|
+
return mockedResponse2;
|
|
50
|
+
});
|
|
51
|
+
if (middlewareException) {
|
|
52
|
+
console.error(`${request.method} ${request.url} net::ERR_FAILED`);
|
|
53
|
+
const error = Object.assign(new TypeError("Failed to fetch"), {
|
|
54
|
+
cause: middlewareException
|
|
55
|
+
});
|
|
56
|
+
return Promise.reject(error);
|
|
57
|
+
}
|
|
47
58
|
if (mockedResponse) {
|
|
48
59
|
this.log("received mocked response:", mockedResponse);
|
|
49
60
|
const responseCloine = mockedResponse.clone();
|
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
|
|
12
12
|
// src/interceptors/fetch/index.ts
|
|
13
13
|
import { invariant } from "outvariant";
|
|
14
|
+
import { until } from "@open-draft/until";
|
|
14
15
|
var _FetchInterceptor = class extends Interceptor {
|
|
15
16
|
constructor() {
|
|
16
17
|
super(_FetchInterceptor.symbol);
|
|
@@ -35,15 +36,25 @@ var _FetchInterceptor = class extends Interceptor {
|
|
|
35
36
|
);
|
|
36
37
|
this.emitter.emit("request", interactiveRequest, requestId);
|
|
37
38
|
this.log("awaiting for the mocked response...");
|
|
38
|
-
await
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
39
|
+
const [middlewareException, mockedResponse] = await until(async () => {
|
|
40
|
+
await this.emitter.untilIdle(
|
|
41
|
+
"request",
|
|
42
|
+
({ args: [, pendingRequestId] }) => {
|
|
43
|
+
return pendingRequestId === requestId;
|
|
44
|
+
}
|
|
45
|
+
);
|
|
46
|
+
this.log("all request listeners have been resolved!");
|
|
47
|
+
const [mockedResponse2] = await interactiveRequest.respondWith.invoked();
|
|
48
|
+
this.log("event.respondWith called with:", mockedResponse2);
|
|
49
|
+
return mockedResponse2;
|
|
50
|
+
});
|
|
51
|
+
if (middlewareException) {
|
|
52
|
+
console.error(`${request.method} ${request.url} net::ERR_FAILED`);
|
|
53
|
+
const error = Object.assign(new TypeError("Failed to fetch"), {
|
|
54
|
+
cause: middlewareException
|
|
55
|
+
});
|
|
56
|
+
return Promise.reject(error);
|
|
57
|
+
}
|
|
47
58
|
if (mockedResponse) {
|
|
48
59
|
this.log("received mocked response:", mockedResponse);
|
|
49
60
|
const responseCloine = mockedResponse.clone();
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mswjs/interceptors",
|
|
3
3
|
"description": "Low-level HTTP/HTTPS/XHR/fetch request interception library.",
|
|
4
|
-
"version": "0.22.
|
|
4
|
+
"version": "0.22.4",
|
|
5
5
|
"main": "./lib/node/index.js",
|
|
6
6
|
"module": "./lib/node/index.mjs",
|
|
7
7
|
"types": "./lib/node/index.d.ts",
|
|
@@ -85,7 +85,7 @@
|
|
|
85
85
|
"devDependencies": {
|
|
86
86
|
"@commitlint/cli": "^16.0.2",
|
|
87
87
|
"@commitlint/config-conventional": "^16.0.0",
|
|
88
|
-
"@open-draft/test-server": "^0.
|
|
88
|
+
"@open-draft/test-server": "^0.5.1",
|
|
89
89
|
"@ossjs/release": "^0.4.0",
|
|
90
90
|
"@playwright/test": "^1.31.1",
|
|
91
91
|
"@types/cors": "^2.8.12",
|
|
@@ -47,17 +47,32 @@ export class XMLHttpRequestController {
|
|
|
47
47
|
|
|
48
48
|
this.request = createProxy(initialRequest, {
|
|
49
49
|
setProperty: ([propertyName, nextValue], invoke) => {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
50
|
+
switch (propertyName) {
|
|
51
|
+
case 'onabort':
|
|
52
|
+
case 'onerror':
|
|
53
|
+
case 'onload':
|
|
54
|
+
case 'onloadend':
|
|
55
|
+
case 'onloadstart':
|
|
56
|
+
case 'onprogress':
|
|
57
|
+
case 'ontimeout':
|
|
58
|
+
case 'onreadystatechange': {
|
|
59
|
+
const eventName = propertyName.slice(
|
|
60
|
+
2
|
|
61
|
+
) as keyof XMLHttpRequestEventTargetEventMap
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* @note Proxy callbacks to event listeners because JSDOM has trouble
|
|
65
|
+
* translating these properties to callbacks. It seemed to be operating
|
|
66
|
+
* on events exclusively.
|
|
67
|
+
*/
|
|
68
|
+
this.request.addEventListener(eventName, nextValue as any)
|
|
69
|
+
return invoke()
|
|
70
|
+
}
|
|
59
71
|
|
|
60
|
-
|
|
72
|
+
default: {
|
|
73
|
+
return invoke()
|
|
74
|
+
}
|
|
75
|
+
}
|
|
61
76
|
},
|
|
62
77
|
methodCall: ([methodName, args], invoke) => {
|
|
63
78
|
switch (methodName) {
|
|
@@ -85,8 +100,8 @@ export class XMLHttpRequestController {
|
|
|
85
100
|
keyof XMLHttpRequestEventTargetEventMap,
|
|
86
101
|
Function
|
|
87
102
|
]
|
|
88
|
-
this.registerEvent(eventName, listener)
|
|
89
103
|
|
|
104
|
+
this.registerEvent(eventName, listener)
|
|
90
105
|
this.log('addEventListener', eventName, listener.name)
|
|
91
106
|
|
|
92
107
|
return invoke()
|
|
@@ -120,8 +135,7 @@ export class XMLHttpRequestController {
|
|
|
120
135
|
this.request,
|
|
121
136
|
/**
|
|
122
137
|
* The `response` property is the right way to read
|
|
123
|
-
* the ambiguous response body, as the request's "
|
|
124
|
-
* may differ.
|
|
138
|
+
* the ambiguous response body, as the request's "responseType" may differ.
|
|
125
139
|
* @see https://xhr.spec.whatwg.org/#the-response-attribute
|
|
126
140
|
*/
|
|
127
141
|
this.request.response
|
|
@@ -171,22 +185,6 @@ export class XMLHttpRequestController {
|
|
|
171
185
|
break
|
|
172
186
|
}
|
|
173
187
|
|
|
174
|
-
case 'onabort':
|
|
175
|
-
case 'onerror':
|
|
176
|
-
case 'onload':
|
|
177
|
-
case 'onloadend':
|
|
178
|
-
case 'onloadstart':
|
|
179
|
-
case 'onprogress':
|
|
180
|
-
case 'ontimeout':
|
|
181
|
-
case 'onreadystatechange': {
|
|
182
|
-
const [listener] = args as [Function]
|
|
183
|
-
this.registerEvent(
|
|
184
|
-
methodName as keyof XMLHttpRequestEventTargetEventMap,
|
|
185
|
-
listener
|
|
186
|
-
)
|
|
187
|
-
return invoke()
|
|
188
|
-
}
|
|
189
|
-
|
|
190
188
|
default: {
|
|
191
189
|
return invoke()
|
|
192
190
|
}
|
|
@@ -264,14 +262,17 @@ export class XMLHttpRequestController {
|
|
|
264
262
|
Object.defineProperties(this.request, {
|
|
265
263
|
response: {
|
|
266
264
|
enumerable: true,
|
|
265
|
+
configurable: false,
|
|
267
266
|
get: () => this.response,
|
|
268
267
|
},
|
|
269
268
|
responseText: {
|
|
270
269
|
enumerable: true,
|
|
270
|
+
configurable: false,
|
|
271
271
|
get: () => this.responseText,
|
|
272
272
|
},
|
|
273
273
|
responseXML: {
|
|
274
274
|
enumerable: true,
|
|
275
|
+
configurable: false,
|
|
275
276
|
get: () => this.responseXML,
|
|
276
277
|
},
|
|
277
278
|
})
|
|
@@ -19,10 +19,28 @@ export function createXMLHttpRequestProxy({
|
|
|
19
19
|
log,
|
|
20
20
|
}: XMLHttpRequestProxyOptions) {
|
|
21
21
|
const XMLHttpRequestProxy = new Proxy(globalThis.XMLHttpRequest, {
|
|
22
|
-
construct(target, args) {
|
|
22
|
+
construct(target, args, newTarget) {
|
|
23
23
|
log('constructed new XMLHttpRequest')
|
|
24
24
|
|
|
25
|
-
const originalRequest = Reflect.construct(target, args)
|
|
25
|
+
const originalRequest = Reflect.construct(target, args, newTarget)
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* @note Forward prototype descriptors onto the proxied object.
|
|
29
|
+
* XMLHttpRequest is implemented in JSDOM in a way that assigns
|
|
30
|
+
* a bunch of descriptors, like "set responseType()" on the prototype.
|
|
31
|
+
* With this propagation, we make sure that those descriptors trigger
|
|
32
|
+
* when the user operates with the proxied request instance.
|
|
33
|
+
*/
|
|
34
|
+
const prototypeDescriptors = Object.getOwnPropertyDescriptors(
|
|
35
|
+
target.prototype
|
|
36
|
+
)
|
|
37
|
+
for (const propertyName in prototypeDescriptors) {
|
|
38
|
+
Reflect.defineProperty(
|
|
39
|
+
originalRequest,
|
|
40
|
+
propertyName,
|
|
41
|
+
prototypeDescriptors[propertyName]
|
|
42
|
+
)
|
|
43
|
+
}
|
|
26
44
|
|
|
27
45
|
const requestController = new XMLHttpRequestController(
|
|
28
46
|
originalRequest,
|
|
@@ -3,6 +3,7 @@ import { HttpRequestEventMap, IS_PATCHED_MODULE } from '../../glossary'
|
|
|
3
3
|
import { Interceptor } from '../../Interceptor'
|
|
4
4
|
import { uuidv4 } from '../../utils/uuid'
|
|
5
5
|
import { toInteractiveRequest } from '../../utils/toInteractiveRequest'
|
|
6
|
+
import { until } from '@open-draft/until'
|
|
6
7
|
|
|
7
8
|
export class FetchInterceptor extends Interceptor<HttpRequestEventMap> {
|
|
8
9
|
static symbol = Symbol('fetch')
|
|
@@ -42,16 +43,28 @@ export class FetchInterceptor extends Interceptor<HttpRequestEventMap> {
|
|
|
42
43
|
|
|
43
44
|
this.log('awaiting for the mocked response...')
|
|
44
45
|
|
|
45
|
-
await
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
46
|
+
const [middlewareException, mockedResponse] = await until(async () => {
|
|
47
|
+
await this.emitter.untilIdle(
|
|
48
|
+
'request',
|
|
49
|
+
({ args: [, pendingRequestId] }) => {
|
|
50
|
+
return pendingRequestId === requestId
|
|
51
|
+
}
|
|
52
|
+
)
|
|
53
|
+
this.log('all request listeners have been resolved!')
|
|
52
54
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
+
const [mockedResponse] = await interactiveRequest.respondWith.invoked()
|
|
56
|
+
this.log('event.respondWith called with:', mockedResponse)
|
|
57
|
+
|
|
58
|
+
return mockedResponse
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
if (middlewareException) {
|
|
62
|
+
console.error(`${request.method} ${request.url} net::ERR_FAILED`)
|
|
63
|
+
const error = Object.assign(new TypeError('Failed to fetch'), {
|
|
64
|
+
cause: middlewareException,
|
|
65
|
+
})
|
|
66
|
+
return Promise.reject(error)
|
|
67
|
+
}
|
|
55
68
|
|
|
56
69
|
if (mockedResponse) {
|
|
57
70
|
this.log('received mocked response:', mockedResponse)
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import { vi, it, expect } from 'vitest'
|
|
2
|
+
import { createProxy } from './createProxy'
|
|
3
|
+
|
|
4
|
+
it('does not interfere with default constructors', () => {
|
|
5
|
+
const ProxyClass = createProxy(
|
|
6
|
+
class {
|
|
7
|
+
constructor(public name: string) {}
|
|
8
|
+
},
|
|
9
|
+
{}
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
const instance = new ProxyClass('John')
|
|
13
|
+
expect(instance.name).toBe('John')
|
|
14
|
+
})
|
|
15
|
+
|
|
16
|
+
it('does not interfere with default getters', () => {
|
|
17
|
+
const proxy = createProxy({ foo: 'initial' }, {})
|
|
18
|
+
expect(proxy.foo).toBe('initial')
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
it('does not interfere with default setters', () => {
|
|
22
|
+
const proxy = createProxy({ foo: 'initial' }, {})
|
|
23
|
+
proxy.foo = 'next'
|
|
24
|
+
|
|
25
|
+
expect(proxy.foo).toBe('next')
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
it('does not interfere with default methods', () => {
|
|
29
|
+
const proxy = createProxy({ getValue: () => 'initial' }, {})
|
|
30
|
+
expect(proxy.getValue()).toBe('initial')
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
it('does not interfere with existing descriptors', () => {
|
|
34
|
+
const target = {} as { foo: string; bar: number }
|
|
35
|
+
let internalBar = 0
|
|
36
|
+
|
|
37
|
+
Object.defineProperties(target, {
|
|
38
|
+
foo: {
|
|
39
|
+
get: () => 'initial',
|
|
40
|
+
},
|
|
41
|
+
bar: {
|
|
42
|
+
set: (value) => {
|
|
43
|
+
internalBar = value + 10
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
const proxy = createProxy(target, {
|
|
49
|
+
getProperty(data, next) {
|
|
50
|
+
return next()
|
|
51
|
+
},
|
|
52
|
+
})
|
|
53
|
+
expect(proxy.foo).toBe('initial')
|
|
54
|
+
|
|
55
|
+
proxy.bar = 5
|
|
56
|
+
expect(proxy.bar).toBeUndefined()
|
|
57
|
+
expect(internalBar).toBe(15)
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
it('infer prototype descriptors', () => {
|
|
61
|
+
class Child {
|
|
62
|
+
ok: boolean
|
|
63
|
+
|
|
64
|
+
set status(nextStatus: number) {
|
|
65
|
+
this.ok = nextStatus >= 200 && nextStatus < 300
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
Object.defineProperties(Child.prototype, {
|
|
70
|
+
status: { enumerable: true },
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
const scope = {} as { child: typeof Child }
|
|
74
|
+
|
|
75
|
+
Object.defineProperty(scope, 'child', {
|
|
76
|
+
enumerable: true,
|
|
77
|
+
value: Child,
|
|
78
|
+
})
|
|
79
|
+
|
|
80
|
+
const ProxyClass = createProxy(scope.child, {})
|
|
81
|
+
const instance = new ProxyClass()
|
|
82
|
+
|
|
83
|
+
instance.status = 201
|
|
84
|
+
expect(instance.ok).toBe(true)
|
|
85
|
+
})
|
|
86
|
+
|
|
87
|
+
it('spies on the constructor', () => {
|
|
88
|
+
const OriginalClass = class {
|
|
89
|
+
constructor(public name: string, public age: number) {}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const constructorCall = vi.fn<
|
|
93
|
+
[ConstructorParameters<typeof OriginalClass>, Function],
|
|
94
|
+
typeof OriginalClass
|
|
95
|
+
>((args, next) => next())
|
|
96
|
+
|
|
97
|
+
const ProxyClass = createProxy(OriginalClass, {
|
|
98
|
+
constructorCall,
|
|
99
|
+
})
|
|
100
|
+
|
|
101
|
+
new ProxyClass('John', 32)
|
|
102
|
+
|
|
103
|
+
expect(constructorCall).toHaveBeenCalledTimes(1)
|
|
104
|
+
expect(constructorCall).toHaveBeenCalledWith(
|
|
105
|
+
['John', 32],
|
|
106
|
+
expect.any(Function)
|
|
107
|
+
)
|
|
108
|
+
})
|
|
109
|
+
|
|
110
|
+
it('spies on property getters', () => {
|
|
111
|
+
const getProperty = vi.fn((args, next) => next())
|
|
112
|
+
const proxy = createProxy({ foo: 'initial' }, { getProperty })
|
|
113
|
+
|
|
114
|
+
proxy.foo
|
|
115
|
+
|
|
116
|
+
expect(getProperty).toHaveBeenCalledTimes(1)
|
|
117
|
+
expect(getProperty).toHaveBeenCalledWith(['foo', proxy], expect.any(Function))
|
|
118
|
+
})
|
|
119
|
+
|
|
120
|
+
it('spies on property setters', () => {
|
|
121
|
+
const setProperty = vi.fn((args, next) => next())
|
|
122
|
+
const proxy = createProxy({ foo: 'initial' }, { setProperty })
|
|
123
|
+
|
|
124
|
+
proxy.foo = 'next'
|
|
125
|
+
|
|
126
|
+
expect(setProperty).toHaveBeenCalledTimes(1)
|
|
127
|
+
expect(setProperty).toHaveBeenCalledWith(
|
|
128
|
+
['foo', 'next'],
|
|
129
|
+
expect.any(Function)
|
|
130
|
+
)
|
|
131
|
+
})
|
|
132
|
+
|
|
133
|
+
it('spies on method calls', () => {
|
|
134
|
+
const methodCall = vi.fn((args, next) => next())
|
|
135
|
+
const proxy = createProxy(
|
|
136
|
+
{
|
|
137
|
+
greet: (name: string) => `hello ${name}`,
|
|
138
|
+
},
|
|
139
|
+
{ methodCall }
|
|
140
|
+
)
|
|
141
|
+
|
|
142
|
+
proxy.greet('Clair')
|
|
143
|
+
|
|
144
|
+
expect(methodCall).toHaveBeenCalledTimes(1)
|
|
145
|
+
expect(methodCall).toHaveBeenCalledWith(
|
|
146
|
+
['greet', ['Clair']],
|
|
147
|
+
expect.any(Function)
|
|
148
|
+
)
|
|
149
|
+
})
|
package/src/utils/createProxy.ts
CHANGED
|
@@ -9,8 +9,8 @@ export interface ProxyOptions<Target extends Record<string, any>> {
|
|
|
9
9
|
|
|
10
10
|
setProperty?(
|
|
11
11
|
data: [propertyName: string | symbol, nextValue: unknown],
|
|
12
|
-
next: NextFunction<
|
|
13
|
-
):
|
|
12
|
+
next: NextFunction<boolean>
|
|
13
|
+
): boolean
|
|
14
14
|
|
|
15
15
|
getProperty?(
|
|
16
16
|
data: [propertyName: string | symbol, receiver: Target],
|
|
@@ -25,6 +25,7 @@ export function createProxy<Target extends object>(
|
|
|
25
25
|
options: ProxyOptions<Target>
|
|
26
26
|
): Target {
|
|
27
27
|
const proxy = new Proxy(target, optionsToProxyHandler(options))
|
|
28
|
+
|
|
28
29
|
return proxy
|
|
29
30
|
}
|
|
30
31
|
|
|
@@ -41,11 +42,31 @@ function optionsToProxyHandler<T extends Record<string, any>>(
|
|
|
41
42
|
}
|
|
42
43
|
}
|
|
43
44
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
const
|
|
47
|
-
|
|
45
|
+
handler.set = function (target, propertyName, nextValue, receiver) {
|
|
46
|
+
const next = () => {
|
|
47
|
+
const ownDescriptors = Reflect.getOwnPropertyDescriptor(
|
|
48
|
+
target,
|
|
49
|
+
propertyName
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
if (typeof ownDescriptors?.set !== 'undefined') {
|
|
53
|
+
ownDescriptors.set.apply(target, [nextValue])
|
|
54
|
+
return true
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return Reflect.defineProperty(target, propertyName, {
|
|
58
|
+
writable: true,
|
|
59
|
+
enumerable: true,
|
|
60
|
+
configurable: true,
|
|
61
|
+
value: nextValue,
|
|
62
|
+
})
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if (typeof setProperty !== 'undefined') {
|
|
66
|
+
return setProperty.call(target, [propertyName, nextValue], next)
|
|
48
67
|
}
|
|
68
|
+
|
|
69
|
+
return next()
|
|
49
70
|
}
|
|
50
71
|
|
|
51
72
|
handler.get = function (target, propertyName, receiver) {
|