Skip to content

SWR cache persistent across tests even with cache clearing and deduping interval at 0 #781

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
frdwhite24 opened this issue Nov 18, 2020 · 10 comments

Comments

@frdwhite24
Copy link

frdwhite24 commented Nov 18, 2020

Bug report

Description / Observed Behavior

I have found that some sort of SWR cache(?) persists between tests regardless of clearing the cache and setting the deduping interval to 0. The results are unpredictable and vary each time I run the tests.

Expected Behavior

With cache clearing and deduping interval set to 0, I expected the components using SWR to return the correct data from the API for that test case, not from the previous test case.

Repro Steps / Code Example

Code example here: https://github.com/frdwhite24/swr-testing
Example test script is here: https://github.com/frdwhite24/swr-testing/blob/master/src/component/FetchData.test.js

git clone https://github.com/frdwhite24/swr-testing.git
cd swr-testing
npm install
npm test (try running this 10 times and watch the different results)

Additional Context

SWR v0.3.9
Jest as the testing lib

I have implemented mocking of my API using MSW (mock service worker) and am replacing an existing query handler with a runtime request handler. Starting out with a minimal code base, I tested out the MSW runtime request handler resetting with a vanilla fetch command. After this worked 100% of the time I introduced a component using SWR to get the data, and tests that run before, with and after I implement the runtime req handler. I found that one of three scenarios occur:

  • All tests pass as expected (very rarely ~5%)
  • The test with the runtime request handler returns data in the original handler and so will fail but all others will pass
  • The test after the runtime request handler has been implemented but reset fails as it returns the new data set in the previous test's updated request handler, but all others will pass

I have tried putting a vanilla fetch between the SWR tests and this seems to help it return the correct data.
I have also put two SWR tests after each other which are identical, and the first one will fail but the second one will pass.
I have logged the SWR cache before and after each test and can see that it is being emptied.
I have logged the number of request handlers being used by MSW and have confirmed that they are as expected.
I have also forced MSW to reset the handlers between tests using the specific list of handlers used at the initial state.
I have tried running each test in isolation using test.only and each one passes 100% of the time.

I've been fighting this one for many days now and appreciate the time you spend looking into it!

@nstepien
Copy link
Contributor

nstepien commented Dec 1, 2020

I've found a workaround:

afterEach(async () => {
  await new Promise(requestAnimationFrame);
  cache.clear();
});

This might not work if multiple fetches happen within the same test though, I'm not sure.
I think this might be related to 9e734aa, @shuding any ideas?

@dburrows
Copy link

dburrows commented Dec 4, 2020

Ran into this one again, can confirm that workaround worked for me on a single fetch test which at least is some progress, still I think this needs to have a more substantial fix as it's causing quite a bit of pain.

@max10rogerio
Copy link

I've found a workaround:

afterEach(async () => {
  cache.clear();
  await new Promise(requestAnimationFrame);
});

This might not work if multiple fetches happen within the same test though, I'm not sure.
I think this might be related to 9e734aa, @shuding any ideas?

worked for me!

ty! I love you!

@lerockit
Copy link

Another workaround that I've found:

afterEach(async () => {
  await waitFor(() => cache.clear())
})

@neviaumi
Copy link

neviaumi commented Mar 1, 2021

Do any planning / instruction for fix it ?

i have a useSWR with options refreshInterval: 10s

and seem

import {cache} from "swr"
cache.clear()
``` no luck for this case

my inflected components still waiting for 10s before get reload.

and if i run this test one by one, if working fine.

My tmp solution is manually trigger mutate every time after render.

@florianmatz
Copy link

Anything new regarding this issue? Had the same problem in my last tests and it's quite difficult a.) to debug and b.) find a solution. At least there should be a hint in the packages documentation.

@shuding
Copy link
Member

shuding commented Apr 6, 2021

We are addressing these issues (better testing support) in #1017, it’s still WIP but any feedback is welcome!

@william-hotmart
Copy link

At the end what is the solution? Implement our own cache and do not cache values when in test environment?
I've still got problems with cache in my tests even using the workarounds that were proposed here

@huozhi
Copy link
Member

huozhi commented Jul 22, 2021

You can reset the cache per test with swr@beta

let provider

describe('...', async () => {
  beforeEach(() => {
    provider = new Map()
  })

  it('....', async () => {
     const { cache } = createCache(provider)
     useSWR(key, fetcher, { cache })
  })
})

In this case, each unit test has its own cache, which won't be effected among all test cases. All the states will be written to the corresponding cache.

See related docs: https://swr.vercel.app/docs/advanced/cache.

@missbruni
Copy link

For those having issues with RTL and SWR, swr cache.clear() after every test handles a global cache and I think this paired with RTL isn't working always as expected which leads to cached responses to be used across tests. However, the new version of SWR handles cache on tests differently and you can now have a cache for each rendered component separately. So this has fixed for me:

previous swr solution (does not clean cache correctly between rtl tests)

import {cache, SWRConfig} from 'swr';

beforeEach(() => cache.clear())

<SWRConfig value={{ dedupingInterval: 0 }}>
      <Component {...props} />
 </SWRConfig>

new swr 1.0 solution:

import {SWRConfig} from 'swr';

 <SWRConfig value={{ provider: () => new Map(), dedupingInterval: 0 }}>
      <Component {...props} />
 </SWRConfig>

This fixed for me as each component has its own cache so there is no more caching issues between tests.
I hope it helps someone!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.