Msw: `server.use()` or `server.resetHandlers` do not appear to be working within/between tests

Created on 26 Jun 2020  路  16Comments  路  Source: mswjs/msw

Describe the bug

server.use() or server.resetHandlers do not appear to be working within tests.

I have a setupTests file that is appropriately calling resetHandlers (confirmed with logging) after each test.

When using a server.use statement to override a route payload like so:

server.use(
      rest.get('myUrl', (req, res, ctx) => {
        return res(ctx.json([]));
      })
    );

I would expect the result to return as an empty array. My main handlers file is setup similarly:

rest.get('myUrl', (req, res, ctx) => {
    return res(ctx.json(mockDataArray));
  })

When running all my tests, I see my mock data, and can log it to the console in the actual component implementation.

When running as part of a test suite, I do not get the overridden empty array that I want, I see the original list from the handlers.

The bug I think I've found is that if I run the test as it.only then I see the correct empty array and my test passes. My component logs out the empty array as the fetched data I was expecting. Running the tests completely by itself seems to fix the issue.

I'm hoping this is just a silly mistake on my part.

Environment

  • msw: 0.19.5
  • nodejs: 12.16.1
  • npm: 6.13.4

Please also provide your browser version. n/a

To Reproduce

Steps to reproduce the behavior:
I attempted to reproduce this behavior using the react example project, but haven't been able to yet.

Expected behavior

I have a setupTests file that is appropriately calling resetHandlers (confirmed with logging) after each test. When using server.use to setup a route override, I should get the payload assigned (as one would expect from the docs as well as the example project.

bug reproduction node

Most helpful comment

I have tried as above and it works. Let me know if I'm wrong

afterEach(() => {
  client.resetStore()
  // Reset any runtime handlers tests may use.
  server.resetHandlers()
  console.log('server.resetHandlers')
})

All 16 comments

By @mwarger thanks for opening this issue :)

Have you tried to understand if you have something not clean before each test?

I think that a reproduction case could help a lot

Thanks for using MSW 馃帄

I've been running into the same issue as well. Let me try and make a reproduction.

Hey! Thanks for reaching out with this. Let me share some insights on what may help in triaging this issue.

Ensure single server instance

The list of request handlers (rest.*) is bound to a server instance. Calling .use() and .resetHandlers() operates on the respective instance. Here's the recommended way of setting up the server for tests:

// src/handlers.js
import { rest } from 'msw'

export const handlers = [
  rest.get('myUrl', (req, res, ctx) => res(ctx.json({ a: 1 }))
]
// src/mocks/server.js
import { setupServer } from 'msw/node'
import { handlers } from './handlers'

export const setupServer(...handlers)
// src/setupTests.js
import { server } from './mocks/server'

beforeAll(() => server.listen())
afterEach(() => server.resetHandlers())
afterAll(() => server.close())
// test/MyComponent.test.js
// Reference the same instance created in `mocks/server.js`
import { server } from '../src/mocks/server'

test('regular', () => {})

test('override', () => {
  server.use(...)
})

Isolate

Isolating a single test to fix an issue is usually a sign of shared state between tests. Apart from the list of request handlers, there may be other state at place, which we can find out. What I'd usually to is .skip each test one-by-one, and see what makes the problematic test pass. That does not mean the skipped tests is the issue, but it may lead us to finding the root cause of it.

Please, try to set up a minimal reproduction scenario/repository, so we could take a look. Thank you.

Reproduction project here: https://github.com/roy-dendro/msw

You can run yarn and yarn run test.

You can see in https://github.com/roy-dendro/msw/blob/master/index.spec.js#L23 that i add a console.log in the overwrite graphql call, but its never called.

In the second test, where it supposed to return an error from the msw, it renders as normally with the handler defined in mocks/handlers

Isolate

Isolating a single test to fix an issue is usually a sign of shared state between tests. Apart from the list of request handlers, there may be other state at place, which we can find out. What I'd usually to is .skip each test one-by-one, and see what makes the problematic test pass. That does not mean the skipped tests is the issue, but it may lead us to finding the root cause of it.

Please, try to set up a minimal reproduction scenario/repository, so we could take a look. Thank you.

Please see the reproduction above. Like you mentioned, when skipping the first it in https://github.com/roy-dendro/msw/blob/master/index.spec.js, the second test, and thus the overwrite using server.use does seem to work.

Any idea what could cause that?

Thanks for getting back at such a short notice. We'll checkout your reproduction repository and let you know on any technical insights we find. Stay tunned.

Hi @roy-dendro I think that ApolloClient is caching you responses. So after the first test your response is cached and not executed again.

Whenever Apollo Client fetches query results from your server, it automatically caches those results locally. This makes subsequent executions of the same query extremely fast.

Hi @roy-dendro I think that ApolloClient is caching you responses. So after the first test your response is cached and not executed again.

Unfortunately i don't think that that's the issue. Setting a fetch-policy to network-only should resolve the issue which is not the case. Also because the whole ApolloProvider is re-rendered across different tests i don't believe cache should be shared between them. Let me verify my assumptions though 馃槄

I have tried as above and it works. Let me know if I'm wrong

afterEach(() => {
  client.resetStore()
  // Reset any runtime handlers tests may use.
  server.resetHandlers()
  console.log('server.resetHandlers')
})

I have tried as above and it works. Let me know if I'm wrong

afterEach(() => {
  client.resetStore()
  // Reset any runtime handlers tests may use.
  server.resetHandlers()
  console.log('server.resetHandlers')
})

That indeed seems to be working, sorry for disregarding your solution so soon in my previous reply.

Setting the fetchPolicy to network-only didn't resolve it, which confuses me at the moment. Also when trying to reproduce in the browers with multiple ApolloProviders i'm not getting shared cache.

I will look into it some more next week, I don't have time at the moment to look into it :)

thanks for your help.

it's not a problem :) the important thing is that the problem is solved. We are here trying to help other and make others help us 馃槃

This ended up being a cache issue. I was using SWR for the tests in question and I needed to add cache clearing and deduping to fix it. Thank you for walking through the issues to consider, and thanks for @roy-dendro for the reproduction and jogging my mind that I needed to think about the cache!

Here's what I ended up doing that solved it: https://github.com/vercel/swr/pull/231#issuecomment-591614747

I appreciate your help and quick response.

This bit me as well. Thank you for the solution. I imagine using Apollo Client is pretty common with msw so might be nice to include that detail somewhere in the docs. Happy to PR that if you want.

For anyone coming to this who is using react-query. You will need to add

import { queryCache } from "react-query"; 

beforeEach(() => {
  // Resets React Query cache
  queryCache.clear();
});

We should really create an FAQ point mentioning cache invalidation for such request clients.

References this suggestion in this FAQ section.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

PritamSangani picture PritamSangani  路  3Comments

danielstreit picture danielstreit  路  3Comments

dashed picture dashed  路  3Comments

tomalexhughes picture tomalexhughes  路  3Comments

veronesecoms picture veronesecoms  路  3Comments