-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
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鈥檒l occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Proposal] 馃殌 Testing utilities for zustand #271
Comments
I am using a zustand/vanilla store, that is testable on its own, it exports action functions, so I can have fast tests that really worry about the business logic that work with the store. Connecting it to react is just a matter of import vanillaZustand from 'zustand/vanilla';
const createVanilla = typeof vanillaZustand === 'function' ? vanillaZustand : vanillaZustand.default; // I dont know how to do without this, help welcome
export const newStore = () => {
const initialState = {};
return createVanilla(() => initialState);
};
const store = newStore();
// make it useable with React
import create from 'zustand';
const useTheStore = create(vanillaStore), here is some tests (kinda kata) I am writing to show how zustand can be used, I am basically writing this to learn (and be able to re-learn) zustand's API and document it (initally for me) |
|
I would hope someone to explore Meanwhile, someone can also work on elaborating/improving https://github.com/pmndrs/zustand#testing and https://github.com/pmndrs/zustand/wiki/Testing. Any volunteers? |
It helps, but only for the components that are wrapped in a context. Not all componets will have or depend on a provider above them, thus the original issue is still valid
What are your thoughts? |
Creating/polishing docs and recipes in the wiki page to resolve this issue. |
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 |
jest.isolateModules() might also be an option to reset the state. |
Here's my branch with the following changes:
Also in a bit of a conundrum here, because zustand is a pretty library agnostic package, yet Another option would be to leave mocking up to the devs and we can just provide examples for jest like the one written here: https://github.com/alekangelov/zustand/blob/271/src/setup-tests.ts |
can you open a draft pr? we'd like to have a comprehensive doc in |
will do, need to write the docs/tests for the bound store, but will give you a solid idea of where I'm going with the changes |
here it is, complete with examples/docs for bound stores and global ones. |
please someone help. |
Looks like this is done with https://github.com/pmndrs/zustand/blob/main/docs/guides/testing.mdx |
We probably want some more practices in docs. That said, this issue is old. So, let's close it. |
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:This can quickly become tedious since:
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:This has the benefits of:
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 oftest
(which currently stands true for all major test runners),zustand
will silently replace the defaultcreate
function with a "mocked" version ofcreate
(available viazustand/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 totrue
in the current major version and tofalse
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
andprocess.env.ZUSTAND_SKIP_AUTO_RESET
, but requires an explicit opt-in.Related Links
#242
The text was updated successfully, but these errors were encountered: