Skip to content

Store テスト

13.4.1. createTestingPinia

テスト環境では @pinia/testingcreateTestingPinia() を使用してテスト用の Pinia インスタンスを生成します。

  • createTestingPinia() はすべての action を自動的にモックします。
  • stubActions: false を指定すると実際の action が実行されます。
  • initialState で Store の初期状態をオーバーライドすることができます。
typescript
import { createTestingPinia } from '@pinia/testing'
import { vi } from 'vitest'

// 基本的な使用方法: すべての action が自動モックされます。
const pinia = createTestingPinia({
  createSpy: vi.fn,
})

// action を実際に実行する場合
const pinia = createTestingPinia({
  createSpy: vi.fn,
  stubActions: false,
})

// 初期状態を指定する場合
const pinia = createTestingPinia({
  createSpy: vi.fn,
  initialState: {
    user: { user: { id: 1, name: 'テストユーザー' }, loading: false },
    cart: { items: [{ id: 1, name: '商品A', price: 10000, quantity: 2 }] },
  },
})

13.4.2. Store 単体テスト

Store をコンポーネントなしで独立してテストする場合は setActivePinia() を使用します。

typescript
// src/stores/__tests__/useCartStore.test.ts
import { describe, it, expect, beforeEach } from 'vitest'
import { setActivePinia, createPinia } from 'pinia'
import { useCartStore } from '../useCartStore'

describe('useCartStore', () => {
  beforeEach(() => {
    setActivePinia(createPinia())
  })

  it('初期状態は空の配列でなければなりません', () => {
    const store = useCartStore()
    expect(store.items).toEqual([])
    expect(store.isEmpty).toBe(true)
  })

  it('項目追加時に totalPrice を正しく計算しなければなりません', () => {
    const store = useCartStore()
    store.items.push({ id: 1, name: '商品A', price: 5000, quantity: 3 })

    expect(store.totalPrice).toBe(15000)
    expect(store.itemCount).toBe(1)
  })

  it('resetState 呼び出し時に初期状態に復元されなければなりません', () => {
    const store = useCartStore()
    store.items.push({ id: 1, name: '商品A', price: 5000, quantity: 1 })

    store.resetState()

    expect(store.items).toEqual([])
  })
})
  • beforeEach で毎回新しい Pinia インスタンスを生成してテスト間の状態汚染を防止します。
  • getter は状態変更後の戻り値を検証します。

13.4.3. コンポーネント内の Store テスト

コンポーネントで Store を使用する場合、mountglobal.pluginscreateTestingPinia() を注入します。

typescript
// src/components/__tests__/UserProfile.test.ts
import { describe, it, expect } from 'vitest'
import { mount } from '@vue/test-utils'
import { vi } from 'vitest'
import { createTestingPinia } from '@pinia/testing'
import UserProfile from '../UserProfile.vue'
import { useUserStore } from '@/stores/useUserStore'

describe('UserProfile', () => {
  it('ユーザー名を表示しなければなりません', () => {
    const wrapper = mount(UserProfile, {
      global: {
        plugins: [
          createTestingPinia({
            createSpy: vi.fn,
            initialState: {
              user: {
                user: { id: 1, name: '山田太郎' },
                loading: false,
              },
            },
          }),
        ],
      },
    })

    expect(wrapper.text()).toContain('山田太郎')
  })

  it('マウント時に loadCurrentUser を呼び出さなければなりません', () => {
    const wrapper = mount(UserProfile, {
      global: {
        plugins: [createTestingPinia({ createSpy: vi.fn })],
      },
    })

    const userStore = useUserStore()
    expect(userStore.loadCurrentUser).toHaveBeenCalledOnce()
  })
})
  • initialState のキーは defineStore に渡した Store ID と一致しなければなりません。
  • コンポーネントマウント後に useUserStore() を呼び出すとテスト用の Store インスタンスが返されます。

13.4.4. モッキングパターン

API 呼び出しのモッキング

Store 内部の API 呼び出しは vi.mock() でモックします。

typescript
import { describe, it, expect, beforeEach, vi } from 'vitest'
import { setActivePinia, createPinia } from 'pinia'
import { useUserStore } from '../useUserStore'
import { fetchCurrentUser } from '@/api/user'

vi.mock('@/api/user', () => ({
  fetchCurrentUser: vi.fn(),
}))

describe('useUserStore - API 連携', () => {
  beforeEach(() => {
    setActivePinia(createPinia())
    vi.clearAllMocks()
  })

  it('loadCurrentUser 成功時にユーザー情報を保存しなければなりません', async () => {
    const mockUser = { id: 1, name: 'テストユーザー' }
    vi.mocked(fetchCurrentUser).mockResolvedValue(mockUser)

    const store = useUserStore()
    await store.loadCurrentUser()

    expect(store.user).toEqual(mockUser)
    expect(store.isLoggedIn).toBe(true)
    expect(store.loading).toBe(false)
  })
})

Action のモッキング

createTestingPinia() を使用するとすべての action が自動モックされます。特定の action の戻り値を指定するには mockResolvedValue() を使用します。

typescript
const pinia = createTestingPinia({ createSpy: vi.fn })
const userStore = useUserStore()

vi.mocked(userStore.loadCurrentUser).mockResolvedValue(undefined)
  • stubActions: true(デフォルト)では action の呼び出し有無のみを検証します。
  • action の実際のロジックをテストするには stubActions: false を指定するか、Store 単体テストを別途作成します。

TIENIPIA QUALIFIED STANDARD