Msw: Question: why I cannot see my request even cannot see it x-powered-by: msw

Created on 2 Dec 2020  ·  15Comments  ·  Source: mswjs/msw

Environment

| Name | Version |
| ------- | ------- |
| msw | 0.24.0 |
| browser | chrome |
| OS | MacOS 11.0.1 |

Request handlers

``` Recipes.spec.tsx
const allRecipes = {
"0": {
"id": "1",
"text": "burger"
},
"1": {
"id": "2",
"text": "fish"
},
"2": {
"id": "3",
"text": "pizza"
},
"3": {
"id": "4",
"text": "lazagne"
}
}

const server = setupServer(
rest.get('http://myurl/receipes', (_, res, ctx) => {
ctx.status(200)
return res(ctx.json({ allRecipes }))
})
)
beforeAll(() => server.listen())
afterAll(() => server.close())

test('fetches and displays all receipes', async () => {
render()
const listItems = await screen.findAllByRole('listitem')
expect(listItems).toHaveLength(8)
expect(listItems[0]).toHaveTextContent('burger')
expect(listItems[1]).toHaveTextContent('fish')
expect(listItems[2]).toHaveTextContent('pizza')
})


## Actual request: Recipes.tsx

```js
export default function Recipes() {
      const [recipes, setRecipes] = useState({})
          const fetchAllRecipes = async () => {
            const response = await fetch('http://myurl/receipes')
            if (response.ok) {
              const jsonResponse = await response.json()
              setRecipes(jsonResponse)
            }
          }

          useEffect(() => {
            fetchAllRecipes()
          }, [])
return (
    <div>
      <ul>
        {Object.entries(recipes).map((element: any) => (
         <li>{element[1].id}</li>
 <li> {element[1].text}</li>
        ))}
      </ul>
    </div>

Current behavior

When I run the test it works for others but for the current one it fails to test it despite that I have added whatwg-fetch dependency for using node to fetch the request but somehow it cannot render the element and it shows this result:

 ● fetches and displays all receipes

    expect(received).toHaveLength(expected)

    Expected length: 8
    Received length: 2
    Received array:  [<li />, <li />]

      46 |
      47 |   const listItems = await screen.findAllByRole('listitem')
    > 48 |   expect(listItems).toHaveLength(8)

also in the browser it's not showing that it is x-powered-by: msw but instead it is showing x-powered-by: Express

Expected behavior

The expected behavior is to have a length of the recipes as 8 but its not showing them

So is there something wrong with it or it me who is configuring things incorrectly?
PS: I wanted to give a thank about the package as it is super helpful and super powerful and I love it!

bug potentially solved browser

Most helpful comment

I understand the issue, I didn't see before. @timdeschryver has right you should do has he suggested or you can
return directly the object. There is also another issue, the status should be inside res function

return res(ctx.status(200),ctx.json(allRecipes))

All 15 comments

Hi @logger-ctrl thanks for reaching us :).

Could I ask you to add the onunhandledrequest option.

beforeAll(() => server.listen({ onUnhandledRequest: 'error' }))

it should print an error in the console, it seams everything ok in your code.

I do think there's something wrong with the code, does it render correctly in the browser?
The mocked response has the following structure:

{ 
  "allRecipes": {...}
}

I'm not fluent in react, but I suppose you have to "grab" allRecipes from the response body before invoking Object.entries.
E.g.:

Object.entries(recipes.allRecipes)

The code is ok because he has taken the data from await response.json() and saved into the state.

I understand the issue, I didn't see before. @timdeschryver has right you should do has he suggested or you can
return directly the object. There is also another issue, the status should be inside res function

return res(ctx.status(200),ctx.json(allRecipes))

@marcosvega91 and thanks and it is working fine, but why I can't see in my response X-Powered-By: msw ? is there something wrong with it?

Do you mean in the browser network ?

@marcosvega91 yes in the network browser

Could you share the part of the code with the setup for the worker ?

I think @timdeschryver is right in pointing out the JSON body structure is not referenced correctly.

const allRecipes = {...}

ctx.json({ allRecipes })

The response body will look as follows:

{
  "allRecipes": [...]
}

This is the object you would get here:

const jsonResponse = await response.json() // { allRecipes: [...] }
setRecipes(jsonResponse)

Your recipes state now is an object with a single key "allRecipes". This is why when you get an enties from it you receive a single [key, value] pair:

Object.entries(recipes)
// ["allRecipes", [...]]

Mapping this object implies 1 iteration that correctly produces 2 <li> elements, according to your component's render logic. This is why you get 2 items, and not the expected 8.

Solution

const jsonResponse = await response.json()
setRecipes(jsonResponse.allRecipes)

@marcosvega91 @kettanaito I have generated browser and a handlers files under src/mock/ as the documentation says but I'm not using CRA t create my app but I'm creating my app with webpack and a custom jest file and I'm building my app in the dist folder but only when I build I have the chunks and that folder, so I didn't really know where to generate the serviceWorker file with msw CLI

Ah ok, so I think that I understand your problem.

I guess that you have bootstrapped MSW using only setupServer. If this is the case, setupServer is not enough for the browser, you need to use setupWorker for the browser and setupServer for your unit tests. MSW is using service workers to intercept requests in the browser.

https://mswjs.io/docs/getting-started/integrate/browser

@marcosvega91 I have followed this docs before actually, and I have browser.ts config:

import { setupWorker } from 'msw'
import { handlers } from './handlers'
export const worker = setupWorker(...handlers)

and my server.ts config:

import { setupServer } from 'msw/node'
import { handlers } from './handlers'
export const server = setupServer(...handlers)

and in my index.tsx:

import React from 'react'
import ReactDOM from 'react-dom'
import App from './App'

if (process.env.NODE_ENV === 'development') {
  const { worker } = require('./__tests__/test/mock/browser')
  worker.start()
}
ReactDOM.render(<App />, document.getElementById('root'))

and my handlers.ts:

import { rest } from 'msw'

const allRecipes = {}
export const handlers = [
  rest.get('merl', (_, res, ctx) => {
    ctx.status(200)
    return res(ctx.status(200), ctx.json(allRecipes))
  })
]

and then I'm getting this error in my console:

[MSW] Failed to register a Service Worker for scope ('http://localhost:8080/') with script ('http://localhost:8080/mockServiceWorker.js'): Service Worker script does not exist at the given path.
Did you forget to run "npx msw init <PUBLIC_DIR>"?
Learn more about creating the Service Worker script: https://mswjs.io/docs/cli/init

Is that what it should be done in a normal config or something else is needed? 🤔

As the error suggests, there is no worker script in your public directory. Did you finish the setup step? It concludes by using the npx msw init command that copies the worker script into the public directory you've specified.

@kettanaito Yes I have followed the steps, but I have a custom webpack config files where I the build will be under a ./dist folder and I don't have a public folder where my html file is there, but instead I have my index.html file inside src folder where I configure my app to be injected inside it during the build, while npx msw init is initialized my mockServiceWorker.js file inside src at the same level where my app would sit, so is it enough?

It looks like you don't have the worker script (mockServiceWorker.js) placed correctly in your public directory.

Examine your webpack configuration and see where the static assets go (i.e. images/fonts). The worker script needs to be located in the same directory.

To verify that you've placed the worker correctly, navigate to http://localhost:8080/mockServiceWorker.js and you should see the worker script's contents. If that URL gives you 404, or any other resource, that implies the worker is not in the public directory, and so MSW fails to find and activate it (the error message you get in the console).

I will close this issue because it doesn't appear to be a library issue. That doesn't mean that we won't help you figure it out, so keep us updated with your progress. Thanks.

Was this page helpful?
0 / 5 - 0 ratings