Testing
Reset stores between tests, drive them from tests, and test contexts with makeProviderWrapper.
The problem this solves
Global stores live at module scope, so state from one test can leak into the next. Contexts are created per render, so a test needs a way to reach the store that a provider created.
Reset global stores
Create the store from a function initializer and call reset() in beforeEach. With a plain value,
reset() keeps the current state; pass the values yourself (reset(state, metadata)) if you cannot change the
initializer. On a persisted store, reset() also clears the stored value.
import { createContext, createGlobalState } from 'react-global-state-hooks';
// A function initializer lets reset() restore a fresh state before each test.
export const useCart = createGlobalState(() => ({ items: [] as string[] }), {
actions: {
add(item: string) {
return ({ setState }) => {
setState((state) => ({ items: [...state.items, item] }));
};
},
},
});
export const CartContext = createContext(
{ items: [] as string[] },
{
actions: {
add(item: string) {
return ({ setState }) => {
setState((state) => ({ items: [...state.items, item] }));
};
},
},
},
);Test with a store or a context
This is the test file that runs in this site’s own test suite, shown unchanged.
import { act, renderHook } from '@testing-library/react';
import { beforeEach, describe, expect, it } from 'vitest';
import { CartContext, useCart } from './cart-store';
describe('global store', () => {
// reset() returns the store to its initial state, so tests do not leak into each other
beforeEach(() => useCart.reset());
it('changes state through actions, without rendering anything', () => {
useCart.actions.add('book');
expect(useCart.getState().items).toEqual(['book']);
});
it('updates a component that uses the hook', () => {
const { result } = renderHook(() => useCart((state) => state.items.length));
expect(result.current[0]).toBe(0);
act(() => useCart.actions.add('book'));
expect(result.current[0]).toBe(1);
});
});
describe('context store', () => {
it('gets a fresh store per render, and exposes it through makeProviderWrapper', () => {
const { wrapper, context } = CartContext.Provider.makeProviderWrapper();
const { result } = renderHook(() => CartContext.use((state) => state.items), { wrapper });
expect(result.current[0]).toEqual([]);
act(() => context.current.actions.add('book'));
expect(result.current[0]).toEqual(['book']);
});
});Persistence in tests
localStorage restores when the store module loads. Set the stored value first, then import the module
(with vi.resetModules() and a dynamic import() in Vitest) to test restoring and migrations.