mswjs / msw

Seamless REST/GraphQL API mocking library for browser and Node.js.
https://mswjs.io
MIT License
15.65k stars 503 forks source link

MSW doesn't seem to be working with URQL or Vite correctly #1593

Open RIP21 opened 1 year ago

RIP21 commented 1 year ago

Prerequisites

Environment check

Browsers

Chromium (Chrome, Brave, etc.)

Reproduction repository

https://codesandbox.io/p/sandbox/brave-voice-5yd8ut

Reproduction steps

I have problems (it doesn't work no matter what I tried) with URQL + Vite. Probably due to some smart-ass preflight calls or so.

Will be glad to get help here or report a bug. A reproduction is a bit tricky on codesandbox, so I suppose downloading the archive and running it locally going to be the best way to test it.

Current behavior

Not a single request to /graphql works despite handlers being registered.

Expected behavior

Everything works perfectly with all requests getting intercepted returning data.

mayteio commented 1 year ago

Reproducible demo - this is just CRA with storybook, urql and msw/storybook-addon-msw.

  1. clone
  2. npm install
  3. npm run storybook
  4. navigate to the "header -> logged in" story and check the console - MSW is enabled but the graphql call is not being intercepted

+1 - we've noticed this since updating to urql's latest version (4.x.x). We've noticed it specifically in storybook, but it seems it's an issue for a handful of people across jest, storybook, vite so I'm posting the issue here. I've used storybook in my demo because it pertains to our issues.

Screenshot 2023-04-14 at 9 12 36 am

Screenshot 2023-04-14 at 9 10 31 am

RIP21 commented 1 year ago

@mayteio I think it's related to URQL getting smarter and shipping some cool stuff such as multipart etc. support out of the box without special exchanges and whatnot.

E.g this https://github.com/urql-graphql/urql/issues/3114

But it's not a BUG of URQL, not at all, I think it's just MSW isn't compatible with these things or so. I think this will be sorted with the next major release of MSW, unsure if addressable now which is a bit pity.

mayteio commented 1 year ago

Yep - makes total sense. Thanks for the info! I'd love to see continued support.

tnyo43 commented 1 year ago

Since version 4.0.0, urql started to support for 'text/event-stream' response (https://github.com/urql-graphql/urql/pull/3050). Because msw just bypasses server sent event, urql requests are not intercepted.

https://github.com/mswjs/msw/blob/670dda7b97f6430418d6faf09698f9a1bca5cf07/src/mockServiceWorker.js#L91-L94

Actually it's not a technical issue of msw but an issue of Service Worker (https://github.com/mswjs/msw/issues/156#issuecomment-627880763).

As a solution for now to use both urql and msw together, I recommend you to add fetchOptions to your urql client (I created a PR for @mayteio 's demo https://github.com/mayteio/storybook-msw-urql/pull/1).

export const graphqlClient = createClient({
  url: 'http://localhost/graphql',
  exchanges: [fetchExchange],
  fetchOptions: { headers: { accept: '*/*' } } // <- overwrite accept of the request header
});
mayteio commented 1 year ago

Thanks @tnyo43! What are the implications of accepting /? Would a regular application/json suffice?

tnyo43 commented 1 year ago

* is just a wild card and accept: */* means it accepts any content types. (https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept#directives)

scottrippey commented 1 year ago

This issue seems to affect all users of Urql v4 ... which seems like a pretty big deal.

Around 2 months ago, URQL added these headers by default: https://github.com/urql-graphql/urql/blob/1470a9c7474c75b65303b503c0a3a51e895f1a38/packages/core/src/internal/fetchOptions.ts#L125-L126

Accept: application/graphql-response+json, application/graphql+json, application/json, text/event-stream, multipart/mixed

It seems to me like msw should be looking for an Accept type that it likes (eg. application/graphql-response+json, application/graphql+json, application/json), rather than skipping just because it finds one it doesn't like. I'd be happy to create a PR, if this seems reasonable?

kettanaito commented 1 year ago

Hi, @scottrippey. As far as I understand the issue, URQL sends the Accept: text/event-stream request header by default, which causes MSW to skip those requests in the browser because we don't have the event stream support at the moment. I am not aware of any other logic that would skip or ignore an outgoing request based on the Accept request header.

scottrippey commented 1 year ago

@kettanaito You're correct, the presence of text/event-stream is why MSW skips these requests. However, URQL's Accept header has five acceptable formats, not just text/event-stream -- it also lists application/json, and other GraphQL-spec ones.

Unfortunately, MSW's logic says "if text/event-stream is present, MSW cannot handle this request". I'd suggest that the logic should be improved. For example, "if any of the following accept types is present, MSW CAN handle this request: application/json, text, etc..."

naorz commented 1 year ago

Hi,

I've encountered a specific issue while using msw to mock my GraphQL requests. Despite my efforts, I'm receiving responses that appear to originate from my actual server, rather than the expected mock responses. It seems that the mockServiceWorker is not intercepting the requests as intended.

To gain further insights into the problem, I decided to experiment with REST mocks. Unfortunately, I found that the worker is not functioning as expected in this scenario either. However, I can confirm that the service worker itself is being successfully loaded.

Here are the details of my environment:

To reproduce the issue, I created an isolated environment using the command npm create vite@latest with React, TypeScript, and SWC. I installed msw, and in the attached image, you'll find all the code changes I made. Additionally, the second image demonstrates that the web service is indeed loaded successfully according to the web console, and it appears to be functioning correctly.

Despite these observations, I'm still encountering a 404 error. It's worth mentioning that I've double-checked the accept header, ensuring it includes application/json and */*, and I've also verified that the handler is correctly sending the expected content type in the response. However, the issue persists.

I kindly request your assistance and guidance in resolving this matter. Any help would be greatly appreciated.

code

web

kettanaito commented 4 months ago

@naorz, I have some time to look into this. Please send me the link to that public reproduction repo. Thanks!