Skip to content

Commit 03d3f94

Browse files
Merge pull request #519 from Techn1x/bo/improve-fetch-response-proxy
fix: proxy more parts of fetch Response
2 parents db982dd + 7dc7f81 commit 03d3f94

File tree

1 file changed

+48
-5
lines changed

1 file changed

+48
-5
lines changed

addon/src/wait-for-fetch.ts

Lines changed: 48 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,64 @@
11
import { default as waitForPromise } from './wait-for-promise.ts';
22

3+
const props = [
4+
'body',
5+
'bodyUsed',
6+
'headers',
7+
'ok',
8+
'redirected',
9+
'status',
10+
'statusText',
11+
'type',
12+
'url',
13+
] as const satisfies (keyof Response)[];
14+
type ResponseProp = (typeof props)[number];
15+
function isResponseProperty(maybeProp: string): maybeProp is ResponseProp {
16+
return props.some((prop) => maybeProp === prop);
17+
}
18+
19+
const fns = [
20+
'arrayBuffer',
21+
'blob',
22+
'bytes',
23+
'clone',
24+
'formData',
25+
'json',
26+
'text',
27+
] as const satisfies (keyof Response)[];
28+
type ResponseFn = (typeof fns)[number];
29+
function isResponseFn(maybeFn: string): maybeFn is ResponseFn {
30+
return fns.some((fn) => maybeFn === fn);
31+
}
32+
33+
/**
34+
* Wraps the fetch promise in a test waiter, and also wraps the returned promises' async functions (like json()) in a
35+
* test waiter.
36+
*/
337
export async function waitForFetch(fetchPromise: ReturnType<typeof fetch>) {
438
const response = await waitForPromise(fetchPromise);
539

640
return new Proxy(response, {
741
get(target, prop, receiver) {
42+
/* Depending on the stack, Response is often already a Proxy. Reflect.get() will error for property values, when
43+
* using a Proxy as the _receiver_ arg, so just return the value the normal way to avoid that issue. */
44+
if (typeof prop === 'string' && isResponseProperty(prop)) {
45+
return target[prop];
46+
}
847
const original = Reflect.get(target, prop, receiver);
948

10-
if (
11-
typeof prop === 'string' &&
12-
['json', 'text', 'arrayBuffer', 'blob', 'formData', 'bytes'].includes(prop)
13-
) {
49+
// Wrap Response functions in test waiter
50+
if (typeof prop === 'string' && isResponseFn(prop)) {
51+
// clone() is sync, no need to wrap in test-waiter
52+
if (prop === 'clone') {
53+
return (...args: unknown[]) => {
54+
return original.call(target, ...args);
55+
};
56+
}
1457
return (...args: unknown[]) => {
1558
return waitForPromise(original.call(target, ...args));
1659
};
1760
}
18-
61+
// return the Reflect.get() result for anything else
1962
return original;
2063
},
2164
});

0 commit comments

Comments
 (0)