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

RFC: Fallback mode #663

Closed
kettanaito opened this issue Mar 25, 2021 · 11 comments · Fixed by #688
Closed

RFC: Fallback mode #663

kettanaito opened this issue Mar 25, 2021 · 11 comments · Fixed by #688
Assignees
Labels
feature scope:browser Related to MSW running in a browser

Comments

@kettanaito
Copy link
Member

kettanaito commented Mar 25, 2021

Description

Fallback mode is an alternative request interception mechanism applied in a browser. Fallback mode is automatically enabled by the library when either of the following conditions is met:

  • The browser doesn't support the Service Worker API;
  • The user has navigator.cookieEnabled set to false that forbids access to the worker;
  • The application is loaded using the file:// protocol.

Motivation

Fallback mode is aimed at improving the browser support and enabling the library in static builds of various tools (i.e. Storybook).

Statements

  1. Fallback mode is enabled automatically by the library.
  2. There is no way to opt-out of the fallback mode.
  3. There is no way to enable the fallback mode when the worker can be used instead.
  4. Requests intercepted via the fallback mode do not appear in the "Network" tab and don't actually happen (see technical details).

Technical details

Fallback mode is powered by the recent addition of the fetch and XMLHttpRequest interceptors to the @mswjs/interceptors library. Under the hood, fallback mode patches window.fetch and window.XMLHttpRequest to provision the interception of requests.

Fallback mode is similar to the way most other API mocking solutions work: patching the in-browser request modules. In Mock Service Worker fallback mode will only affect the library's behavior in the environments where Service Worker API cannot be otherwise used.

Pre-requisites

Public API

There are no changes to the public API related to this feature. Fallback mode is enabled automatically, when necessary.

The only user-facing change would be the change of the library's activation message:

[MSW] Mocking enabled (fallback-mode).

In addition to the activation message change, the library should print the warning message indicating that the worker couldn't be registered in the current environment:

[MSW] Cannot register a Service Worker in the current environment. Using the fallback mode instead.

Read more about the fallback mode: <DOCS_LINK>
@otaciliolacerda
Copy link
Contributor

otaciliolacerda commented Mar 28, 2021

Hi @kettanaito,

Another condition could be to check navigator.cookieEnabled. I was trying to test a scenario on my app where the cookies where disabled but I could not use the mock service due to the error: The user denied permission to use Service Worker. The fallback mode would be nice on this case.

@kettanaito
Copy link
Member Author

Hey, @otaciliolacerda. I didn't know that navigator.cookieEnabled blocks access to the worker. Thank you for sharing this. Sounds like a good case to enable the fallback mode then. I Will account for that in tests.

@kettanaito kettanaito self-assigned this Mar 28, 2021
@kettanaito kettanaito added the scope:browser Related to MSW running in a browser label Mar 28, 2021
@LarsDenBakker
Copy link

+1 to this. Using the implementation for node as a base, I was able to set up the XHR and fetch interceptors (removing the client interceptor) and this worked at least for the basics.

I had to change the rollup config to prioritize the browser field over the main field, so that the browser version of the debug module was used.

@romaolucas
Copy link

Hey @kettanaito is there a reason why we don't see the requests in the network tab when MSW is using fallback mode?

@kettanaito
Copy link
Member Author

Hi, @romaolucas. Yes, there is. The fallback mode activates automatically in a browser that cannot run Service Worker for one reason or another. Since we cannot run the worker, we cannot intercept requests on the network level. Thus, you don't see the requests there.

Instead, we employ a more conventional interception by stubbing fetch and XMLHttpRequest only during the fallback mode. The behavior you're experiencing is intended. But the fact that your app cannot register a worker is, probably, not. I recommend you look into that.

@catch99
Copy link

catch99 commented Jun 29, 2022

If i understood it correctly it falls into fallback mode also in non-secure context?

@kettanaito
Copy link
Member Author

Hey, @catch99. Yes, you've understood correctly. Insecure contexts, such as serving an app over HTTP or an untrusted HTTPS, are where a Service Worker cannot register per spec. Instead of leaving you with a broken state, MSW falls back to a more conventional fetch/XHR patching to still keep the mocking functional.

@ahayes91
Copy link

ahayes91 commented Jul 26, 2024

Hey @kettanaito! I appreciate this one is hard to completely answer without a reproduction library and I'm working on it, but question about fallback mode.
I'm seeing "fallback mode" kicking in when I run Cypress in a docker image against a local running instance of Storybook (https://www.cypress.io/blog/2019/05/02/run-cypress-with-a-single-docker-command#Interactive-mode are the docs I followed to see the message in the console that MSW is running in fallback mode).

I'm mocking an image response with the instructions in https://mswjs.io/docs/recipes/responding-with-binary/ in my Storybook entry (using await fetch in the mock handler), and I noticed that it doesn't work in fallback mode.

Can you suggest any other way to mock an image request so that it still works in fallback mode? Thank you!

@kettanaito
Copy link
Member Author

Hi, @ahayes91. That's interesting. So, the fallback mode only ever kicks in if (1) the Service Worker API is not available in the current context; (2) your application is server over non-HTTP protocol (like file://). If that's the case, and the fallback mode is intended, then everything is okay.

Regarding the image binary mocking, I can't think of a reason it wouldn't work. The fallback mode relies on our Fetch and XHR interceptors, and those are rather well-tested. Can you please provide your request handlers and the request for the image itself? Of course, a full reproduction repo would be best.

@ahayes91
Copy link

Thank you @kettanaito for the speedy response! I think this one will definitely be best answered with a reproduction repo, so let me get back to you in a few hours (hopefully, but it could be a few days 😅).

@ahayes91
Copy link

ahayes91 commented Jul 26, 2024

@kettanaito I've got something here at https://github.com/ahayes91/msw-cypress-docker-storybook if you could have a look 🙇‍♀️ and thank you!

Edit - raised #2225 for this, figured that's easier to keep track of!

@github-actions github-actions bot locked and limited conversation to collaborators Oct 29, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
feature scope:browser Related to MSW running in a browser
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants