LoginSignup
2
1
お題は不問!Qiita Engineer Festa 2024で記事投稿!
Qiita Engineer Festa20242024年7月17日まで開催中!

【Nuxt3】5分で完了!Vitest と Testing Libraryを用いた単体テスト実行環境を作る!

Last updated at Posted at 2024-06-14

閲覧頂き、ありがとうございます🙇

この記事は Vitest@nuxt/test-utilsTesting 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 LibraryVue でも使える!
  • 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

参考記事📎

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1