Vue.js
Vue.js ist ein zugängliches, leistungsstarkes und vielseitiges Framework zum Erstellen von Web-Benutzeroberflächen. Sie können Vue.js-Komponenten direkt in einem echten Browser mit WebdriverIO und seinem Browser-Runner testen.
Setup
Um WebdriverIO in Ihrem Vue.js-Projekt einzurichten, folgen Sie den Anweisungen in unserer Komponententest-Dokumentation. Stellen Sie sicher, dass Sie vue
als Voreinstellung in Ihren Runner-Optionen auswählen, z.B.:
// wdio.conf.js
export const config = {
// ...
runner: ['browser', {
preset: 'vue'
}],
// ...
}
Wenn Sie bereits Vite als Entwicklungsserver verwenden, können Sie Ihre Konfiguration in vite.config.ts
auch einfach in Ihrer WebdriverIO-Konfiguration wiederverwenden. Weitere Informationen finden Sie unter viteConfig
in den Runner-Optionen.
Die Vue-Voreinstellung erfordert, dass @vitejs/plugin-vue
installiert ist. Außerdem empfehlen wir die Verwendung von Testing Library zum Rendern der Komponente auf der Testseite. Dafür müssen Sie die folgenden zusätzlichen Abhängigkeiten installieren:
- npm
- Yarn
- pnpm
npm install --save-dev @testing-library/vue @vitejs/plugin-vue
yarn add --dev @testing-library/vue @vitejs/plugin-vue
pnpm add --save-dev @testing-library/vue @vitejs/plugin-vue
Sie können dann die Tests starten, indem Sie Folgendes ausführen:
npx wdio run ./wdio.conf.js
Tests schreiben
Angenommen, Sie haben die folgende Vue.js-Komponente:
<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>
Rendern Sie in Ihrem Test die Komponente in das DOM und führen Sie Assertions darauf aus. Wir empfehlen, entweder @vue/test-utils
oder @testing-library/vue
zu verwenden, um die Komponente an die Testseite anzuhängen. Verwenden Sie WebdriverIO-Befehle, um mit der Komponente zu interagieren, da sie sich näher an tatsächlichen Benutzerinteraktionen orientieren, z.B.:
- @vue/test-utils
- @testing-library/vue
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
})
})
import { $, expect } from '@wdio/globals'
import { render } from '@testing-library/vue'
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 { getByText } = render(Component)
// getByText returns the first matching node for the provided text, and
// throws an error if no elements match or if more than one match is found.
getByText('Times clicked: 0')
const button = await $(getByText('increment'))
// Dispatch a native click event to our button element.
await button.click()
await button.click()
getByText('Times clicked: 2') // assert with Testing Library
await expect($('p=Times clicked: 2')).toExist() // assert with WebdriverIO
})
})
Ein vollständiges Beispiel einer WebdriverIO-Komponententestsuite für Vue.js finden Sie in unserem Beispiel-Repository.
Testen von asynchronen Komponenten in Vue3
Wenn Sie Vue v3 verwenden und asynchrone Komponenten wie die folgende testen:
<script setup>
const res = await fetch(...)
const posts = await res.json()
</script>
<template>
{{ posts }}
</template>
Wir empfehlen, @vue/test-utils
und einen kleinen Suspense-Wrapper zu verwenden, um die Komponente zu rendern. Leider hat @testing-library/vue
dafür noch keine Unterstützung. Erstellen Sie eine helper.ts
-Datei mit folgendem Inhalt:
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 })
}
Importieren und testen Sie die Komponente dann wie folgt:
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()
})
})
Testen von Vue-Komponenten in Nuxt
Wenn Sie das Web-Framework Nuxt verwenden, aktiviert WebdriverIO automatisch die Auto-Import-Funktion und erleichtert das Testen Ihrer Vue-Komponenten und Nuxt-Seiten. Allerdings können Nuxt-Module, die Sie möglicherweise in Ihrer Konfiguration definieren und die Kontext zur Nuxt-Anwendung benötigen, nicht unterstützt werden.
Gründe dafür sind:
- WebdriverIO kann eine Nuxt-Anwendung nicht ausschließlich in einer Browser-Umgebung initiieren
- Wenn Komponententests zu stark von der Nuxt-Umgebung abhängen, entsteht Komplexität, und wir empfehlen, diese Tests als E2E-Tests auszuführen
WebdriverIO bietet auch einen Service zum Ausführen von E2E-Tests auf Nuxt-Anwendungen, siehe webdriverio-community/wdio-nuxt-service
für weitere Informationen.
Mocken von eingebauten Composables
Falls Ihre Komponente ein natives Nuxt-Composable verwendet, z.B. useNuxtData
, wird WebdriverIO diese Funktionen automatisch mocken und ermöglicht es Ihnen, ihr Verhalten zu ändern oder gegen sie zu testen, z.B.:
import { mocked } from '@wdio/browser-runner'
// z.B. verwendet Ihre Komponente `useNuxtData` auf folgende Weise
// `const { data: posts } = useNuxtData('posts')`
// in Ihrem Test können Sie dagegen testen
expect(useNuxtData).toBeCalledWith('posts')
// und ihr Verhalten ändern
mocked(useNuxtData).mockReturnValue({
data: [...]
})
Umgang mit Composables von Drittanbietern
Alle Module von Drittanbietern, die Ihr Nuxt-Projekt verbessern können, werden nicht automatisch gemockt. In diesen Fällen müssen Sie sie manuell mocken, z.B. wenn Ihre Anwendung das Supabase-Modul-Plugin verwendet:
export default defineNuxtConfig({
modules: [
"@nuxtjs/supabase",
// ...
],
// ...
});
und Sie irgendwo in Ihren Composables eine Instanz von Supabase erstellen, z.B.:
const superbase = useSupabaseClient()
wird der Test aufgrund von folgendem fehlschlagen:
ReferenceError: useSupabaseClient is not defined
Hier empfehlen wir, entweder das gesamte Modul, das die Funktion useSupabaseClient
verwendet, zu mocken oder eine globale Variable zu erstellen, die diese Funktion mockt, z.B.:
import { fn } from '@wdio/browser-runner'
globalThis.useSupabaseClient = fn().mockReturnValue({})