閲覧頂き、ありがとうございます🙇
この記事は Vitest
と@nuxt/test-utils
とTesting Library
を用いた、
単体テスト環境を作成していきます!
前提
name | version |
---|---|
Node.js | v20.11.X |
Nuxt.js(Vue.js) | v3.x |
経緯
-
Nuxt3
の環境で単体テストを実行するための環境準備を初めて行なった! -
Testing Library
を使ってみたい! - 時間がないので、なるべく
早く
環境を整えたい! - 日本語の記事があまりない・・・
結論
以下パッケージの導入で解決🎉
-
Vitest ⚡️
- Vite(ビルドツール)ベースのユニットテストフレームワーク
- ≒ Jest
-
@vitest/coverage-v8 ⚡️
- Vitestでカバレッジ率を確認するためのライブラリ
- 実装したコードをどれだけテストできたかの割合とかを出すやつ
-
@nuxt/test-utils 🫘
- Nuxt向けのテストユーティリティパッケージ
- Nuxt3でテストする時に必要なものを色々含めてる便利な福袋的な
-
@testing-library/vue 🐙
- Vue用のTesting Libraryのライブラリ
- ユーザーが実際の操作に近い形でテストを書くことが可能
-
happy-dom 🎊
- Node.js環境で動作するDOMのエミュレーター
- これがないと「ボタンをクリック」みたいなテストでボタンを見つけられない
推しポイント🫶
-
公式
で紹介されている! - Reactのテストで有名な
Testing Library
をVue
でも使える! -
Testing Library
でユーザー目線のテストを行える! -
Vitest
ですがJest
とほぼ同じでテストコードが書ける! - 基本設定が
5分
で完了する!
環境構築
インストール📝
$ npm i -D vitest @vitest/coverage-v8 @nuxt/test-utils @testing-library/vue happy-dom
- すでにNuxt3はインストールされている前提です!
nuxt.config.ts の修正📝
nuxt.config.ts
export default defineNuxtConfig({
modules: [
'@nuxt/test-utils/module', // 追加
],
})
vitest.config.ts の作成📝
vitest.config.ts
import { defineVitestConfig } from '@nuxt/test-utils/config'
import { coverageConfigDefaults } from 'vitest/config'
export default defineVitestConfig({
test: {
environment: 'nuxt',
coverage: {
exclude: [
...coverageConfigDefaults.exclude,
'nuxt.config.ts',
],
},
},
})
-
environment: 'nuxt'
で Nuxtのランタイム環境での実行となる- 要するにNuxt環境上でテストコードを実行するよーってこと!
-
coverage.exclude
で一部ファイルをテストから除外する-
coverageConfigDefaults.exclude
はデフォルトのルール - これを書かないとデフォルトが無視されてしまうのでルールを追加するときは必要!
-
【任意】 npm scripts の追加📝
package.json
{
~~~~~
"scripts": {
"test": "vitest",
"test:coverage": "vitest run --coverage"
}
}
-
npx
で実行でも大丈夫なので任意にしてます! - これで環境構築は完了です🙌
実際にテストコードを書いてみる🧑💻
コンポーネントを用意する
components/AppButton.vue
<script setup lang="ts">
const props = defineProps<{
buttonText: string
alertMessage: string
}>()
const showAlert = (message: string) => {
alert(message)
}
</script>
<template>
<button @click="showAlert(props.alertMessage)">{{ props.buttonText }}</button>
</template>
- 今回は簡単なボタンコンポーネントを用意
- クリックしたらPropsで渡されたテキストをアラート表示する機能を持つ
コンポーネントのテストコードを書く
tests/components/AppButton.spec.ts
import AppButton from '~/components/AppButton.vue'
import { renderSuspended } from '@nuxt/test-utils/runtime'
import { screen, fireEvent } from '@testing-library/vue'
import { describe, test, expect, vi } from 'vitest'
// alertのモック
const spyOnAlert = vi.spyOn(window, 'alert').mockImplementation(() => vi.fn())
describe('AppButton', async () => {
// コンポーネントをレンダリング(Propsもここで渡す)
await renderSuspended(AppButton, {
props: {
buttonText: 'テキスト',
alertMessage: 'メッセージ',
},
})
// 画面から指定テキストを元にボタンを取得する
const appButton = screen.getByText('テキスト')
test('Propsを渡すと正常に表示される', async () => {
expect(appButton.innerText).toBe('テキスト')
})
test('ボタンを押下した時にアラートが表示される', async () => {
// ボタンをクリックする動作
await fireEvent.click(appButton)
expect(spyOnAlert).toHaveBeenCalledOnce()
expect(spyOnAlert).toHaveBeenCalledWith('メッセージ')
})
})
- テスト内容や各種メソッドはコードのコメントに書いてある通りです!
-
推しポイント
に書いたユーザー目線のテスト
と言うのは、
そのボタンをユーザーが見つけるときはボタンに書いてある文字から見つける
👀
ボタンに振られているIDで見つけるわけではない
🙅
といったように、
テストしたい要素を取得する部分もユーザーの気持ちで行うことができる🫶
(伝わってるかな・・・w)
テストの実行✅
通常のテスト実行
$ npm run test
✓ tests/components/AppButton.spec.ts (2)
✓ AppButton (2)
✓ Propsを渡すと正常に表示される
✓ ボタンを押下した時にアラートが表示される
Test Files 1 passed (1)
Tests 2 passed (2)
Start at 23:11:30
Duration 598ms (transform 220ms, setup 117ms, collect 229ms, tests 2ms, environment 65ms, prepare 113ms)
PASS Waiting for file changes...
- 全てのテストが通っていることが確認🎉
カバレッジ付きのテスト実行
$ npm run test:coverage
✓ tests/components/AppButton.spec.ts (2)
✓ AppButton (2)
✓ Propsを渡すと正常に表示される
✓ ボタンを押下した時にアラートが表示される
Test Files 1 passed (1)
Tests 2 passed (2)
Start at 23:22:15
Duration 600ms (transform 228ms, setup 119ms, collect 208ms, tests 3ms, environment 61ms, prepare 104ms)
% Coverage report from v8
-----------------------------------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
-----------------------------------|---------|----------|---------|---------|-------------------
All files | 100 | 100 | 100 | 100 |
nuxt3-simplest-starter | 100 | 100 | 100 | 100 |
app.vue | 100 | 100 | 100 | 100 |
nuxt3-simplest-starter/components | 100 | 100 | 100 | 100 |
AppButton.vue | 100 | 100 | 100 | 100 |
-----------------------------------|---------|----------|---------|---------|-------------------
- カバレッジについても今回の機能は小規模のため
100%
になっています🎉
((100%はあるべき姿だけど、追い求めすぎるのも良くないと聞いたことがある・・・
最後に🍵
テストコードは僕もまだまだ勉強中です!
環境構築にいつも悩むので誰かの参考になれば幸いです!
いいね
や ストック
待ってます🙏
Nuxt3 × @nuxt/eslint
の記事もよかったら是非😉
https://qiita.com/yuki_s_14/items/96620ccfb1dd897ce9f3
参考記事📎
- Nuxt.js v3: Testing
- Vue Testing Library: Intro
- Vitest: Coverage
- 今回の設定をした実際のデモプロジェクト