Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

msw/node unable to intercept requests from fetch in undici #2165

Open
4 tasks done
TheHolyWaffle opened this issue May 24, 2024 · 8 comments
Open
4 tasks done

msw/node unable to intercept requests from fetch in undici #2165

TheHolyWaffle opened this issue May 24, 2024 · 8 comments
Labels
bug Something isn't working needs:triage Issues that have not been investigated yet. scope:node Related to MSW running in Node

Comments

@TheHolyWaffle
Copy link

Prerequisites

Environment check

  • I'm using the latest msw version
  • I'm using Node.js version 18 or higher

Node.js version

20.13.1

Reproduction repository

https://github.com/TheHolyWaffle/msw-undici-reproduction

Reproduction steps

npm i
npx jest to run the sample test.js unit test

Current behavior

When adding a GET handler to https://example.com, msw does not intercept the request. Instead the fetch goes to the real example.com. See failing unit test.

To make the unit test succeed, uncomment const { fetch } = require("undici"); so that the node-native fetch is used instead of the `

Expected behavior

msw should intercept the fetch call from undici and unit test should succeed.

@TheHolyWaffle TheHolyWaffle added bug Something isn't working needs:triage Issues that have not been investigated yet. scope:node Related to MSW running in Node labels May 24, 2024
@kettanaito
Copy link
Member

Hi, @TheHolyWaffle. Thanks for reporting this.

Please, compare your usage example to the Jest and Jest+JSDOM examples from MSW. Those are functional (as functional as anything on JSDOM can get).

You don't have to import fetch from undici explicitly if you have this line.

I also highly recommend to drop jest.polyfills.js and use jest-fixed-jsdom preset instead. Try that and let me know if you still encounter the issue.

@TheHolyWaffle
Copy link
Author

TheHolyWaffle commented May 25, 2024

@kettanaito Thanks for looking into this.

I have removed the polyfills again in the minimal reproduction. They were a futile attempt to fix my issue but they never made sense. This bug purely revolves around a nodejs backend microservice, no jsdom environment is needed.

I have a hard requirement to import fetch directly from the undici package. This is because the node built-in version of fetch is from an older undici version. Since then, there have been bugs fixed in undici. Also, the node built-in fetch does not allow passing a dispatcher directly, unlike fetch from undici. Because of these reasons, I cannot use the global fetch.

Please reconsider this issue 🙏

@kettanaito
Copy link
Member

I have a hard requirement to import fetch directly from the undici package.

That shouldn't be a problem.

Also, the node built-in fetch does not allow passing a dispatcher directly, unlike fetch from undici.

TIL!

No worries, let's reopen this then.

@kettanaito kettanaito reopened this May 25, 2024
@bobanm
Copy link

bobanm commented Jun 28, 2024

@TheHolyWaffle we have exactly the same reasons to use undici instead of the Node's native fetch: the dispatcher. And the same problem, that MSW does not intercept and mock the requests, but let's the requests go through to the real service.

Have you found a decent solution?

@TheHolyWaffle
Copy link
Author

TheHolyWaffle commented Jul 14, 2024

@bobanm I went ahead with Undici's MockAgent instead of msw, see https://undici.nodejs.org/#/docs/api/MockAgent

Feel free to 👍 the original issue to bring more attention to this!

@bobanm
Copy link

bobanm commented Jul 15, 2024

@TheHolyWaffle I ended up doing the same. I find it to be a little bit less elegant than using MSW, but still quite a good solution.

I hope MSW adds support for Undici.

@Jokinen
Copy link

Jokinen commented Jul 31, 2024

@TheHolyWaffle Are you sure that node's fetch does not support the dispatcher field? I have the same problem, but as far as I understand, the issue is with TS types, not in the API of the native fetch. At least the typings for the "node version of the types" do include the dispatcher field in the RequestInit object.

DefinitelyTyped/DefinitelyTyped#66824

If you are using typescript, the @types/node library may be giving you the DOM types when you'd prefer to use the types for node ("undici types"). If your TS project includes a frontend, you may have configured lib.dom.d.ts in use yourself ("lib": ["dom"] in tsconfig) or a dependency of yours may be pulling it in (you can try to use explainFiles to find out the cause(s) of the files inclusion if its unclear).

This may be of no real help to you. Just jotting this down for future reference in case it has an impact on API decision. Still looking for a feasible workaround myself.

E: At least one workaround is to use multiple tsconfig files and structure your project so that the fetch integration is covered by a tsconfig without lib.dom.d.ts and any dependencies that may end up including it.

@kettanaito
Copy link
Member

kettanaito commented Jul 31, 2024

Why this happens

Undici is a custom client that doesn't rely on the node:http module, which is a primary request-issuing module which MSW observes in Node.js (as of now). Because of that, the requests Undici makes are invisible to MSW (I believe Undici uses net.Socket directly).

How to solve this

For now, you can switch to Undici's MockAgent as Undici ships with their own mocking in mind. If that works for you, that's great!

Note that you can call MSW request handlers directly, including in your MockAgent by Undici. See the getResponse() function.

Undici support

MSW has a strong position on not shipping request client-specific code. Instead, we try out best to support the underlying protocols, tapping into the network at the layer that is both more resilient and less intrusive to the things you are running.

I highly doubt a standalone Undici support will ever happen in MSW. What may happen, is net.Socket support, which Undici uses. We've already merged the Socket-based interceptor in @mswjs/interceptors but (a) it's not used in MSW yet; (b) it still taps into node:http by using a custom Agent and a mock socket.

Raw socket-level interception is theoretically possible, we just need to get it right. Sockets transport many things, not just HTTP requests. We better not interfere with those things.

Important

Also please note that MSW supports global fetch in Node.js still. That is also, technically, Undici. It just has to be a global fetch function. It's important to disambiguate that we aren't talking about global fetch but about a standalone usage of Undici, like their request function.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working needs:triage Issues that have not been investigated yet. scope:node Related to MSW running in Node
Projects
None yet
Development

No branches or pull requests

4 participants