Episode ini membahas strategi testing Zustand dengan Vitest: unit test untuk state dan action, menguji middleware persist dengan storage mock, dan component testing memakai React Testing Library. Kalian juga belajar pola reset store antar test agar setiap test berjalan dari kondisi bersih.

Store adalah bagian logika aplikasi yang paling layak diuji: murni, deterministik, dan tanpa DOM. Episode 18 membahas strategi testing Zustand dengan Vitest — unit test untuk state dan action, menguji middleware persist dengan storage mock, dan component testing memakai React Testing Library untuk memastikan komponen merespons state dengan benar.
Kalian juga belajar pola reset store antar test agar setiap test berjalan dari kondisi bersih.
Instal Vitest dan React Testing Library:
npm i -D vitest @testing-library/react @testing-library/jest-domLalu tulis test untuk store sederhana. Karena store hanyalah fungsi, test bisa mengetuk getState dan memanggil action langsung:
import { describe, expect, it } from 'vitest'
import { useCounter } from './counter-store'
describe('counter store', () => {
it('increment menambah count dari 0 menjadi 1', () => {
expect(useCounter.getState().count).toBe(0)
useCounter.getState().increment()
expect(useCounter.getState().count).toBe(1)
})
})useCounter.getState().increment() menjalankan action tanpa render apa pun. Test ini memverifikasi logika store terisolasi dari UI.
Untuk action async yang mengambil data, mock fetch dan pastikan state berubah setelah promise selesai:
it('memuat user setelah fetch selesai', async () => {
vi.stubGlobal('fetch', vi.fn(() =>
Promise.resolve({ json: () => Promise.resolve({ name: 'Arman' }) }),
))
await useUserStore.getState().loadUser(1)
expect(useUserStore.getState().user.name).toBe('Arman')
expect(useUserStore.getState().loading).toBe(false)
vi.unstubAllGlobals()
})await useUserStore.getState().loadUser(1) menunggu action async selesai, lalu memeriksa hasilnya. Ini pola yang sama untuk status loading dan error handling.
Persist membaca storage saat rehydrate. Untuk menguji, mock storage dengan objek sederhana dan kontrol waktu rehydrate:
import { createJSONStorage } from 'zustand/middleware'
it('me-rehydrate state dari storage', () => {
const storage = createJSONStorage(() => ({
getItem: () => JSON.stringify({ state: { theme: 'dark' } }),
setItem: () => {},
removeItem: () => {},
}))
const store = create(persist((set) => ({ theme: 'light' }), {
name: 'theme-store',
storage,
}))
expect(store.getState().theme).toBe('dark')
})getItem yang mengembalikan state tersimpan membuat persist langsung me-rehydrate nilai theme menjadi dark saat store dibuat. Untuk storage asinkron, gunakan waitFor atau polling sampai state terisi.
Untuk komponen yang memakai hook, render dengan testing library dan simulasikan interaksi:
import { render, screen } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
it('menampilkan tombol Tambah', async () => {
render(<Counter />)
await userEvent.click(screen.getByRole('button', { name: 'Tambah' }))
expect(screen.getByText('Count: 1')).toBeInTheDocument()
})userEvent.click mensimulasikan klik nyata dan memicu action store, lalu render diperiksa lewat teks yang muncul. Component test melengkapi unit test: yang pertama memastikan logika, yang kedua memastikan UI tersambung dengan benar.
State store bersifat global dan menempel antar test. Reset di beforeEach agar tiap test dimulai dari kondisi awal:
import { beforeEach } from 'vitest'
beforeEach(() => {
useCounter.setState({ count: 0 })
useUserStore.setState({ user: null, loading: false })
})setState({ count: 0 }) mengembalikan store ke kondisi awal tanpa me-render komponen. Ini mencegah test saling mempengaruhi dan membuat setiap test deterministik.
Episode 18 melengkapi safety net: unit test untuk logika store dengan getState langsung, test action async dengan fetch mock, test persist dengan storage mock, component test dengan React Testing Library, dan reset state di beforeEach agar setiap test bersih.
Inti yang harus dibawa pulang:
Di episode 19 selanjutnya kita akan membahas optimasi dan debugging — profil re-render dengan React Profiler dan Redux DevTools, lalu troubleshooting umum seperti infinite render, state yang tidak ter-update, hydration mismatch, dan stale closure.