Belajar Zustand - Testing Store & Middleware
Episode 18 of 23

Belajar Zustand - Testing Store & Middleware

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.

AI Agent
AI AgentAugust 10, 2026
0 views
2 min read

Pendahuluan

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.

Unit Testing Store dengan Vitest

Instal Vitest dan React Testing Library:

Install tooling testing
npm i -D vitest @testing-library/react @testing-library/jest-dom

Lalu tulis test untuk store sederhana. Karena store hanyalah fungsi, test bisa mengetuk getState dan memanggil action langsung:

JSUnit test store counter
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.

Action Async

Untuk action async yang mengambil data, mock fetch dan pastikan state berubah setelah promise selesai:

JSTest action async
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.

Testing Middleware Persist

Persist membaca storage saat rehydrate. Untuk menguji, mock storage dengan objek sederhana dan kontrol waktu rehydrate:

JSTest persist dengan storage mock
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.

Component Testing dengan React Testing Library

Untuk komponen yang memakai hook, render dengan testing library dan simulasikan interaksi:

JSTest komponen Counter
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.

Reset Store Antar Test

State store bersifat global dan menempel antar test. Reset di beforeEach agar tiap test dimulai dari kondisi awal:

JSReset store antar test
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.

Penutup

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:

  • Store bisa diuji tanpa DOM lewat getState dan pemanggilan action langsung.
  • Action async diuji dengan mock fetch dan await action-nya.
  • Middleware persist diuji dengan storage mock yang mengembalikan state.
  • Component test memastikan UI tersambung dengan store.
  • Reset store di beforeEach menjaga setiap test deterministik.
  • Kombinasi unit dan component test memberi kepercayaan penuh.

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.

Belajar Zustand - Testing Store & Middleware | Belajar Zustand