Migration Vue 2 zu Vue 3 mit Composition API, Typescript und script setup: Herausforderung wrapper.setData() in Unit Tests
In einem unserer Projekte migrieren wir nach der Boy-Scout-Regel Schritt für Schritt die Vue 2 Komponenten zu Vue 3 mit script setup und Typescript. Dabei müssen gelegentlich auch die Unit Tests angepasst werden.
Die Migration ist meist unkompliziert. In einem Unit Test wurde allerdings wrapper.setData() aufgerufen. Das funktioniert so mit der Composition API nicht mehr.
Die zu migrierende Vue 2 Komponente enthielt diesen Code:
data() {
return {
isDirty : false
}
}
Der Unit Test dazu enthielt diesen Test:
test (`saving changes allowed`, async () => {
await wrapper.setData ({isDirty: true})
expect (…)…
}
Die Herausforderungen:
- wrapper.setData() funktioniert auf script setup Komponenten nicht mehr.
- console.log(wrapper.vm) zeigt keine Refs und Funktionen auf. Die IDE erkennt auch nichts in der Code Completion und stellt den Aufruf sogar als Warning dar.
Die Lösung:
Der Code der Komponente mit Vue 3 und script setup
const isDirty = ref(false)
function foo() {}
Im migrierten Unit Test kann man über vm auf die Ref zugreifen:
test.each(allowedRoles)(`saving changes allowed for %s`, async (role) => {
wrapper.vm.isDirty = true
await nextTick()
})
Aha-Momente hierbei:
-
- Obwohl isDirty nun eine Ref ist, darf man im Unit Test nicht wrapper.vm.isDirty.value schreiben.
- Eine Ref wird von der IDE erkannt, wenn sie da steht aber nicht in der Code Completion. (Es gibt keinen Warning marker, und nachdem sie geschrieben ist, wird der Typ im Popup korrekt angezeigt.)
- Eine Funktion, bspw. wrapper.vm.foo() wird nie von der IDE erkannt und erhält einen Warning Marker “unknown function”. ABER: Führt man den Test aus, wird die Funktion korrekt aufgerufen. Der nächste Punkt trifft dann trotzdem zu.
- Ohne await nextTick() funktioniert der Vue 3 Test Code trotzdem nicht. Das ist das Ungewöhnlichste an dieser Migration. Testet man eine Vue 2 Komponente braucht man das nextTick() nicht. Die Änderung des internen States der data Properties wirkt sich sofort im Template Code aus. Beim Verwenden von Refs verhält sich Vue anders.
- defineExpose() hat keinen Einfluss auf console.log(wrapper.vm) oder die IDE Code Completion in Unit Tests.
- Ruft man eine Funktion auf, funktioniert zwar der Unit Test, aber der Build schlägt fehl, da der vue-tsc Befehl die Funktion nicht findet und den Build abbricht. Da der problematische Code im Unit Test liegt, kann man dem vue-tsc über eine Konfigurationsdatei mitteilen, Unit Tests beim Build zu ignorieren:
tsconfig.build-dts.json neben tsconfig.json
{
„extends“: „,./tsconfig.json“,
„exclude“: [
„**/*.spec.ts“,
„**/*.test.ts“,
]
}