mswjs / msw

Industry standard API mocking for JavaScript.
https://mswjs.io
MIT License
15.97k stars 519 forks source link

not compatible with fetch-retry #2221

Closed zoli-kasa closed 3 months ago

zoli-kasa commented 3 months ago

Prerequisites

Environment check

Node.js version

20.12.2

Reproduction repository

https://github.com/zoli-kasa/msw-examples

Reproduction steps

pnpm install
cd examples/with-jest
npm test

Current behavior


  ✓ receives a mocked response to a REST API request (9 ms)
  ✕ receives a mocked response to a REST API fetch-retry request (3059 ms)
  ✓ receives a mocked response to a GraphQL API request (12 ms)

  ● receives a mocked response to a REST API fetch-retry request

    TypeError: fetch failed

    Cause:
    getaddrinfo ENOTFOUND api.example.com

### Expected behavior

it does not try to call the real endpoint
kettanaito commented 3 months ago

Hi, @zoli-kasa. Thanks for reporting this!

This looks like an import order issue. In other words, the fetch you pass as an argument to retry-fetch is not yet the patched version of fetch that MSW uses to observe the network (after the server.listen() call).

You can fix this by deferring the moment you create the retry fetch function. One way to do that, is to import it dynamically in your test:

diff --git a/examples/with-jest/example.test.ts b/examples/with-jest/example.test.ts
index 6e139bb..6dae37b 100644
--- a/examples/with-jest/example.test.ts
+++ b/examples/with-jest/example.test.ts
@@ -1,5 +1,3 @@
-const fetchRetry = require('fetch-retry')(fetch)
-
 it('receives a mocked response to a REST API request', async () => {
   const response = await fetch('https://api.example.com/user')

@@ -12,6 +10,9 @@ it('receives a mocked response to a REST API request', async () => {
 })

 it('receives a mocked response to a REST API fetch-retry request', async () => {
+  const { default: createFetchRetry } = await import('fetch-retry')
+  const fetchRetry = createFetchRetry(fetch)
+
   const response = await fetchRetry('https://api.example.com/user', {
     retries: 3,
     retryDelay: 1000,

Another way, is to wrap retry-fetch in a utility function that gets created during the test run, not the top-level imports of the test.

zoli-kasa commented 3 months ago

thanks, this works!