playwright
playwright copied to clipboard
[Question] How to use miragejs mocks with Playwright component tests?
I've been playing around with Playwright Component tests, and am struggling to wire up miragejs mock server with the test suite. Is there a recommended approach/solution to this?
My frontend app uses CRA and has a miragejs mock server for testing. What's the right way to initialize this in Playwright component tests?
Note: For comparison, this is how Cypress wires it up. I've tried adding a proxy function like the one Cypress uses via context.addInitScript before the test begins. I can see the function being attached to the window object, but redirect from the app doesn't seem to work.
I'm not familiar with miragejs, but based on the Cypress example and the miragejs docs, it looks like an in-browser mocking library. Since it wants to run in the browser (as opposed to the node process), context.addInitScript is the correct approach.
Please share a minimal repro (i.e. a GitHub repository we can clone and run that exhibits the error you're seeing) so we can better understand what you're experiencing and how the wiring looks. Thanks!
Thanks @rwoll for taking a look. Here's a sample repo with Playwright component tests added.
I'm setting up the proxy function here in the test beforeEach hook and forwarding network requests to it from the app here. If you try to debug the test, you can see the network request being made (miragejs should ideally be intercepting the call and it shouldn't show up in the network tab).
Thanks @VaasRamsay—I was able to use that to better understand what's going on.
A key part of Playwright is, some code runs in Node other code runs in the Browser. miragejs runs in the browser to work properly, but it looks like your code is creating the mirage server in Node—the code inside context.addInitScript will run in the browser, but the other code in that file is running in Node.
To use miragejs, all of the mirage code must be run in the browser. You can achieve that one of a few ways, but the following does work: https://github.com/rwoll/playwright-miragejs-demo. For component tests, all code in playwright/index.ts will run in the browser.
Does this make sense? If you clone that repo, you can run the tests locally and they should pass!
NB: Playwright provides its own mocking/routing functions, so if you aren't already invested in miragejs, you might consider using those as we'll be able to assist better: https://playwright.dev/docs/network#handle-requests. (I don't recommend using multiple network mocking strategies at once (e.g. Playwright's page.route/context.route + miragejs + MSW) as it will likley have unexpected behavior.)
Great, thanks @rwoll! Your example works fine with the latest update. I can use the hooks to setup the server before tests.
However, is it possible to modify the mocks from the tests somehow? For example, I could setup a clean mock server before every test and then from test A seed a single item and from test B seed hundreds of items to test my component. How can I achieve this? Jest and Cypress tests are able to do this with miragejs, wondering how to achieve similar functionality with Playwright.
@VaasRamsay Thanks for your patience! It's possible to do this functionality, but in order to give you a better answer, we'll need some more time to play around.
I've assigned this out and marked to the next milestone so we can hopefully dedicate some time to it. (It hits on topics beyond just network mocking—e.g. running code in browser vs. in node—and what to do where when, so there's probs some more holistic education/docs we can add here.)
@VaasRamsay
// playwright/index.ts
import { beforeMount } from '@playwright/experimental-ct-react/hooks';
import { createServer } from "miragejs"
beforeMount(async ({ hooksConfig }) => {
createServer({
routes() {
this.get("/api/users", () => hooksConfig.users)
},
});
});
src/Users.spec.tsx
import { test, expect } from "@playwright/experimental-ct-react";
import React from "react";
import { Users } from "./Users";
test("should work", async ({ mount }) => {
const component = await mount(<Users />, {
hooksConfig: {
users: [
{ id: "1", name: "Luke" },
{ id: "2", name: "Leia" },
{ id: "3", name: "Anakin" },
]
}
});
await expect(component.locator("li")).toContainText([
"Luke",
"Leia",
"Anakin",
]);
});
@VaasRamsay would you be open to contributing a docs page (markdown) providing this example?
@pavelfeldman PTAL https://github.com/microsoft/playwright/pull/16706
Closing with https://github.com/microsoft/playwright/pull/16706, thanks!