Open lmiller1990 opened 3 years ago
We managed to get Cypress to work with Service Workers using Workbox. Key is simply to tell the SW not to cache (or precache) any Cypress resources:
const navigationRoute = new NavigationRoute(handler, {
denylist: [
new RegExp('/__'),
new RegExp('cypress'),
],
});
Then add a rule which forces all Cypress requests to be network-only:
registerRoute(
(request) => request.url.includes('cypress'),
new NetworkOnly(),
);
We managed to get Cypress to work with Service Workers using Workbox. Key is simply to tell the SW not to cache (or precache) any Cypress resources:
const navigationRoute = new NavigationRoute(handler, { denylist: [ new RegExp('/__'), new RegExp('cypress'), ], });
Then add a rule which forces all Cypress requests to be network-only:
registerRoute( (request) => request.url.includes('cypress'), new NetworkOnly(), );
Thanks for sharing that @csvan ! @kettanaito do you think this could help msw?
Hey, @yannbf. I think it may but I'd like to learn more about the context: what is NavigationRoute
? What is NetworkOnly
? Is there a solution using a barebone Service Worker API (afaik Workbox is an abstraction on top Service Workers)?
The root issue also seems different at the first glance. MSW doesn't cache anything. So the situation when a Cypress resource would get cached isn't possible. Therefore, configuring any sort of whitelisting on our side is redundant. I think the actual cause for the issue lies elsewhere, and that's where I'd love to hear more feedback from developers investigating what goes wrong when they use Service Workers with Cypress.
thanks @csvan after hours of searching finally found this and while it didn't immediately work and took a bit of figuring out for our setup, managed to get it working in the end. couple points to note for anyone else, hopefully it'll save them a bit more time digging.
I'd agree with you though, this does feel a bit hacky, not sure how long before it breaks. Also have no clue at this stage what the impact of it is on the caching or offline testing. Although we have a PWA our app isn't really intended to be fully offline with local data sync and stuff, so fingers crossed it's ok for now. I did read somewhere, that the SW caching has no affect on cypress. This is certainly true in the testing I saw today, the only real issue is ensuring it forces the cypress url to be network only. But that might only be our PWA config.
I'm not sure if that's a configurable thing, but to get it working and it seemed maybe to ensure we do only capture this for the testing url (who knows someone could have a slug with cypress) we changed it to. Also this is the import for networkOnly, save having to track that down.
import {NetworkOnly} from 'workbox-strategies';
registerRoute(
(request) => request.url.includes('/__/#/'),
new NetworkOnly(),
);
const handler = createHandlerBoundToURL('/index.html');
const navigationRoute = new NavigationRoute(handler, {
denylist: [
new RegExp('/__')
],
});
registerRoute(navigationRoute);
Thanks again, really saved us.
Seems like the best solution here would just be a detailed blog post + example project? Do we need any work in Cypress to facilitate this?
@lmiller1990 yeah sounds good if that's the way you guys like to role. I think there's a number of issues related to service workers spread out over diferent issues, possibly something that could sum them all up in one place with solutions for the ones that have them. I know I just kept on stumbling on all of the others but couldn't find this one until it crossed my mind this could be a issue specific to workbox not just a service worker thing.
Any update on this ?
Did you try the work-around suggested above?
Are you trying to use msw or just service workers in general?
const navigationRoute = new NavigationRoute(handler, { denylist: [ new RegExp('/__'), new RegExp('cypress'), ], });
Do you have a repo with this?
@lydemann not one I can share, but I'll get our test guy to chime in if he can @ashramsey
@lydemann not one I can share, but I'll get our test guy to chime in if he can @ashramsey
I'm afraid not, I haven't ever used cypress this way Im sorry.
We managed to get Cypress to work with Service Workers using Workbox. Key is simply to tell the SW not to cache (or precache) any Cypress resources:
const navigationRoute = new NavigationRoute(handler, { denylist: [ new RegExp('/__'), new RegExp('cypress'), ], });
Then add a rule which forces all Cypress requests to be network-only:
registerRoute( (request) => request.url.includes('cypress'), new NetworkOnly(), );
Thanks for sharing that @csvan ! @kettanaito do you think this could help msw?
Where do you put this in the app, can you share a snippet with imports and everything?
This works fine in my Vite example app: https://github.com/cypress-io/cypress-component-testing-apps/commit/d71e897e1c246f057a4148ad993acfd54660e020
In before
, ensure you return
- it's a promise, it needs to resolve and msw has to start before the test runs:
before(() => {
// return here! Don't forget.
return worker.start();
})
worker.start
Hi, thanks.
Do you have an Angular example as well? I see you haven't set up MSW for the Angular app here.
publicPath
) and msw cannot fetch the mockServiceWorker.js
file. I don't know why yet.This issue has not had any activity in 180 days. Cypress evolves quickly and the reported behavior should be tested on the latest version of Cypress to verify the behavior is still occurring. It will be closed in 14 days if no updates are provided.
Has anyone got a solution or a workaround for this in an Angular app?
setup
using the regular mockServiceWorker.js
on ./public
component tests would refresh on an infinite loop when trying to start the worker:
support/component.ts
test:before:run:async
hook inside support/component.ts
before
call inside a spec file.\support\component-index.html
in all these cases the worker would be started as worker.start({ serviceWorker: { url: "http://localhost:5173/__cypress/src/mockServiceWorker.js" } });
I modified the cypress 13.11.0 installation files to add the service worker script at the top most frame of the runner, the worker would register correctly
no looping but was not able to capture request happening inside the spec runner. My theory is that this did not work because of some reasons:
http://localhost:5173/__cypress/src/
where MSW is served from vs http://localhost:5173/__cypress/iframes
where the iframe that runs the specs is served fromsrc
initially, which as I understand makes it so that it the worker cannot be inherited and then src
gets replaced later.
http://localhost:5173/__cypress/src/mockServiceWorker.jsPlacing a copy of mockServiceWorker.js
inside AppData\Local\Cypress\Cache\13.11.0\Cypress\resources\app\packages\app\dist\assets\
allowed me to change the worker start url to worker.start({ serviceWorker: { url: "http://localhost:5173/__cypress/iframes/mockServiceWorker.js" } });
, this would enable the service worker to register correctly, have correct scope and be able to capture request.
From here I was able to initialize the worker directly inside support/component.ts
, using the event test:before:run:async
or on a before
call inside the specs, warning there are timing issues, on some of these approaches the specs run before the worker is finished setting up.
Sorry I don't have a solution to set all this up, just wanted to share what I've found so far, hopefully this can hint to a proper solution.
Current behavior
Weird behavior with service workers (or at least, mock service worker) in component testing.
See: https://github.com/mswjs/msw/issues/744
Desired behavior
It should work.
Test code to reproduce
https://github.com/mswjs/msw/issues/744#issue-898881738
Versions