msw: Unable to intercept requests sent during pre-rendering in Next.js

Prerequisites

Environment check

  • I’m using the latest msw version
  • I’m using Node.js version 14 or higher

Node.js version

v18.3.0

Reproduction repository

https://github.com/ajfAfg/msw-operation-research

Reproduction steps

  1. Run the following commands
git clone https://github.com/ajfAfg/msw-operation-research.git
cd msw-operation-research/nextjs-rest
npm install
npm run dev
  1. Open http://localhost:3000

Current behavior

In src/pages/index.tsx, getServerSideProps fetches data and outputs the received data to the console. Currently, the output is as follows.

server: {"answer":"yes","forced":false,"image":"https://yesno.wtf/assets/yes/14-b57c6dc03aa15a4b18f53eb50d6197ee.gif"}

The data being fetched here is as follows.

$ curl https://yesno.wtf/api
{"answer":"yes","forced":false,"image":"https://yesno.wtf/assets/yes/11-a23cbde4ae018bbda812d2d8b2b8fc6c.gif"}

Expected behavior

The expected output is as follows, since the request is intercepted by the definition in src/mocks/handlers.ts.

server: {"foo":"bar"}

About this issue

  • Original URL
  • State: open
  • Created 2 years ago
  • Reactions: 3
  • Comments: 17 (3 by maintainers)

Most upvoted comments

Anyone got this working in Next13 ?

@kettanaito The issue with NextJS and MSW being enabled to intercept client side requests still exists.

Using node: v16.18.1 npm: 8.19.2

I’ve managed to fix the issue. But it involved changing a few things in the Next.JS setup. Had to enable webpack experiments of topLevelAwait along with changing TypeScript tsconfig.json target from ES5 to ESNext

So I could change _app.tsx from using

  require('../mocks')

to

  await import('../mocks')

You can see all the changes in this commit https://github.com/andykenward/next-with-msw/commit/91d9bbda12baff864913dc9eb95e7d921d75fb27

To reproduce the client side error before the above changes, checkout commit https://github.com/andykenward/next-with-msw/commit/3d00db8f66b12e5496881b18bbd3b903a479f0df

You should get this error on the server from the client side fetch happening in a useEffect

error - FetchError: request to https://my.backend/book failed, reason: getaddrinfo ENOTFOUND my.backend
    at ClientRequest.<anonymous> (/Users/andykenward/Documents/github/andykenward/next-with-msw/with-msw-pages/node_modules/next/dist/compiled/node-fetch/index.js:1:65756)
    at ClientRequest.emit (node:events:513:28)
    at TLSSocket.socketErrorListener (node:_http_client:494:9)
    at TLSSocket.emit (node:events:513:28)
    at emitErrorNT (node:internal/streams/destroy:157:8)
    at emitErrorCloseNT (node:internal/streams/destroy:122:3)
    at processTicksAndRejections (node:internal/process/task_queues:83:21) {
  type: 'system',
  errno: 'ENOTFOUND',
  code: 'ENOTFOUND',
  page: '/'
}

I’ve started to also look into using the new Next.JS app directory changes they are currently working on. But haven’t managed to get it working yet. https://github.com/andykenward/next-with-msw/tree/main/with-msw-app . Will probably hold off until msw native fetch support version is released.

I am seeing this error in NextJS 13 when using the pages directory. The MSW server is unable to intercept server-side requests reliably. You can reproduce this by running the official with-msw example. It will throw this error from the request in getServerSideProps:

 ⨯ TypeError: fetch failed
    at Object.fetch (node:internal/deps/undici/undici:11576:11)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
    at async getServerSideProps (webpack-internal:///./pages/index.tsx:88:17) {
  cause: Error: getaddrinfo ENOTFOUND my.backend
      at GetAddrInfoReqWrap.onlookup [as oncomplete] (node:dns:108:26) {
    errno: -3008,
    code: 'ENOTFOUND',
    syscall: 'getaddrinfo',
    hostname: 'my.backend'
  },
  page: '/'
}

It also does not work if you upgrade the example to msw@next.

In my own app, I see that server side requests are occasionally intercepted, but most times not.

I have also opened an issue in Next.js: https://github.com/vercel/next.js/issues/56608

@kettanaito I’ve tested the NextJS MSW template and it doesn’t work at all, I’ve reported it to them, but if you have any idea how to make it work, that would be awesome 😁 vercel/next.js#43221

Thanks!

@watch-janick The NextJs MSW example is using an exact version of msw 0.47.3 and doesn’t install the latest version. If you update it to the latest version 0.49.0 it should work. I’ve fixed the example in this PR https://github.com/vercel/next.js/pull/43224

@andykenward re: the app directory, https://twitter.com/housecor/status/1592718956288413696 suggests you can get it working by putting the mocks import inside the RootLayout exported function, whereas in your repo it’s in the layout.tsx file but not inside the exported function.

I tried that and couldn’t get it working, but thought I’d share this just in case you have more luck with it than I did!

@philwolstenholme I’ve not managed to get msw working using the app directory Next.js feature. I’ve found that layout components render after the page component, when using next dev. So any data fetching in a page that needs msw already loaded would fail. But even moving any MSW logic to a page component didn’t help in getting MSW working.

I have found that using any top level async, throws any error in next-swc-loader. Which my fix uses.

top level await requires target to es2017 or higher and topLevelAwait:true for ecmascript

This error only threw when i removed the if statement check.

// if (process.env.NEXT_PUBLIC_API_MOCKING === 'enabled') {
  await import('../mocks')
// }

I don’ t think you are able to change the compile output target at the moment when using the app directory in Next.js.

A working example repo from the tweet author would be helpful.

I’ve found using await import instead of require was the only reliable & consistent way to have MSW loaded before fetch requests. Otherwise i was getting flaky tests etc.

@andykenward thanks man!

We’ve just recently protected our API route and we didn’t put auth headers on the request that went out to that API so we got 2 nasty surprises:

  • Some of our static built pages (especially those created getStaticPaths + getStaticProps) were going out to our real API instead of being intercepted.
  • The occurrences were random, sometimes it works, but after navigating between pages it fails.

Implementing your solution works for now!

Thanks for fixing the template, @andykenward! Does it function as expected now both in terms of client-side and server-side interception (i.e. this issue is resolved)?

@kettanaito I’ve not checked the “reproduction repository” https://github.com/ajfAfg/msw-operation-research in this issue. Will do that now and also try the latest msw 0.49.0. But I wont use node 18.