N-LAB

Nuxt 3 × Piniaでストアの単体テストを実行する

更新日: 2024年12月30日


目標


前提

※本手順書ではソースディレクトリを「src」に変更している想定としています。テストコードは「src/unitTests」に保存します。

https://n-laboratory.jp/articles/nuxt3-vitest-unittest

・Nuxt 3.15.0
・Vitest 2.1.8
・Pinia 2.3.0
・@pinia/nuxt 0.9.0
・@pinia/testing 0.1.7

目次

  1. Piniaインストール
  2. ストアの実装
  3. VitestのPinia初期設定
  4. ストアの単体テストコードの実装
  5. Vueファイルでストアを利用する場合の単体テストコード実装


Piniaインストール

1. Piniaをインストールします。

$ npm install pinia @pinia/nuxt


2. nuxt.config.ts のmodulesに以下を追加します。

// nuxt.config.ts
export default defineNuxtConfig({
  modules: [
    ['@pinia/nuxt',
      {
        autoImports: [
          // defineStoreの自動インポート
          'defineStore',
        ],
        // vuexも併用する場合は以下を追加
        // disableVuex: false ,
      },
    ],
  ],
});


ストアの実装

1. storesディレクトリを新規作成します。 user.ts を新規作成して以下の内容で保存します。

// stores/user.ts
// nuxt.config.tsのautoImportsにdefineStoreを追加している場合はこのimport文は不要です。
import { defineStore } from 'pinia'

type UserState = {
  email: string,
  password: string
}

export const useUserStore = defineStore('user', {
  state: (): UserState => ({
    // ユーザーの定義・初期化
    email: '',
    password: ''
  }),
  actions: {
    // ユーザー情報の更新
    setUserInfo (email: string, password: string) {
      this.email = email
      this.password = password
    }
  }
})


2. Vueファイルからストアを参照するには以下のように実装します。

// pages/store.vue
<script lang="ts" setup>
import { useUserStore } from '~/stores/user'

// storeの取得
const userStore = useUserStore()

// emailの取得
const email = userStore.email

// passwordの取得
const password = userStore.password

// ユーザー情報の更新
userStore.setUserInfo("new email", "new password")
</script>
<template>
  <p>Email: {{ email }}</p>
  <p>Password: {{ password }}</p>
</template>


VitestのPinia初期設定

Error: [🍍]: "getActivePinia()" was called but there was no active Pinia. Did you forget to install pinia?
import { setActivePinia, createPinia } from 'pinia'

beforeEach(() => {
  setActivePinia(createPinia())
})

※詳細は以下を参照ください。
https://pinia.vuejs.org/cookbook/testing.html#unit-testing-components

ストアの単体テストコードの実装

1. user.spec.ts を新規作成して以下の内容で保存します。

// src/unitTests/user.spec.ts
import { beforeEach, describe, expect, test } from 'vitest'
import { setActivePinia, createPinia } from 'pinia'
import { useUserStore } from '~/stores/user'

const initialUser = {
  email: '',
  password: ''
}
const updatedUser = {
  email: 'new email',
  password: 'new password'
}

describe('Stores/user', () => {
  beforeEach(() => {
    setActivePinia(createPinia())
  })

  test('ストアのユーザー情報が初期化されていること', () => {
    // Arrange
    const user = useUserStore()

    // Assert
    expect(user.email).toBe(initialUser.email)
    expect(user.password).toBe(initialUser.password)
  })

  test('setUserInfoを呼び出した場合、ストアのユーザー情報が更新されること', () => {
    // Arrange
    const user = useUserStore()

    // Act
    user.setUserInfo(updatedUser.email, updatedUser.password)

    // Assert
    expect(user.email).toBe(updatedUser.email)
    expect(user.password).toBe(updatedUser.password)
  })
})


2. テストを実行します。全件passすることを確認します。

$ npm run test
> test
> vitest
 ✓ src/unitTests/user.spec.ts (2)
   ✓ Stores/user (2)
     ✓ ストアのユーザー情報が初期化されていること
     ✓ setUserInfoを呼び出した場合, ストアのユーザー情報が更新されること
 Test Files  1 passed (1)
      Tests  2 passed (2)

※本手順書では package.json のscriptsに以下が追加されている想定としています。

{
  "scripts": {
    "test": "vitest",
  },
}


Vueファイルでストアを利用する場合の単体テストコード実装

・@pinia/testing

1. @pinia/testingをインストールします。

$ npm install --save-dev @pinia/testing


2. 以下のVueファイルを作成します。ここではこのVueファイルの単体テストコードを実装します。

// pages/store.vue
<script lang="ts" setup>
import { useUserStore } from '~/stores/user'

// storeの取得
const userStore = useUserStore()

// emailの取得
const email = userStore.email

// passwordの取得
const password = userStore.password
</script>
<template>
  <p>Email: {{ email }}</p>
  <p>Password: {{ password }}</p>
</template>


3. store.spec.ts を新規作成して以下の内容で保存します。

// src/unitTests/store.spec.ts
import { beforeEach, describe, expect, test } from 'vitest'
import { render, screen } from '@testing-library/vue'
import { setActivePinia, createPinia } from 'pinia'
import { createTestingPinia } from '@pinia/testing'
import Store from '~/pages/store.vue'

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

  test('emailとpasswordが表示されること', () => {
    // Arrange
    render(Store, {
      global: {
        plugins: [
          createTestingPinia({
            // storeのuserの初期値を設定
            initialState: {
              user: {
                email: 'Initial email',
                password: 'Initial password'
              },
            },
          }),
        ],
      },
    })

    // Assert
    expect(screen.getByText('Email: Initial email')).toBeTruthy()
    expect(screen.getByText('Password: Initial password')).toBeTruthy()
  })
})


4. テストを実行します。全件passすることを確認します。

$ npm run test
> test
> vitest
 ✓ src/unitTests/store.spec.ts (1)
   ✓ Store (1)
     ✓ emailとpasswordが表示されること
 Test Files  1 passed (1)
      Tests  1 passed (1)


以上で全ての手順は完了になります