Vue Testing Library (1/2)
Für das Testen eines aktuellen Lotto-Projektes waren wir auf der Suche nach einer Testing-Library, die den Fokus auf ein Testen nahe am erwarteten User-Verhalten in den Fokus stellt. Fündig geworden sind wir hier bei der Vue-Testing-Library, mit der nicht die konkrete Implementierung von Komponenten getestet wird, sondern ihre Funktionalität. Dadurch soll gewährleistet werden, dass, wenn wir Änderungen an der Implementierung vornehmen, beispielsweise bei einem Refactoring, und dabei die Funktionalität weiter gleich bleibt, die Tests weiterhin valide sind.
The more your tests resemble the way your software is used, the more confidence they can give you. (Leitsatz der DOM-Testing-Library)
Die Vue-Testing-Library basiert auf der DOM-Testing-Library und den @vue/test-utils. Sie ergänzt die DOM-Testing-Library um APIs, die es ermöglichen, mit Vue zu arbeiten und übernimmt von den @vue/test-utils nur die Methoden, die sie für das User-zentrierte Testen als sinnvoll ansieht.
Zunächst einmal ist kein aufwendiges Setup notwendig, um die Library im eigenen Projekt nutzen zu können. Zunächst muss das Package installiert, und dann die benötigten Bestandteile in die einzelnen Test-Dateien kopiert werden. In der Praxis sieht das dann so aus:
yarn add @testing-library/vue
import %7B render, fireEvent %7D from '@testing-library/vue'
Wir benötigen für jeden Test die von der Vue-Testing-Library bereitgestellte render-Funktion. Mit dieser Funktion können wir die zu testende Komponente für den Test rendern lassen. Diese Funktion kann bis zu drei Parameter annehmen, die Komponente, Options und eine Callback-Funktion. In einem einfachen Beispiel benötigen wir nur den ersten Parameter, bei aufwändigeren Tests lohnt es sich aber, auch die weiteren beiden Parameter zu nutzen. (Über die Options können beispielsweise Properties, Mocks oder Vue-State-Models in den Test hineingegeben werden!)
Neben der render-Funktion bietet die Vue-Testing-Library eine Vielzahl an Queries, die wir in unseren Tests nutzen können, um bestimmte Elemente aus der Komponente zu greifen. Diese Queries kann man für die komplette Test-Datei importieren oder für die einzelnen Tests per Destructuring Assignment aus der render-Funktion ziehen.
Mit diesen Mitteln können wir schon testen, ob sich bestimmte Elemente in der gerenderten Komponente befinden:
expect(getByRole('button'‚ %7B name: 'Confirm'%7D))
expect(getByLabelText('Date of birth')
Es gibt eine Vielzahl von Queries die es sich einmal lohnt anzuschauen, um zu erkennen, welchen Möglichkeiten diese bieten. Um sich dann zu entscheiden, in welcher Situation man am besten welche Query einsetzt, stellt die Vue-Testing-Library in ihrer Dokumentation eine Orientierungshilfe zur Verfügung: Die Queries sind hier nach Priorität geordnet, in Hinblick darauf, wie sehr sie das Ziel der Vue-Testing-Library unterstützen können, ein User-zentriertes Testen zu ermöglichen.
Um beim Testen verschiedene Events zu simulieren, bietet die Vue-Testing-Library fireEvent. Damit lassen sich Events, wie das click-Event auf einem Button oder das Ausfüllen eines Inputs ausführen. (Eine Alternative dazu ist das UserEvent, mit dem man noch mehr Flexibilität und eine genauere Simulation der User-Aktivität erreichen kann.)
Ein erstes einfaches Beispiel bietet die Dokumentation der Library:
<template>
<div>
<p>Times clicked: %7B%7B count %7D%7D</p>
<button @click="increment">increment</button>
</div>
</template>
<script>
export default %7B
data: () => (%7B
count: 0,
%7D),
methods: %7B
increment() %7B
this.count++
%7D,
%7D,
%7D
</script>
import %7B render, fireEvent %7D from '@testing-library/vue'
import Component from './Component.vue'
test('increments value on click', async () => %7B
const %7B getByText %7D = render(Component)
getByText('Times clicked: 0')
const button = getByText('increment')
await fireEvent.click(button)
getByText('Times clicked: 1')
%7D)