sinonjs / sinon

Test spies, stubs and mocks for JavaScript.
https://sinonjs.org/
Other
9.6k stars 769 forks source link

[Node v21.7.0] Impossible to stub `fetch` #2590

Closed regseb closed 1 month ago

regseb commented 4 months ago

Describe the bug With Node.js v21.7.0, it's no longer possible to stub the fetch() function.

Edit:

To Reproduce

Steps to reproduce the behavior:

  1. npm install
  2. node testcase.js
node:internal/deps/undici/undici:13737
      Error.captureStackTrace(err, this);
            ^

TypeError: fetch failed
    at node:internal/deps/undici/undici:13737:13
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
    at async file:///home/sregne/script/tc/testcase.js:7:18 {
  [cause]: Error: getaddrinfo ENOTFOUND baz.qux
      at GetAddrInfoReqWrap.onlookupall [as oncomplete] (node:dns:118:26) {
    errno: -3008,
    code: 'ENOTFOUND',
    syscall: 'getaddrinfo',
    hostname: 'baz.qux'
  }
}

Node.js v21.7.0

Expected behavior

{ foo: 'bar' }
https://baz.qux/

Context (please complete the following information):

Additional context It's work with Node.js v21.6.2.


The problem seems to come from Node.js and the pull request https://github.com/nodejs/node/pull/51598#issuecomment-1984341350

This was a breaking change for tests mocking global fetch, for ex:

import { describe, it } from 'node:test';
import assert from 'node:assert/strict';
import { fetchSomething } from '../lib/index.mjs';

describe('my test suite', () => {
  it('fetch stuff', async (t) => {
    const mockValue = { key: 'value' };
    const mockFetch = async () => ({
      json: async () => mockValue,
      status: 200,
    });

    t.mock.method(global, 'fetch', mockFetch);
    assert.deepStrictEqual(await fetchSomething(), mockValue);
    t.mock.restoreAll();
  });
});

which produces:

✖ fetch stuff (0.894292ms)
  TypeError [ERR_INVALID_ARG_VALUE]: The argument 'methodName' must be a method. Received undefined
      at MockTracker.method (node:internal/test_runner/mock/mock:241:13)
      at TestContext.<anonymous> (my.test.mjs:13:12)
      at Test.runInAsyncScope (node:async_hooks:206:9)
      at Test.run (node:internal/test_runner/test:641:25)
      at Suite.processPendingSubtests (node:internal/test_runner/test:382:18)
      at Test.postRun (node:internal/test_runner/test:732:19)
      at Test.run (node:internal/test_runner/test:690:12)
      at async Promise.all (index 0)
      at async Suite.run (node:internal/test_runner/test:966:7)
      at async startSubtest (node:internal/test_runner/harness:218:3) {
    code: 'ERR_INVALID_ARG_VALUE'
  }

to fix the break, i had to reference global.fetch before mocking it...ie:

fetch;
t.mock.method(global, 'fetch', mockFetch);
fatso83 commented 3 months ago

Thank you for linking up the associated Node issues. Lots of good stuff there, including your own contributions. I think it's wise to hold off for a little while in order to see if this partly resolves itself within Node (my take after reading the discussion).

iantocristian commented 3 months ago

Same behaviour in node 20.12.0 (stopped working in this version)

fatso83 commented 3 months ago

We can't do much about this until https://github.com/nodejs/node/pull/52275 (created 5 days ago) is merged and then subsequently released and possibly backmerged (into version 20).

fatso83 commented 1 month ago

Fix for this landed in Node 22.1.0 (https://github.com/nodejs/node/pull/52768). There is no fix for version 21, but installing the latest version 20 will get you the fix. I have also verified this works in 20.13.1 and 22.2.0, as well as testing that it did not working in 20.12.0 and others.