Home Arrow Icon Knowledge base Arrow Icon Global Arrow Icon How do you test Zustand stores effectively


How do you test Zustand stores effectively


To test Zustand stores effectively, you can follow these steps:

1. Create a mock Zustand store

Zustand provides a way to create mock stores for testing purposes. You can use the `create` function provided by Zustand to create a mock store that you can use in your tests. Here's an example:

javascript
import { create } from 'zustand/testing';

const useCountStore = create((set) => ({
  count: 0,
  increment: () => set((state) => ({ count: state.count + 1 })),
}));

describe('Count Store', () => {
  it('should increment the count', () => {
    const store = useCountStore.getState();
    expect(store.count).toEqual(0);
    store.increment();
    expect(store.count).toEqual(1);
  });
});

In this example, we create a mock `useCountStore` using the `create` function from `zustand/testing`. We then use the `getState` method to access the current state of the store and make assertions about its behavior.

2. Use the `act` function from React Testing Library

When testing components that use Zustand stores, you'll need to use the `act` function from React Testing Library to ensure that state updates are properly handled. Here's an example:

javascript
import { render } from '@testing-library/react';
import { act } from 'react-dom/test-utils';
import useCountStore from './countStore';

const CountComponent = () => {
  const count = useCountStore((state) => state.count);
  const increment = useCountStore((state) => state.increment);

  return (
    <div>
      <span>Count: {count}</span>
      <button onClick={increment}>Increment</button>
    </div>
  );
};

describe('Count Component', () => {
  it('should increment the count', () => {
    const { getByText } = render(<CountComponent />);
    const countText = getByText('Count: 0');
    expect(countText).toBeInTheDocument();

    act(() => {
      fireEvent.click(getByText('Increment'));
    });

    expect(getByText('Count: 1')).toBeInTheDocument();
  });
});

In this example, we use the `act` function to ensure that the state updates are properly handled when we click the "Increment" button.

3. Use the `persist` middleware for persistent state

If your Zustand store uses the `persist` middleware to store state in local storage, you'll need to mock the storage API in your tests. You can use the `createJSONStorage` function provided by Zustand to create a mock storage implementation. Here's an example:

javascript
import { create } from 'zustand';
import { persist, createJSONStorage } from 'zustand/middleware';

const useCartStore = create(
  persist(
    (set) => ({
      items: [],
      addItem: (item) => set((state) => ({ items: [...state.items, item] })),
      removeItem: (itemId) =>
        set((state) => ({
          items: state.items.filter((item) => item.id !== itemId),
        })),
    }),
    {
      name: 'cart-storage',
      storage: createJSONStorage(() => ({
        getItem: (name) => Promise.resolve(localStorage.getItem(name)),
        setItem: (name, value) => Promise.resolve(localStorage.setItem(name, value)),
        removeItem: (name) => Promise.resolve(localStorage.removeItem(name)),
      })),
    }
  )
);

describe('Cart Store', () => {
  beforeEach(() => {
    localStorage.clear();
  });

  it('should persist the cart state', () => {
    const store = useCartStore.getState();
    store.addItem({ id: '1', name: 'Product 1', price: 10 });
    expect(store.items).toEqual([{ id: '1', name: 'Product 1', price: 10 }]);

    const newStore = useCartStore.getState();
    expect(newStore.items).toEqual([{ id: '1', name: 'Product 1', price: 10 }]);
  });
});

In this example, we use the `createJSONStorage` function to create a mock storage implementation that uses the browser's `localStorage` API. We then clear the `localStorage` before each test to ensure a clean slate.

By following these steps, you can effectively test your Zustand stores and ensure that your application's state management logic is working as expected.

Citations:
[1] https://www.bomberbot.com/react/mastering-zustand-a-simple-and-efficient-state-management-library-for-react/
[2] https://blog.peslostudios.com/blog/zustand-writing-tests-for-your-data-store/
[3] https://github.com/pmndrs/zustand/discussions/2343
[4] https://tkdodo.eu/blog/working-with-zustand
[5] https://stackoverflow.com/questions/74691765/how-to-use-a-zustand-store-in-jest-in-place-of-props