zustand/docs/guides/testing.mdx
Aleksandar Dimitrov 38ccc1ffb1
Fix Jest example's usage of default imports (#1641)
* docs: Fix Jest example's usage of default imports

Default exports and imports are deprecated. The default import of `zustand` generates a deprecation warning on the console. The default export that was suggested previously would actually fail to compile. See the comments at the very bottom of #559 for further discussion.

This commit fixes the example in the documentation by introducing named exports & imports instead of default exports & imports.

* docs: Suggest using plain import for Jest

`jest.requireActual` is not necessary when we're not mocking any other
part of `zustand`.

* docs: Fix TypeScript example

The `create` function was curried where it should not have been.
The example is now written in plain TypeScript, as the code that it
contains does not require JSX.

* Prettier suggestions

* Use `jest.requireActual` to avoid circular dependencies
2023-02-27 10:58:11 +09:00

103 lines
3.6 KiB
Plaintext

---
title: Testing
description: How to test your new store
nav: 9
---
## Resetting state between tests in **react-dom**
When running tests, the stores are not automatically reset before each test run.
Thus, there can be cases where the state of one test can affect another. To make sure all tests run with a pristine store state, you can mock `zustand` during testing and use the following code to create your store:
```jsx
import { create as actualCreate } from 'zustand'
// const { create: actualCreate } = jest.requireActual('zustand') // if using jest
import { act } from 'react-dom/test-utils'
// 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
export 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
beforeEach(() => {
act(() => storeResetFns.forEach((resetFn) => resetFn()))
})
```
The way you mock a dependency depends on your test runner/library.
In [jest](https://jestjs.io/), you can create a `__mocks__/zustand.js` and place the code in that file. If your app is using `zustand/vanilla` instead of `zustand`, then you'll have to place the above code in `__mocks__/zustand/vanilla.js`.
### TypeScript usage
If you are using zustand, as documented in [TypeScript Guide](./typescript.md), use the following code:
```typescript
import { create as actualCreate, StateCreator } from 'zustand'
// if using Jest:
// import { StateCreator } from 'zustand';
// const { create: actualCreate } = jest.requireActual<typeof import('zustand')>('zustand');
import { act } from 'react-dom/test-utils'
// a variable to hold reset functions for all stores declared in the app
const storeResetFns = new Set<() => void>()
// when creating a store, we get its initial state, create a reset function and add it in the set
export const create = <S>(createState: StateCreator<S>) => {
const store = actualCreate(createState)
const initialState = store.getState()
storeResetFns.add(() => store.setState(initialState, true))
return store
}
// Reset all stores after each test run
beforeEach(() => {
act(() => storeResetFns.forEach((resetFn) => resetFn()))
})
```
## Resetting state between tests in **react-native** and **jest**
You should use the following code in the `__mocks__/zustand.js` file (the `__mocks__` directory should be adjacent to node_modules, placed in the same folder as node_modules, unless you configured roots to point to a folder other than the project root [jest docs: mocking node modules](https://jestjs.io/docs/manual-mocks#mocking-node-modules)):
```js
import { act } from '@testing-library/react-native'
const { create: actualCreate } = jest.requireActual('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
export 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
beforeEach(async () => {
await act(() =>
storeResetFns.forEach((resetFn) => {
resetFn()
})
)
})
```
If the `jest.config.js` has `automock: false`, then you need to do the following in `jest.setup.js`:
```js
jest.mock('zustand')
```