この記事でやること
-
Vitest
で Vuetify のコンポーネントを使ったテストが動くようにする -
vitest-setup.ts
を作って、共通のテスト設定をまとめる
はじめに
Vue 3 のアプリで Vuetify を使っているコンポーネントをテストしようとした時、何にも考えずテストを書いたところ、こんなエラーが出てきたところが始まりでした。
TypeError: Unknown file extension ".css" for /usr/src/node_modules/vuetify/lib/directives/ripple/VRipple.css
ふむふむ.css
なんて知らないぞと・・・
そこから少し手間取ってしまったので奮闘記として残します!
まずは全体
テスト全体でVuetifyが使えるようにvitest-setup.tsを作成
import { config } from "@vue/test-utils";
import ResizeObserver from "resize-observer-polyfill";
import { createVuetify } from "vuetify";
import * as components from "vuetify/components";
import * as directives from "vuetify/directives";
// Vuetifyインスタンスを作成
const vuetify = createVuetify({
components,
directives,
});
// Vue Test Utilsのglobal設定にプラグインとして追加
config.global.plugins = (config.global.plugins || []).concat([vuetify]);
// ResizeObserverのpolyfill
window.ResizeObserver = ResizeObserver;
vitest.config.ts
にsetupFiles
とinline
の項目を追加し作成ファイルを指定
import { fileURLToPath } from "node:url";
import { configDefaults, defineConfig, mergeConfig } from "vitest/config";
import viteConfig from "./vite.config";
export default mergeConfig(
viteConfig,
defineConfig({
test: {
environment: "jsdom",
exclude: [...configDefaults.exclude, "e2e/**"],
root: fileURLToPath(new URL("./", import.meta.url)),
globals: true,
setupFiles: ["./vitest-setup.ts"], // 追加
server: { // 追加
deps: {
inline: ["vuetify"],
},
},
},
}),
);
このようなレイアウト用コンポーネントのテストを想定
<script setup lang="ts">
const props = defineProps({
testText: {
type: String,
default: "test1234",
},
});
</script>
<template>
<v-app-bar> hogehoge </v-app-bar>
<v-main>
<v-container>
<h1>{{ testText }}</h1>
</v-container>
</v-main>
<v-footer app color="primary"> fugafuga </v-footer>
</template>
import { mount } from "@vue/test-utils";
import { describe, expect, it } from "vitest";
import TestPage from "../TestPage.vue";
describe("testComponent", async () => {
it("should render", async () => {
const wrapper = mount({
template: "<v-layout><TestPage :test-text='testText'/></v-layout>",
components: {
TestPage,
},
props: {
testText: "test123",
},
});
expect(wrapper.html()).toContain("test123");
});
});
1. configファイルに追記
公式を見てみたところvuetifyの依存関係をインライン化しなきゃということで、テスト用のconfigファイルvitest.config.ts
に設定を追加する模様。
test: {
globals: true,
environment: 'jsdom',
server: {
deps: {
inline: ['vuetify'],
},
},
},
})
2. ResizeObserverパッケージ追加
公式ドキュメントにも書かれていますが、jsdom では ResizeObserver がサポートされていないため、別途パッケージを追加します。
npm install resize-observer-polyfill --save-dev
3. いざテスト
テストの対象はVuetifyのレイアウト用のコンポーネントなども使っているものです。
<script setup lang="ts">
const props = defineProps({
testText: {
type: String,
default: "test1234",
},
});
</script>
<template>
<v-app-bar> hogehoge </v-app-bar>
<v-main>
<v-container>
<h1>{{ testText }}</h1>
</v-container>
</v-main>
<v-footer app color="primary"> fugafuga </v-footer>
</template>
こんな感じでテスト!
JSDOM 環境でvite-plugin-vuetify
の autoImport: true 設定
は動かないようなので、components
とdirectives
を全てインポートします。
import { mount } from "@vue/test-utils";
import { createVuetify } from "vuetify";
import * as components from "vuetify/components";
import * as directives from "vuetify/directives";
const vuetify = createVuetify({
components,
directives,
});
global.ResizeObserver = require("resize-observer-polyfill");
describe("testComponent", async () => {
it("should render", async () => {
const wrapper = mount(testComponent, {
props: {
testText: "test123",
},
global: {
plugins: [vuetify],
},
});
expect(wrapper.html()).toContain("test123");
残念ながらこのままではエラーとなりました。
レイアウト用コンポーネントなどは公式サイトに記載通りv-layout
でラップする必要がありました。
Error: [Vuetify] Could not find injected layout
ということで、v-layoutでラップします。
const wrapper = mount(
{
template: "<v-layout><TestPage :test-text='testText'/></v-layout>",
components: {
TestPage,
},
props: {
testText: "test123",
},
},
{
global: {
plugins: [vuetify],
},
},
);
expect(wrapper.html()).toContain("test123");
これで無事テスト成功しました👏👏👏
4. vitest-setup.ts
を作成
テストが作成出来るようになりましたが、毎回createVuetify
やplugins: [vuetify]
を記述するのは少々面倒。
そこで、以下の内容をvitest-setup.ts
に切り出します。
- Vuetify のコンポーネント・ディレクティブを読み込み
- Vue Test Utils の config.global.plugins に vuetify を追加
- ResizeObserverに
resize-observer-polyfill
を設定
import { config } from "@vue/test-utils";
import ResizeObserver from "resize-observer-polyfill";
import { createVuetify } from "vuetify";
import * as components from "vuetify/components";
import * as directives from "vuetify/directives";
// Vuetifyインスタンスを作成
const vuetify = createVuetify({
components,
directives,
});
// Vue Test Utilsのglobal設定にプラグインとして追加
config.global.plugins = (config.global.plugins || []).concat([vuetify]);
// ResizeObserverのpolyfill
window.ResizeObserver = ResizeObserver;
作成したファイルをvitest.config.ts
にsetupFiles
として設定します。
import { fileURLToPath } from "node:url";
import { configDefaults, defineConfig, mergeConfig } from "vitest/config";
import viteConfig from "./vite.config";
export default mergeConfig(
viteConfig,
defineConfig({
test: {
environment: "jsdom",
exclude: [...configDefaults.exclude, "e2e/**"],
root: fileURLToPath(new URL("./", import.meta.url)),
globals: true,
setupFiles: ["./vitest-setup.ts"], // 追加
server: { // 追加
deps: {
inline: ["vuetify"],
},
},
},
}),
);
これで、Vuetifyを使ったコンポーネントも簡単にテスト出来るようになりました。
終わりに
- やっと少しずつVueに慣れてきました
- 今後もテストなど少しずつ残していきます