更新日: 2024年12月29日
https://n-laboratory.jp/articles/nuxt3-vitest-unittest
・Nuxt 3.15.0
・Vitest 2.1.8
・VeeValidate 4.15.0
・@vee-validate/i18n 4.15.0
・@vee-validate/rules 4.15.0
・@testing-library/user-event 14.5.2
1. VeeValidateをインストールします。
$ npm install --save-dev vee-validate @vee-validate/i18n @vee-validate/rules
2. pluginsディレクトリに vee-validate-plugin.ts を新規作成して以下の内容で保存します。
// plugins/vee-validate-plugin.ts
import { localize, setLocale } from '@vee-validate/i18n'
import ja from '@vee-validate/i18n/dist/locale/ja.json'
import { all } from '@vee-validate/rules'
import { defineRule, configure } from 'vee-validate'
import { defineNuxtPlugin } from '#app'
export default defineNuxtPlugin((_nuxtApp) => {
configure({
generateMessage: localize({
// エラーメッセージの日本語化
ja,
}),
})
// すべてのルールをインポート
Object.entries(all).forEach(([name, rule]) => {
defineRule(name, rule)
})
// エラーメッセージの日本語化
setLocale('ja')
})
3. pagesディレクトリに form.vue を新規作成して以下の内容で保存します。
// pages/form.vue
<script lang="ts" setup>
import { Form, Field, ErrorMessage } from 'vee-validate'
// 送信ボタン押下時に実行される関数
const handleSubmit = (values: Record<string, string>) => {
console.log(values.email)
}
</script>
<template>
<Form v-slot="{ meta }" @submit="handleSubmit">
<!-- バリデーション対象の項目 -->
<Field rules="required|email" name="email" as="input" type="text" placeholder="email" />
<!-- バリデーションエラーメッセージの表示 -->
<ErrorMessage name="email" />
<!-- meta.validは全項目で有効な値を入力された場合にtrueを返し、無効な値を入力または初期状態はfalseを返す -->
<button :disabled="!meta.valid">Submit</button>
</Form>
</template>
4. Nuxtを起動後に以下のURLにアクセスします。テキストボックスと送信ボタンが表示されていることを確認します。
http://localhost:3000/form
5. テキストボックスに「test」を入力するとエラーメッセージが表示されることを確認します。
6. テキストボックスが未入力の場合にエラーメッセージが表示されることを確認します。
7. テキストボックスに「test@test.com」を入力するとエラーメッセージが表示されず、送信ボタンが活性することを確認します。
1. テストファイルや設定ファイルを保存するためのディレクトリをルート配下に作成します。
mkdir unitTests
※ソースディレクトリを変更している場合は、変更先のディレクトリ内に作成してください。
2. setup.ts をunitTests配下に新規作成して以下の内容で保存します。
// unitTests/setup.ts
import { localize, setLocale } from '@vee-validate/i18n'
import ja from '@vee-validate/i18n/dist/locale/ja.json'
import { all } from '@vee-validate/rules'
import { defineRule, configure } from 'vee-validate'
// vee-validate setup
configure({
generateMessage: localize({
// エラーメッセージの日本語化
ja,
}),
})
// すべてのルールをインポート
Object.entries(all).forEach(([name, rule]) => {
defineRule(name, rule)
})
// エラーメッセージの日本語化
setLocale('ja')
3. vitest.config.ts のsetupFilesに setup.ts のパスを追加します。
// vitest.config.ts
export default defineConfig({
test: {
// テスト実行時に以下で指定したファイルが読み込まれます。
setupFiles: './unitTests/setup.ts'
}
})
1. unitTests配下に form.spec.ts を新規作成して以下の内容で保存します。
// unitTests/form.spec.ts
import { describe, expect, test, vi } from 'vitest'
import { render, screen, waitFor } from '@testing-library/vue'
import userEvent from '@testing-library/user-event'
import Form from '~/pages/form.vue'
describe('Form', () => {
describe('画面初期状態の確認', () => {
test('送信ボタンが非活性であること', async () => {
// Arrange
render(Form)
await waitFor(() => {
// Assert
const isDisabled = (screen.getByRole('button') as HTMLButtonElement).disabled
expect(isDisabled).toBe(true)
})
})
})
describe('vee-validateの動作確認', () => {
test('emailは入力必須の項目であること', async () => {
// Arrange
const user = userEvent.setup()
render(Form)
const inputElement = screen.getByPlaceholderText('email')
// Act
await user.type(inputElement, '{Tab}')
// Assert
expect(screen.getByText('emailは必須項目です')).toBeTruthy()
})
test('emailの入力は有効なメールアドレス形式であること', async () => {
// Arrange
const user = userEvent.setup()
render(Form)
const email = screen.getByPlaceholderText('email')
// Act
await user.type(email, 'abc{Tab}')
// Assert
expect(screen.getByText('emailは有効なメールアドレスではありません')).toBeTruthy()
})
test('有効なemailを入力した場合は、送信ボタンが活性になること', async () => {
// Arrange
const user = userEvent.setup()
render(Form)
// Act
await user.type(screen.getByPlaceholderText('email'), 'abc@abc.com')
await waitFor(() => {
// Assert
const isDisabled = (screen.getByRole('button') as HTMLButtonElement).disabled
expect(isDisabled).toBe(false)
})
})
test('送信ボタンを押下した場合は、送信処理が実行されること', async () => {
// Arrange
const user = userEvent.setup()
const handleSubmitMock = vi.fn()
render(Form, {
global: {
mocks: {
handleSubmit: handleSubmitMock
},
}
})
await user.type(screen.getByPlaceholderText('email'), 'abc@abc.com')
// Act
await user.click(screen.getByRole('button'))
await waitFor(() => {
// Assert
expect(handleSubmitMock).toHaveBeenCalledOnce()
})
})
})
})
2. テストを実行します。全件passすることを確認します。
$ npm run test
> test
> vitest
✓ unitTests/form.spec.ts
✓ Form (5) 529ms
✓ 画面初期状態の確認 (1)
✓ 送信ボタンが非活性であること
✓ vee-validateの動作確認 (4) 495ms
✓ emailは入力必須の項目であること
✓ emailの入力は有効なメールアドレス形式であること
✓ 有効なemailを入力した場合は、送信ボタンが活性になること
✓ 送信ボタンを押下した場合は、送信処理が実行されること
Test Files 1 passed (1)
Tests 5 passed (5)
※本手順書では「package.json」の「scripts」に以下が追加されている想定としています。
{
"scripts": {
"test": "vitest",
},
}
以上で全ての手順は完了になります