Skip to content

Commit

Permalink
fix(http): Dynamicaly call the global fetch implementation
Browse files Browse the repository at this point in the history
Instead of using the reference that existed when `FetchBackend` was setup.

fixes angular#57527
  • Loading branch information
JeanMeche committed Aug 26, 2024
1 parent 969dadc commit eae4b45
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 1 deletion.
2 changes: 1 addition & 1 deletion packages/common/http/src/fetch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ function getResponseUrl(response: Response): string | null {
export class FetchBackend implements HttpBackend {
// We need to bind the native fetch to its context or it will throw an "illegal invocation"
private readonly fetchImpl =
inject(FetchFactory, {optional: true})?.fetch ?? fetch.bind(globalThis);
inject(FetchFactory, {optional: true})?.fetch ?? ((...args) => globalThis.fetch(...args));
private readonly ngZone = inject(NgZone);

handle(request: HttpRequest<any>): Observable<HttpEvent<any>> {
Expand Down
33 changes: 33 additions & 0 deletions packages/common/http/test/fetch_spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,14 @@ import {Observable, of, Subject} from 'rxjs';
import {catchError, retry, scan, skip, take, toArray} from 'rxjs/operators';

import {
HttpClient,
HttpDownloadProgressEvent,
HttpErrorResponse,
HttpHeaderResponse,
HttpParams,
HttpStatusCode,
provideHttpClient,
withFetch,
} from '../public_api';
import {FetchBackend, FetchFactory} from '../src/fetch';

Expand Down Expand Up @@ -416,6 +419,36 @@ describe('FetchBackend', async () => {
fetchMock.mockFlush(0, 'CORS 0 status');
});
});

describe('dynamic global fetch', () => {
beforeEach(() => {
TestBed.resetTestingModule();
TestBed.configureTestingModule({
providers: [provideHttpClient(withFetch())],
});
});

it('should use the current implementation of the global fetch', async () => {
const fakeFetch = jasmine
.createSpy('', () => Promise.resolve(new Response(JSON.stringify({foo: 'bar'}))))
.and.callThrough();
globalThis.fetch = fakeFetch;

const client = TestBed.inject(HttpClient);
expect(fakeFetch).not.toHaveBeenCalled();
let response = await client.get<unknown>('').toPromise();
expect(fakeFetch).toHaveBeenCalled();
expect(response).toEqual({foo: 'bar'});

// We dynamicaly change the implementation of fetch
const fakeFetch2 = jasmine
.createSpy('', () => Promise.resolve(new Response(JSON.stringify({foo: 'baz'}))))
.and.callThrough();
globalThis.fetch = fakeFetch2;
response = await client.get<unknown>('').toPromise();
expect(response).toEqual({foo: 'baz'});
});
});
});

export class MockFetchFactory extends FetchFactory {
Expand Down

0 comments on commit eae4b45

Please sign in to comment.