Reputation: 991
Say I have a listStore.js
like this:
import { create } from 'zustand'
import queryList from '@/service'
const useListStore = () => create((get, set) => ({
list: [],
getList: async () => {
const list = await queryList()
const { updateList } = get()
updateList(list)
}
updateList: list => {
set({
list: list.map(i => i + 1)
})
}
}))
To test this store hook, I create a test file named listStore.test.js
like this:
import useListStore from './useListStore'
import { renderHook, act } from '@testing-library/react'
jest.mock('@/service', () => ({
queryList: jest.fn().mockResolvedValue([1,2,3])
}))
describe('test listStore', () => {
test('test updateList function', () => {
// some codes
})
test('test getList function', () => {
const { result } = renderHook(() => useListStore())
act(() => result.current.getList())
expect(queryList).toHaveBeenCalled()
expect(result.current.list).toEqual([2,3,4])
})
})
When testing getList
function, not only should I test the queryList
has been called, but I also need to test that the list
state has been updated correctly.
The key point is that, before I do an assertion like expect(result.current.list).toEqual([2,3,4])
, I have to make sure that the state update has been done. However, I have no idea how to make sure that. Even when I waitFor
or await
the expect
assertion, the state I get seems to be an old value. The list
state is still []
instead of [2,3,4]
.
Upvotes: 0
Views: 120
Reputation: 102547
You code has some issues:
stateCreatorFn
passed in create
accept set
function as its first argument, get
function as its second argument.See function signature below:
export type StateCreator<T, Mis extends [StoreMutatorIdentifier, unknown][] = [], Mos extends [StoreMutatorIdentifier, unknown][] = [], U = T> = ((setState: Get<Mutate<StoreApi<T>, Mis>, 'setState', never>, getState: Get<Mutate<StoreApi<T>, Mis>, 'getState', never>, store: Mutate<StoreApi<T>, Mis>) => U) & {
$$storeMutators?: Mos;
};
create
returns a React Hook with API utilities, but you create a high order function. It should be:const useListStore = create((set, get) => {/** */})
NOT:
const useListStore = () => create((set, get) => {/** */})
getList
action directly by calling set
function.import { create } from 'zustand';
import queryList from './service';
const useListStore = create((set) => ({
list: [],
getList: async () => {
const list = await queryList();
set({ list: list.map((v) => v + 1) });
},
}));
export default useListStore;
await act(async () => ...)
, otherwise the test will fail and get the warningWarning: You called act(async () => ...) without await. This could lead to unexpected testing behaviour, interleaving multiple act calls and mixing their scopes. You should - await act(async () => ...);
Then, the test should be:
useListStore.test.js
import useListStore from './useListStore';
import queryList from './service';
import '@testing-library/jest-dom';
import { renderHook, act } from '@testing-library/react';
jest.mock('./service');
describe('test listStore', () => {
test('test getList function', async () => {
queryList.mockResolvedValueOnce([1, 2, 3]);
const { result } = renderHook(() => useListStore());
await act(async () => await result.current.getList());
expect(queryList).toHaveBeenCalled();
expect(result.current.list).toEqual([2, 3, 4]);
});
});
service.js
:
const queryList = () => ['real data'];
export default queryList;
Test result:
$ npm t -- -o --coverage
> [email protected] test
> jest -o --coverage
PASS stackoverflow/79274146/useListStore.test.js
test listStore
√ test getList function (12 ms)
-----------------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
-----------------|---------|----------|---------|---------|-------------------
All files | 85.71 | 100 | 75 | 100 |
service.js | 50 | 100 | 0 | 100 |
useListStore.js | 100 | 100 | 100 | 100 |
-----------------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 2.157 s
package versions:
"@testing-library/react": "^14.1.2",
"jest": "^29.7.0",
"zustand": "^5.0.2",
"react": "^18.2.0",
P.S. I don't have __mocks__/zustand.ts
file mentioned here
Upvotes: 0