Vueでテストを書く
テストと一緒にVueのアプリを書いてみます。レポジトリをzunda/clean-urlで、稼働例をclean-url.zunda.ninjaで参照できます。
雛形のアプリを作る
新しいディレクトリにVueのアプリを作ります。
手元のXubuntu 24.01にはyarnパッケージとしてyarn 1.22.15が入っています。
$ mkdir clean-url
$ cd clean-url
$ yarn init
$ yarn add -D @vue/cli
$ yarn run vue create .
package.jsonを眺めると、yarn serveで開発用のサーバを起動できそうです。
{
"scripts": {
"serve": "vue-cli-service serve"
}
}
サーバが起動しました。念のためブラウザで閲覧できるのを確認します。
$ yarn serve
(中略)
App running at:
- Local: http://localhost:8080/
- Network: http://192.168.1.141:8080/
Note that the development build is not optimized.
To create a production build, run yarn build.
ユニットテストを書いて実行する
今回は、入力されたURLを加工するアプリを書いてみます。
まず、URLをパーズするヘルパ関数を書きます。
src/helpers.jsに、とりあえず最小の機能を持った下記の関数を定義します。
export function parseUrl(url) {
return URL.parse(url)
}
VueによるTestingガイドによると、テストフレームワークにはVitestが推奨のようです。インストールします。
$ yarn add -D vitest
Getting Startedガイドに従って、
package.jsonにtestスクリプトを追加します。
{
"scripts": {
"test": "vitest"
}
}
さらに、src/helpers.spec.jsにユニットテストを書きます。
import { describe, expect, test } from 'vitest'
import { parseUrl } from './helpers'
describe('parseUrl', () => {
test('parses a minimal URL', () => {
const parsed = parseUrl('https://example.com')
const expected = { host: 'example.com', protocol: 'https:' }
Object.entries(expected).forEach(([prop, goal]) => {
expect(parsed[prop]).toBe(goal)
})
})
})
ユニットテストを実行します。
$ yarn test
yarn run v1.22.15
$ vitest
DEV v4.0.18 /home/zunda/c/src/local/clean-url
✓ src/helpers.spec.js (1 test) 3ms
✓ parseUrl (1)
✓ parses a minimal URL 1ms
Test Files 1 passed (1)
Tests 1 passed (1)
Start at 15:11:03
Duration 190ms (transform 29ms, setup 0ms, import 44ms, tests 3ms, environment 0ms)
PASS Waiting for file changes...
press h to show help, press q to quit
成功しました。
Vueコンポーネントのふるまいをテストする
VitestのComponent Testingガイドによると、Vueのテストには@testing-library/vueを使うのが一般的なようです。Testing LibraryのQuickstartに従ってテストを進めてみます。
ここでは、src/components/UrlCleaner.vueに定義した、UrlCleanerComponentをテストしてみます。1つ目のinputエレメントに任意のURLを入力すると、2つ目の読み取り専用のinputエレメントにv=…以外のクエリパラメータが削除されたURLが出力されるはずです。
この段階では、src/UrlCleaner.jsからUrlCleanerクラスがエキスポートされて、このクラスにはparse()スタティックメソッドとremoveQueriesExceptFor()メソッドが定義されていました。
<template>
<div class="urlCleaner">
<input v-model="dirtyUrl" placeholder="Dirty URL" type="url" />
<br/>
<input v-model="cleanUrl" placeholder="Clean URL" readonly="readonly" />
</div>
</template>
<script>
import { UrlCleaner } from '../UrlCleaner'
export default {
name: 'UrlCleanerComponent',
data() {
return {
dirtyUrl: ""
}
},
computed: {
cleanUrl() {
const x = UrlCleaner.parse(this.dirtyUrl)
return x ? x.removeQueriesExceptFor(["v"]).toString() : ""
}
}
}
</script>
テストでVueコンポーネントをimportするためには、@vitejs/plugin-vueをインスールして有効にする必要があるようです1。NodeからでブラウザのAPIを利用できるようにするため、jsdomもインストールします2。
$ yarn add --dev @testing-library/vue @vitejs/plugin-vue jsdom
vite.config.jsとして下記のファイルを作成します。
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
export default defineConfig({
plugins: [vue()],
test: {
include: [
'./src/**/*.spec.js'
],
environment: 'jsdom'
}
})
src/tests/UrlCleaner.spec.jsにテストを書き始めます。Testing Libraryによる例では、await fireEvent.update(エレメント, 文字列)で入力するようです。
import { describe, expect, test } from 'vitest'
import { render, cleanup, fireEvent, screen } from '@testing-library/vue'
import UrlCleanerComponent from '../components/UrlCleaner.vue'
describe('UrlCleanerComponent', () => {
test('removes queries from a URL', async () => {
render(UrlCleanerComponent)
const dirty = screen.getByPlaceholderText('Dirty URL')
const clean = screen.getByPlaceholderText('Clean URL')
const dirtyUrl = 'http://example.com/path/?p=parameter&v=keep'
const cleanUrl = 'http://example.com/path/?v=keep'
await fireEvent.update(dirty, dirtyUrl)
expect(dirty.value).toBe(dirtyUrl)
expect(clean.value).toBe(cleanUrl)
cleanup()
})
})
--runオプションを付けて実行するとvitestは一度だけの実行で停止してくれるようです。テストが通りました。
$ yarn test --run src/tests/UrlCleaner.spec.js
yarn run v1.22.15
$ vitest --run src/tests/UrlCleaner.spec.js
RUN v4.0.18 /home/zunda/c/src/local/clean-url
✓ src/tests/UrlCleaner.spec.js (1 test) 36ms
✓ UrlCleanerComponent (1)
✓ removes queries from a URL 34ms
Test Files 1 passed (1)
Tests 1 passed (1)
Start at 11:31:41
Duration 1.13s (transform 95ms, setup 0ms, import 300ms, tests 36ms, environment 631ms)
Done in 1.65s.
Yarnを新しいものにする
コードを書き続けていると、
手元のyarn 1.22.15ではnode_modulesディレクトリ以下にインストールされるモジュールのバージョンが安定せず、
yarn installの繰り返しによって時折コマンドが失敗することがわかりました。
Yarn 4+のページに従ってyarnコマンドを4.12.0に更新したところ、
yarn testコマンドの実行によってインストールされているモジュールのテストも走るようになりました。
vite.config.jsで定義したdefineConfig関数の引数のtestプロパティにincludeプロパティとして['./src/**/*.spec.js']を追加することで、
srcディレクトリ以下のテストのみを走らせることができました。