From 2cd3073e0f19d8e28c2412c9208f6ffed60ae33b Mon Sep 17 00:00:00 2001 From: Victor Chen Date: Sat, 13 Apr 2024 01:54:42 +0800 Subject: [PATCH] lib: refactor lazy loading of undici for fetch method Object.defineProperty is updated to lazily load the undici dependency for the fetch method. This change allows for simpler and more reliable mocking of the fetch method for testing purposes, resolving issues encountered with premature method invocation during testing. Fixes: https://github.com/nodejs/node/issues/52015 PR-URL: https://github.com/nodejs/node/pull/52275 Reviewed-By: Moshe Atlow Reviewed-By: Matteo Collina Reviewed-By: Chemi Atlow Reviewed-By: James M Snell Reviewed-By: Joyee Cheung --- .../bootstrap/web/exposed-window-or-worker.js | 41 +++++++------------ test/parallel/test-fetch-mock.js | 20 +++++++++ 2 files changed, 35 insertions(+), 26 deletions(-) create mode 100644 test/parallel/test-fetch-mock.js diff --git a/lib/internal/bootstrap/web/exposed-window-or-worker.js b/lib/internal/bootstrap/web/exposed-window-or-worker.js index 2459bee85bb8b0..82888b3cd9512e 100644 --- a/lib/internal/bootstrap/web/exposed-window-or-worker.js +++ b/lib/internal/bootstrap/web/exposed-window-or-worker.js @@ -57,32 +57,21 @@ defineReplaceableLazyAttribute(globalThis, 'perf_hooks', ['performance']); const { installObjectURLMethods } = require('internal/url'); installObjectURLMethods(); -{ - // https://fetch.spec.whatwg.org/#fetch-method - function set(value) { - ObjectDefineProperty(globalThis, 'fetch', { - __proto__: null, - writable: true, - value, - }); - } - ObjectDefineProperty(globalThis, 'fetch', { - __proto__: null, - configurable: true, - enumerable: true, - set, - get() { - function fetch(input, init = undefined) { - // Loading undici alone lead to promises which breaks lots of tests so we - // have to load it really lazily for now. - const { fetch: impl } = require('internal/deps/undici/undici'); - return impl(input, init); - } - set(fetch); - return fetch; - }, - }); -} +let fetchImpl; +// https://fetch.spec.whatwg.org/#fetch-method +ObjectDefineProperty(globalThis, 'fetch', { + __proto__: null, + configurable: true, + enumerable: true, + writable: true, + value: function value(input, init = undefined) { + if (!fetchImpl) { // Implement lazy loading of undici module for fetch function + const undiciModule = require('internal/deps/undici/undici'); + fetchImpl = undiciModule.fetch; + } + return fetchImpl(input, init); + }, +}); // https://xhr.spec.whatwg.org/#interface-formdata // https://fetch.spec.whatwg.org/#headers-class diff --git a/test/parallel/test-fetch-mock.js b/test/parallel/test-fetch-mock.js new file mode 100644 index 00000000000000..b457745f1c4c90 --- /dev/null +++ b/test/parallel/test-fetch-mock.js @@ -0,0 +1,20 @@ +'use strict'; +require('../common'); +const { mock, test } = require('node:test'); +const assert = require('node:assert'); + +test('should correctly stub globalThis.fetch', async () => { + const customFetch = async (url) => { + return { + text: async () => 'foo', + }; + }; + + mock.method(globalThis, 'fetch', customFetch); + + const response = await globalThis.fetch('some-url'); + const text = await response.text(); + + assert.strictEqual(text, 'foo'); + mock.restoreAll(); +});