メインコンテンツにスキップ

Vue.js

Vue.jsは、Webユーザーインターフェースを構築するための扱いやすく、パフォーマンスが高く、汎用性のあるフレームワークです。WebdriverIOとそのブラウザランナーを使用して、実際のブラウザで直接Vue.jsコンポーネントをテストできます。

セットアップ

Vue.jsプロジェクト内にWebdriverIOをセットアップするには、コンポーネントテストドキュメントの手順に従ってください。ランナーオプション内でvueをプリセットとして選択してください:

// wdio.conf.js
export const config = {
// ...
runner: ['browser', {
preset: 'vue'
}],
// ...
}
情報

すでにViteを開発サーバーとして使用している場合は、vite.config.tsの設定をWebdriverIO設定内で再利用することもできます。詳細については、ランナーオプションviteConfigを参照してください。

Vueプリセットには@vitejs/plugin-vueのインストールが必要です。また、コンポーネントをテストページにレンダリングするためにTesting Libraryの使用をお勧めします。そのため、以下の追加依存関係をインストールする必要があります:

npm install --save-dev @testing-library/vue @vitejs/plugin-vue

その後、以下のコマンドでテストを開始できます:

npx wdio run ./wdio.conf.js

テストの記述

以下のようなVue.jsコンポーネントがあるとします:

./components/Component.vue
<template>
<div>
<p>Times clicked: {{ count }}</p>
<button @click="increment">increment</button>
</div>
</template>

<script>
export default {
data: () => ({
count: 0,
}),

methods: {
increment() {
this.count++
},
},
}
</script>

テストでは、コンポーネントをDOMにレンダリングし、アサーションを実行します。コンポーネントをテストページにアタッチするには、@vue/test-utilsまたは@testing-library/vueのいずれかを使用することをお勧めします。コンポーネントとのインタラクションには、実際のユーザーインタラクションに近い動作をするWebdriverIOコマンドを使用してください:

vue.test.js
import { $, expect } from '@wdio/globals'
import { mount } from '@vue/test-utils'
import Component from './components/Component.vue'

describe('Vue Component Testing', () => {
it('increments value on click', async () => {
// The render method returns a collection of utilities to query your component.
const wrapper = mount(Component, { attachTo: document.body })
expect(wrapper.text()).toContain('Times clicked: 0')

const button = await $('aria/increment')

// Dispatch a native click event to our button element.
await button.click()
await button.click()

expect(wrapper.text()).toContain('Times clicked: 2')
await expect($('p=Times clicked: 2')).toExist() // same assertion with WebdriverIO
})
})

Vue.js用のWebdriverIOコンポーネントテストスイートの完全な例は、サンプルリポジトリで確認できます。

Vue3での非同期コンポーネントのテスト

Vue v3を使用していて、以下のような非同期コンポーネントをテストしている場合:

<script setup>
const res = await fetch(...)
const posts = await res.json()
</script>

<template>
{{ posts }}
</template>

@vue/test-utilsと小さなサスペンスラッパーを使用してコンポーネントをレンダリングすることをお勧めします。残念ながら@testing-library/vueにはまだこのサポートがありません。以下の内容でhelper.tsファイルを作成してください:

import { mount, type VueWrapper as VueWrapperImport } from '@vue/test-utils'
import { Suspense } from 'vue'

export type VueWrapper = VueWrapperImport<any>
const scheduler = typeof setImmediate === 'function' ? setImmediate : setTimeout

export function flushPromises(): Promise<void> {
return new Promise((resolve) => {
scheduler(resolve, 0)
})
}

export function wrapInSuspense(
component: ReturnType<typeof defineComponent>,
{ props }: { props: object },
): ReturnType<typeof defineComponent> {
return defineComponent({
render() {
return h(
'div',
{ id: 'root' },
h(Suspense, null, {
default() {
return h(component, props)
},
fallback: h('div', 'fallback'),
}),
)
},
})
}

export function renderAsyncComponent(vueComponent: ReturnType<typeof defineComponent>, props: object): VueWrapper{
const component = wrapInSuspense(vueComponent, { props })
return mount(component, { attachTo: document.body })
}

そして、以下のようにコンポーネントをインポートしてテストします:

import { $, expect } from '@wdio/globals'

import { renderAsyncComponent, flushPromises, type VueWrapper } from './helpers.js'
import AsyncComponent from '/components/SomeAsyncComponent.vue'

describe('Testing Async Components', () => {
let wrapper: VueWrapper

it('should display component correctly', async () => {
const props = {}
wrapper = renderAsyncComponent(AsyncComponent, { props })
await flushPromises()
await expect($('...')).toBePresent()
})

afterEach(() => {
wrapper.unmount()
})
})

NuxtでのVueコンポーネントのテスト

ウェブフレームワークNuxtを使用している場合、WebdriverIOは自動的にauto-import機能を有効にし、Vueコンポーネントとヌクストページのテストを容易にします。ただし、設定で定義されているNuxtアプリケーションのコンテキストを必要とするNuxtモジュールはサポートされません。

その理由は以下の通りです:

  • WebdriverIOはブラウザ環境のみでNuxtアプリケーションを起動することができません
  • コンポーネントテストがNuxt環境に過度に依存すると複雑さが増し、これらのテストはe2eテストとして実行することをお勧めします
情報

WebdriverIOはNuxtアプリケーション上でe2eテストを実行するためのサービスも提供しています。詳細はwebdriverio-community/wdio-nuxt-serviceを参照してください。

組み込みコンポーザブルのモック

コンポーネントがネイティブNuxtコンポーザブル(例:useNuxtData)を使用している場合、WebdriverIOは自動的にこれらの関数をモック化し、その動作を変更したり、アサーションを行ったりすることができます:

import { mocked } from '@wdio/browser-runner'

// 例:コンポーネントが次のように`useNuxtData`を呼び出している場合
// `const { data: posts } = useNuxtData('posts')`
// テスト内でそれに対してアサーションできます
expect(useNuxtData).toBeCalledWith('posts')
// また、その動作を変更することができます
mocked(useNuxtData).mockReturnValue({
data: [...]
})

サードパーティのコンポーザブルの扱い

Nuxtプロジェクトを強化できるサードパーティモジュールは自動的にモック化できません。そのような場合は手動でモック化する必要があります。例えば、アプリケーションがSupabaseモジュールプラグインを使用している場合:

export default defineNuxtConfig({
modules: [
"@nuxtjs/supabase",
// ...
],
// ...
});

そして、コンポーザブルのどこかでSupabaseのインスタンスを作成している場合:

const superbase = useSupabaseClient()

次のようなエラーでテストが失敗します:

ReferenceError: useSupabaseClient is not defined

この場合、useSupabaseClient関数を使用するモジュール全体をモック化するか、この関数をモック化するグローバル変数を作成することをお勧めします:

import { fn } from '@wdio/browser-runner'
globalThis.useSupabaseClient = fn().mockReturnValue({})

Welcome! How can I help?

WebdriverIO AI Copilot