ofetch icon indicating copy to clipboard operation
ofetch copied to clipboard

Usage with MSW / patched fetch

Open meesvandongen opened this issue 1 year ago • 13 comments

Environment

Node

Reproduction

https://codesandbox.io/p/sandbox/stoic-https-6gjdtz?file=/index.js:14,16

import { setupServer } from "msw/node";
import { http, HttpResponse } from "msw";
import wretch from 'wretch'
import { ofetch, fetch, createFetch } from 'ofetch'
import got from 'got'

const server = setupServer(
    http.get('https://example.com', () => {
        return HttpResponse.text('1')
    })
)
server.listen();

console.table([
 ['fetch', await globalThis.fetch('https://example.com').then(res => res.text()).then(res => res === '1')],
 ['ofetch fetch', await fetch('https://example.com').then(res => res.text()).then(res => res === '1')],
 ['ofetch createFetch', await createFetch()('https://example.com').then(res => res === '1')],
 ['ofetch', await ofetch('https://example.com').then(res => res === '1')],
 ['wretch', await wretch('https://example.com').get().text().then(res => res === '1')],
 ['got', await got.get('https://example.com').text().then(res => res === '1')],
])

CleanShot 2023-12-23 at 14 00 06@2x

Describe the bug

When other tools patch fetch, the global instance of ofetch will have the original fetch instance. This will cause tools such as msw to not be able to intercept requests with ofetch. A workaround could be to only get the globalThis.fetch at request time if no other fetch is specified.

Additional context

Users can work around this at this time by using the createFetch helper function.

Logs

No response

meesvandongen avatar Sep 11 '23 12:09 meesvandongen

Thanks @meesvandongen for opening this issue, which is also a problem we have encountered. PooyaJaan @pi0 please let us know what is the best and efficient temporary solution to solve this problem until it is resolved? Should we use the createFetch function?

mohammadGh avatar Nov 01 '23 11:11 mohammadGh

For anyone coming here, I found a hacky but functional way to workaround this for now using the Proxy constructor

function createMyFetch() {
  const newFetch = createFetch({
    fetch: globalThis.fetch,
    Headers: globalThis.Headers,
  });

  return newFetch.create({
    // ...default options
  });
}

const original = createMyFetch();

export const http = new Proxy(original, {
  apply(_, thisArg, argumentsList) {
    return Reflect.apply(createMyFetch(), thisArg, argumentsList);
  },
});

// Then in other file calling `http` will be intercepted but maintaining the same usage
http('https://jsonplaceholder.typicode.com/todos/1')

This will work with [email protected] and [email protected]. You can merge the arguments instead of creating a new stance every time, or creating one only on the first call, etc

edumudu avatar Nov 17 '23 15:11 edumudu

Running into this issue as well, a fix or workaround for usage with msw would be greatly appreciated.

rinux55 avatar Dec 16 '23 13:12 rinux55

Running into this issue as well, a fix or workaround for usage with msw would be greatly appreciated.

Same here, not working with Nuxt in my case for MSW serverside outgoing calls EDIT:

After more debuggin in nuxtJS i found out above issue is main issue mocking in server/api is not working (calls to third parties

export default defineEventHandler(async (event) => {
  const data = await createFetch()(
    'https://jsonplaceholder.typicode.com/todos/1',
    {
      method: 'GET',
      headers: {
        'Content-Type': 'application/json',
      },
    },
  )
  console.log(JSON.stringify(data))
  return {
    hello: 'world',
  }
})

Right now i fixed it by using the createFetch insteda of $fetch from nuxt.

stichingsd-vitrion avatar Jan 05 '24 12:01 stichingsd-vitrion

Just adding on here, this is also apparently a problem when using Sentry in the Browser - any requests made via ofetch will not be captured by the monkey-patched fetch that Sentry relies on to capture network requests, sadly.

mydea avatar Feb 15 '24 16:02 mydea

I think this same problem (even if not strictly an issue with ofetch) happens with Datadog RUM: https://github.com/unjs/ofetch/issues/339

dwightjack avatar Mar 20 '24 23:03 dwightjack

I might have found a possible, non-breaking solution to this problem and submitted a PR, but I wonder whether it is effective in all scenarios.

dwightjack avatar Mar 21 '24 05:03 dwightjack

Any update on this ?

mentalrob avatar Mar 26 '24 20:03 mentalrob

Here is a possible workaround for me with useFetch hook in Nuxt.

useFetch(url, {
    $fetch: createFetch({
      fetch: globalThis.fetch,
      Headers: globalThis.Headers,
    }), 
   ...options,
  });

Maybe this could be better supported in Nuxt.

cy-moi avatar Apr 24 '24 12:04 cy-moi

I'm too humbly awaiting the solution, thank you, guys, for your time! Tried to overcome the issue by myself, but for now don't see any available options.

artmizu avatar May 13 '24 06:05 artmizu

For someone who stuck in Nuxt + ofetch, I have created a Nuxt module nuxt-msw, which integrate msw with Nuxt.

shunnNet avatar Aug 30 '24 14:08 shunnNet

This issue was a deciding factor against using ofetch when migrating an app that was using request even though the ofetch api is really nice :disappointed:

cctidal avatar Aug 30 '24 14:08 cctidal

Next version of ofetch will use patched fetch.

pi0 avatar Aug 30 '24 14:08 pi0