Skip to content

Commit 6701f38

Browse files
committed
fix: don't mutate mergeApiOptions params so that fetchFn works
1 parent 0b8c657 commit 6701f38

File tree

3 files changed

+40
-7
lines changed

3 files changed

+40
-7
lines changed

src/sdk/v4/_fetcher.ts

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,14 @@ export const fetcher = async <T extends object>(
3333
return camelizeKeys(json) as T;
3434
}
3535

36-
if (typeof fetch === 'undefined') {
37-
throw new Error('fetch is not defined');
36+
if (typeof globalThis.fetch !== 'function') {
37+
throw new Error(
38+
'Looks like there is no global fetch function. Take a look at https://quranjs.com/techniques#custom-fetcher for more info.'
39+
);
3840
}
3941

4042
// if there is no fetchFn, we use the global fetch
41-
const res = await fetch(makeUrl(url, params));
43+
const res = await globalThis.fetch(makeUrl(url, params));
4244

4345
if (!res.ok || res.status >= 400) {
4446
throw new Error(`${res.status} ${res.statusText}`);
@@ -57,12 +59,14 @@ export const mergeApiOptions = (
5759
options: MergeApiOptionsObject = {},
5860
defaultOptions: Record<string, unknown> = {}
5961
) => {
62+
const clonedOptions = { ...options };
63+
6064
// we can set it to undefined because `makeUrl` will filter it out
61-
if (options.fetchFn) options.fetchFn = undefined;
65+
if (clonedOptions.fetchFn) clonedOptions.fetchFn = undefined;
6266

6367
const final: Record<string, unknown> = {
6468
...defaultOptions,
65-
...options,
69+
...clonedOptions,
6670
};
6771

6872
if (final.fields) {

test/fetchFn.test.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import { describe, expect, it } from 'vitest';
2+
import fetch from 'cross-fetch';
3+
import { quran } from '../src';
4+
5+
describe('Custom fetcher', () => {
6+
it('should fail with no fetch', () => {
7+
// @ts-expect-error - we are testing this
8+
globalThis.fetch = undefined;
9+
10+
expect(() => quran.v4.chapters.findAll()).rejects.toThrowError(
11+
/global fetch/
12+
);
13+
});
14+
15+
it('should not fail if you pass a fetchFn', () => {
16+
// @ts-expect-error - we are testing this
17+
globalThis.fetch = undefined;
18+
19+
expect(
20+
quran.v4.chapters.findById('1', {
21+
fetchFn: (url) => {
22+
return fetch(url).then((res) => res.json());
23+
},
24+
})
25+
).resolves.not.toThrow();
26+
});
27+
});

test/setup.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
import fetch from 'cross-fetch';
2-
import { beforeAll, afterEach, afterAll } from 'vitest';
2+
import { beforeAll, afterEach, afterAll, beforeEach } from 'vitest';
33
import { server } from '../mocks/server';
44

55
// Establish API mocking before all tests.
66
beforeAll(async () => {
77
server.listen();
8+
});
89

10+
beforeEach(async () => {
911
// we do this instead of passing a fetchFn every time
10-
global.fetch = fetch;
12+
globalThis.fetch = fetch;
1113
});
1214

1315
// Reset any request handlers that we may add during the tests,

0 commit comments

Comments
 (0)