Msw: Create React App - Mocks work only every 2nd page reload

Created on 26 Aug 2020  路  5Comments  路  Source: mswjs/msw

Environment

| Name | Version |
| ------- | ------- |
| msw | 0.20.5 |
| browser | Chrome 84.0.4147.125 (Official Build) (64-bit) |
| OS | Kubuntu 20.04, 5.4.0-42-generic

Request handlers

handlers.ts, taken from the official tutorial + a simple get route

import { rest } from 'msw'
export const handlers = [
  rest.get('http://localhost:3001/test', (req, res,ctx) => {

    return res(ctx.json({key: "value"}));

  }),
  rest.post('/login', (req, res, ctx) => {
    // Persist user's authentication in the session
    sessionStorage.setItem('is-authenticated', "true")
    return res(
      // Respond with a 200 status code
      ctx.status(200),
    )
  }),
  rest.get('/user', (req, res, ctx) => {
    // Check if the user is authenticated in this session
    const isAuthenticated = sessionStorage.getItem('is-authenticated')
    if (!isAuthenticated) {
      // If not authenticated, respond with a 403 error
      return res(
        ctx.status(403),
        ctx.json({
          errorMessage: 'Not authorized',
        }),
      )
    }
    // If authenticated, return a mocked user details
    return res(
      ctx.status(200),
      ctx.json({
        username: 'admin',
      }),
    )
  }),
]

browser.ts, taken from the official tutorial

// src/mocks/browser.js
import { setupWorker } from 'msw'
import { handlers } from './handlers'
// This configures a Service Worker with the given request handlers.
export const worker = setupWorker(...handlers)

Starting the worker, right above React.render

  if (process.env.NODE_ENV === "development") {
    const { worker } = require("./mocks/browser");
    console.log(worker);
    worker.start();
  }

  ReactDOM.render(
    <React.StrictMode>
      <App />
    </React.StrictMode>,
    document.getElementById("root")
  );

Request logic

  useEffect(() => {
    setTimeout(async () => {
      {
        const resp = await fetch("http://localhost:3001/test");
        console.log(await resp.text());
      }
    }, 1000);
  }, []);

Current behavior

Mocking works only every 2nd page refresh. I can keep mashing F5, and only every 2nd refresh comes the expected response (CTRL+F5, that is hard refresh, makes it work every time).

During the non-working refreshes:

  • If the request is made to the same origin as the webpack devserver, simply the page's source is sent back (Example: fetch('/test') or fetch('http://localhost:3000/test'))
  • If we're mocking under a different mask, such as fetch('http://localhost:3001/test'), this is sent back:
GET http://localhost:3001/test net::ERR_CONNECTION_REFUSED
App.tsx:12 Uncaught (in promise) TypeError: Failed to fetch

Moreover, attemping to load the service worker asynchronously makes the mock work only on the initial load (then you need to unregister the worker, and refresh the page to have it work again... for just one time).

(async () => {
    if (process.env.NODE_ENV === "development") {
      const { worker } = await import("./mocks/browser");
      console.log(worker);
      await worker.start();
    }

    ReactDOM.render(
      <React.StrictMode>
        <App />
      </React.StrictMode>,
      document.getElementById("root")
    );

    // If you want your app to work offline and load faster, you can change
    // unregister() to register() below. Note this comes with some pitfalls.
    // Learn more about service workers: https://bit.ly/CRA-PWA
    serviceWorker.unregister();
  })();

Expected behavior

Mocking works every refresh.

Repo link

Click

bug browser

Most helpful comment

Ho @Sun-2 thanks for raising this :).

The problem with your example is that the CRA will unregister MSW serviceWorker with this line of code serviceWorker.unregister(). To use MSW you should remove this line. Maybe we can add this into the documentation. What do you think @kettanaito ?

All 5 comments

Ho @Sun-2 thanks for raising this :).

The problem with your example is that the CRA will unregister MSW serviceWorker with this line of code serviceWorker.unregister(). To use MSW you should remove this line. Maybe we can add this into the documentation. What do you think @kettanaito ?

@marcosvega91 Great find.

Unless I'm misunderstanding, I think this should probably lead to a PR into CRA as well - it seems irresponsible to call unregister at all without any logic to find the correct worker registration. I'd imagine that this is also why this line is stripped from the Code Sandbox React templates. It's also interesting that they always call unregister in any environment, but only register in production? 馃く

I'll open a PR on CRA to understand

Thank you guys, splendid. This cost me a lot of time thinking I messed up some simple config somewhere.
No idea why on earth CRA would choose to unregister all SW's.

Since this is more of a CRA issue, I guess we can close this one?

Yes we are also adding a note on the doc. Thank you 馃槃

Was this page helpful?
0 / 5 - 0 ratings