question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. ItĀ collects links to all the places you might be looking at while hunting down a tough bug.

And, if youā€™re still stuck at the end, weā€™re happy to hop on a call to see how we can help out.

[Proposal] šŸš€ Testing utilities for zustand

See original GitHub issue

Background

zustand is an amazing package that doesnā€™t depend on React Context providers at all. The stores live ā€œoutsideā€ of React and can be accessed from everywhere, even outside of React components.

Because of this, when testing React components via a testing library, the states of the stores donā€™t reset across tests. That means that the code of one test may affect the outcome of another test. It also means that within a test suite (i.e. describe block), test order matters, since a test might modify the state of a store that another test may be depending upon.

Thereā€™s currently no official way of resetting store state before/after each test. A custom solution would include manually extracting the initialState of a store and using it to force-set a storeā€™s state before each test run:

const initialStoreState = useStore.getState();

describe('Suite', () => {
  
  beforeEach(() => {
    useStore.setState(initialStoreState, true);
  });

  ... // tests

});

This can quickly become tedious since:

  1. You have to manually do that for each test suite/file
  2. You have to do that for each and every store in your app or remember the exact stores your tests will be using

An alternative solution involves ā€œmockingā€ zustand and automatically resetting all stores after each test by keeping track of all stores in the app. This involves creating a __mocks__/zustand.js file and putting the following code in there:

import actualCreate from 'zustand';

// a variable to hold reset functions for all stores declared in the app
const storeResetFns = new Set();

// when creating a store, we get its initial state, create a reset function and add it in the set
const create = createState => {
  const store = actualCreate(createState);
  const initialState = store.getState();
  storeResetFns.add(() => store.setState(initialState, true));
  return store;
};

// Reset all stores after each test run
afterEach(() => {
  storeResetFns.forEach(resetFn => resetFn());
});

This has the benefits of:

  1. Not having to modify your source code or tests in any shape or form
  2. Not having to do anything for each new store you create

Goal

Have an officially supported way of testing zustand, while limiting the developerā€™s effort to achieve that

Proposal

We create a separate package named zustand/testing which will contain a polished & safe version of the snippet above. From there there are 2 options:

Option 1 - Automatic mocking

This option automatically mocks zustandā€™s default export, without the developer needing to create any mock files.

Whenever process.env.NODE_ENV has a value of test (which currently stands true for all major test runners), zustand will silently replace the default create function with a ā€œmockedā€ version of create (available via zustand/testing) that will enable the reset functionality portrayed above.

In order to be backwards compatible & avoid any breaking changes, this can be controlled by an additional additional ENV variable named ZUSTAND_SKIP_AUTO_RESET which will default to true in the current major version and to false in the next one.

Option 2 - Manual mocking

This option requires developers to explicitly opt-in to the mocking behavior. Specifically, developers will have to import zustand/testing within their setup file in order to have the mocking capability enabled.

This removes the need for process.env.NODE_ENV and process.env.ZUSTAND_SKIP_AUTO_RESET, but requires an explicit opt-in.

Related Links

https://github.com/pmndrs/zustand/issues/242

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Reactions:23
  • Comments:14 (10 by maintainers)

github_iconTop GitHub Comments

2reactions
mx-bernhardcommented, Jan 1, 2022

jest.isolateModules() might also be an option to reset the state.

2reactions
flqcommented, Oct 27, 2021

Just starting out with Zustand, so I cannot comment yet on how tedious it becomes - we wrote this little helper here:

export function initZustandStoreCleanup(hook: UseBoundStore<any, StoreApi<any>>) {
  let initialState = hook.getState();
  return () => {
    // cleanup here is from react-testing: if components are still "alive" after a test, resetting the state of the hook
    // causes warnings that changes are happening without having it wrapped in "act"
    cleanup();
    hook.setState(initialState);
  };
}

which you can the use like that:

let resetCache: SimpleHandler;

beforeAll(() => {
  resetCache = initZustandStoreCleanup(useNewsFeedCache);
});

afterEach(resetCache);

this can be easily extended to accept a number of such hooks, soā€¦I guess usage will pick up gradually now, we shall see how tedious this becomes

Read more comments on GitHub >

github_iconTop Results From Across the Web

Testing - Zustand Documentation
Zustand is a small, fast and scalable bearbones state-management solution, it has a comfy api based on hooks.
Read more >
Zustand: Bear Necessities for State Management in React
For these cases the resulting hook has utility functions attached to its ... For information regarding testing with Zustand, visit the dedicated Wiki...
Read more >
The SAT Subject Tests Student Guide
Plan to Use These Test-Taking Strategies ... We offer resources to help you find the best college and ... Additional SAT Subject Test...
Read more >
Solana Walkthrough - Scaffold Series - Part 2 Wallet Balance
Then, for utility, they also fetch some information for your key, such as token balance; More advanced, they can also start proposing tokenĀ ......
Read more >
Jotai vs. Recoil: What are the differences? - LogRocket Blog
Flux (Redux, Zustand); Proxy (Mobx, Valtio); Atomic (Recoil, Jotai) ... compared to tools like Redux, which have no concrete plans for itsĀ ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found