-
-
Notifications
You must be signed in to change notification settings - Fork 503
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
Add example how to use with Cypress #1560
Comments
Hey, @TeemuKoivisto. That's a good suggestion. What we should have done long time ago is showcased how to correctly use MSW with Cypress. Currently, we have a minimal usage example which will be fine for some percentage of use cases but it is not fully correct in terms of awaiting MSW's worker while running tests in Cypress. I recall someone from the community posting a fantastic example of how they use a custom Cypress plugin (or a different terminology) that allows them to import and await MSW as a part of their Cypress run vs exposing MSW on
|
@kettanaito great and thanks! Yeah it's a little complicated so I wager I'd be nice to have a solid example to make people less hesitant to use |
@TeemuKoivisto This is a blog post I wrote awhile back but its a little outdated at this point. I could potentially re-write it to deal with Cypress v10 and above if you need it. Hope it helps. |
The blog post from @Capocaccia is one of the best integration examples I've seen. Posting here for clarity: //cypress/support/index.js
import { worker } from '../../src/mocks/browser';
Cypress.on('test:before:run:async', async () => {
await worker.start();
}); The idea they propose here is to start the worker in Cypress' internal hook. I think this is marvelous. Give it a try.
|
Just as an update, I had to remove So I added a hacky if-else like this: let worker: DriveWorker;
// @ts-ignore
if (window.Cypress) {
// Don't use workers inside Cypress since Cypress uses workers itself heavily which deprioritizes
// our workers, taking forever to run
const postWorkerMsg = (ev: WorkerEvent) => {
worker.onmessage({ data: ev });
};
const workerSelf = {
onmessage: onmessage({ postMessage: postWorkerMsg }),
postMessage: postWorkerMsg,
};
worker = {
onmessage: (ev: { data: WorkerEvent }) => {},
postMessage(msg: ClientEvent) {
workerSelf.onmessage({ data: msg });
},
terminate() {},
};
} else {
worker = new Worker(
// @ts-ignore
new URL("../../workers/driveWorker", import.meta.url),
{ type: "module" },
) as DriveWorker;
} to switch back to single-threaded execution while in Cypress. Something similar probably happens with Now that I added this if-else hack, I perhaps could await |
I stand by that the simplest and most straightforward integration is just following the Browser integration for your entire app, enable it conditionally during the Cypress run (env variables are your friends) and get client-side request interception out of the box. Since you await responses anyway, you are unlikely to deal with race conditions as long as you write correct assertions, which you should be doing regardless of the API mocking library of choice. I will try to add a Cypress usage example to the new examples repo to have a single point of reference and close this issue afterward. |
@kettanaito I concur that using similar conditional env I was able to launch the app and use msw in Cypress. It was only my other workers which then failed. Probably with that new hack & reverting to using env for msw it could work but it just got too much at that point. |
I think the easiest way to implement MSW within Cypress without exposing worker to the Also it works with OOB Intercept by Cypress but this way you can reuse you handlers if you already implement them for your app. Note: Just make sure to expose the file in import { setupWorker, type SetupWorker, type RequestHandler } from 'msw'
declare global {
namespace Cypress {
interface Chainable {
interceptRequest(...handlers: RequestHandler[]): void
}
}
}
let worker: SetupWorker
before(() => {
worker = setupWorker()
cy.wrap(worker.start({ onUnhandledRequest: 'bypass' }), { log: false })
})
Cypress.on('test:before:run', () => {
if (!worker) return
worker.resetHandlers()
})
Cypress.Commands.add('interceptRequest', (...handlers: RequestHandler[]) => {
worker.use(...handlers)
}) Import into import './msw' Now you can use worker to mock requests: import { rest } from 'msw'
it('visit app', () => {
const handler = rest.post('/api/items', (req, res, ctx) => {
return res(
ctx.status(200),
ctx.json([
{ name: 'apple' },
{ name: 'orange' },
]))
})
cy.interceptRequest(handler)
// your app inside will fetch '/api/items'
cy.visit('/')
}) I hope it helps! |
great
Great example! can you show an repo? |
There you have msw-cypress it's just simple. |
Thanks all for sharing! I just integrated MSW into Cypress with a small tweak since // cypress/support/e2e.{js,jsx,ts,tsx}
import { worker } from '../../src/mocks/browser';
Cypress.on('test:before:run:async', async () => {
await worker.start();
}); |
Can someone please open a pull request to One question: does this approach allow one to reference the worker instance in tests to append runtime handlers with Examples using Cypress |
I'll take a look |
@kettanaito I ran up against this the other day and went ahead and put together a small, easily reproducible example using the latest Cypress and MSW that shows the constant restart issue very clearly. Grab that zip, run Now, stop that process and run Open up What is even crazier is that i had this same setup at a prior employer with msw 1.3.2 and I had it all working correctly. I even tried to duplicate that in this example repo (separately) with that version of msw and now I can't even get that working as well, so not sure how it ever worked previously :\ That project had a much more elaborate setup but I tried to boil it down to what I would think would be sufficient and still could not get it to work in the older version of msw. |
I’m also seeing this issue with the Cypress test runner getting in a crazy infinite loop after trying to move from a webpack config to vite. @reintroducing small tip, you can use I feel like because this worked before in Webpack this is very likely a vite-related Cypress regression. Have you raised there? |
@MattyBalaam i previously had this working in Vite so not exactly sure where the problem is, unfortunately. |
@reintroducing Was that vite 4, rather than vite 5? |
@MattyBalaam good call, it was Vite 4.4.4 and msw 1.3.2 |
OK, I think I got it. There is a badly documented cypress-io/cypress#28347 (comment)
|
@MattyBalaam ooooohhhh, thats promising. so this isn't an msw issue after all? at this point i don't even know where i'd log a bug for this :\ |
Yeah, it’s more a documentation and error handling issue really I think. Possibly there could be something MSW could do here if it is retiggering a reload as I see that in some of the code… but could also be more in Cypress’s court to handle that better. @kettanaito any thoughts here? |
Is there something like this for nextjs? If you also know something about how to intercept requests made by the nextjs middleware (server side request) it would help a lot, I'm having a lot of problems with this |
Scope
Improves an existing behavior
Compatibility
Feature description
Hi, I just recently faced a really bizarre bug where my
window.location.pathname
would not be updated to correct path when I hadmsw
enabled.Turns out, since there was a home page outside the main Vue app that loaded without
msw
and inner app withmsw
there was no time formsw
to completely load.I had to add following checks to ensure it had loaded:
So my small request is, could this be added to some Cypress example in how to use msw? I'm pretty sure I won't be the only one stumbling across this and scratching their head for a long while since to cause is not so obvious.
Showing that you should load
msw
first with eg:And then say add a command:
With your
cypress/support/index.d.ts
looking like:And use it at the start of your test:
Thanks for the library though!
EDIT: Okay, it broke again. I thought I had it working but apparently when
msw
is enabled something goes wrong withvue-router
. If I callhistory.pushState
manually it works again.EDIT EDIT: Cypress really doesn't go along well with
msw
. Here's an example I got working https://github.com/TeemuKoivisto/sveltekit-monorepo-templateThe text was updated successfully, but these errors were encountered: