From 18ae7a46f678917761589714768973c6895e2b1a 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 db5d449dd79be4..7733f711bc6daf 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(); +});