Rumah > Soal Jawab > teks badan
Berdasarkan tajuk, adakah ini mungkin?
Saya cuba menguji komponen mudah aplikasi Vue yang mengandungi pengepala dan butang yang mengubah hala pengguna ke halaman seterusnya. Saya ingin menguji sama ada apabila butang diklik acara/mesej dihantar ke penghala dan semak sama ada laluan destinasi adalah betul.
Aplikasi berstruktur seperti berikut:
App.Vue - Komponen kemasukan
<script setup lang="ts"> import { RouterView } from "vue-router"; import Wrapper from "@/components/Wrapper.vue"; import Container from "@/components/Container.vue"; import HomeView from "@/views/HomeView.vue"; </script> <template> <Wrapper> <Container> <RouterView/> </Container> </Wrapper> </template> <style> body{ @apply bg-slate-50 text-slate-800 dark:bg-slate-800 dark:text-slate-50; } </style>
router/index.ts - Fail konfigurasi Penghala Vue
import {createRouter, createWebHistory} from "vue-router"; import HomeView from "@/views/HomeView.vue"; export enum RouteNames { HOME = "home", GAME = "game", } const routes = [ { path: "/", name: RouteNames.HOME, component: HomeView, alias: "/home" }, { path: "/game", name: RouteNames.GAME, component: () => import("@/views/GameView.vue"), }, ]; const router = createRouter({ history: createWebHistory(import.meta.env.BASE_URL), routes }); export default router;
HomeView.Vue - Paparan pintu masuk RouterView dalam komponen Apl
<template> <Header title="My App"/> <ButtonRouterLink :to="RouteNames.GAME" text="Start" class="btn-game"/> </template> <script setup> import Header from "@/components/Header.vue"; import ButtonRouterLink from "@/components/ButtonRouterLink.vue"; import {RouteNames} from "@/router/"; </script>
ButtonRouterLink.vue
<template> <RouterLink v-bind:to="{name: to}" class="btn"> {{ text }} </RouterLink> </template> <script setup> import { RouterLink } from "vue-router"; const props = defineProps({ to: String, text: String }) </script>
Memandangkan ia menggunakan CompositionAPI dan TypeScript, adakah terdapat cara untuk mensimulasikan penghala dalam ujian Vitest?
Berikut ialah contoh struktur fail ujian (HomeView.spec.ts):
import {shallowMount} from "@vue/test-utils"; import { describe, test, vi, expect } from "vitest"; import { RouteNames } from "@/router"; import HomeView from "../../views/HomeView.vue"; describe("Home", () => { test ('navigates to game route', async () => { // Check if the button navigates to the game route const wrapper = shallowMount(HomeView); await wrapper.find('.btn-game').trigger('click'); expect(MOCK_ROUTER.push).toHaveBeenCalledWith({ name: RouteNames.GAME }); }); });
Saya mencuba pelbagai kaedah: vi.mock('vue-router'), vi.spyOn(useRoute,'push'), vue-router-mock library, tetapi saya tidak dapat menjalankan ujian, nampaknya penghala hanya tidak tersedia.
Berikutan cadangan @tao, saya menyedari bahawa menguji acara klik dalam HomeView bukanlah ujian yang baik (pustaka yang diuji, bukan apl saya), jadi saya menambah ujian ButtonRouterLink untuk melihat sama ada Vue RouterLink dipaparkan dengan betul , menggunakan parameter ke:
import {mount, shallowMount} from "@vue/test-utils"; import { describe, test, vi, expect } from "vitest"; import { RouteNames } from "@/router"; import ButtonRouterLink from "../ButtonRouterLink.vue"; vi.mock('vue-router'); describe("ButtonRouterLink", () => { test (`correctly transforms 'to' param into a router-link prop`, async () => { const wrapper = mount(ButtonRouterLink, { props: { to: RouteNames.GAME } }); expect(wrapper.html()).toMatchSnapshot(); }); });
Ia memaparkan rentetan HTML kosong""
exports[`ButtonRouterLink > correctly transforms 'to' param into a router-link prop 1`] = `""`;
Disertai dengan amaran Vue yang tidak begitu membantu (jenis yang dijangka tidak dinyatakan):
[Vue warn]: Invalid prop: type check failed for prop "to". Expected , got Object at <RouterLink to= { name: 'game' } class="btn btn-blue" > at <ButtonRouterLink to="game" ref="VTU_COMPONENT" > at <VTUROOT> [Vue warn]: Invalid prop: type check failed for prop "ariaCurrentValue". Expected , got String with value "page". at <RouterLink to= { name: 'game' } class="btn btn-blue" > at <ButtonRouterLink to="game" ref="VTU_COMPONENT" > at <VTUROOT> [Vue warn]: Component is missing template or render function. at <RouterLink to= { name: 'game' } class="btn btn-blue" > at <ButtonRouterLink to="game" ref="VTU_COMPONENT" > at <VTUROOT>
P粉7594512552024-03-28 00:46:02
Ini mungkin.
Terdapat perbezaan penting antara contoh anda dan contoh rasmi: dalam komponen yang diuji, anda meletakkannya dalam komponen perantaraan dan bukannya menggunakan butang RouterLink
(或使用router.push
).
Bagaimana ini akan menukar ujian unit?
Masalah pertama ialah anda menggunakan shallowMount
shallowMount
,它会用空容器替换子组件。在你的情况下,这意味着ButtonRouterLink
不再包含RouterLink
, yang menggantikan komponen kanak-kanak dengan bekas kosong. Dalam kes anda ini bermakna ButtonRouterLink
tidak lagi mengandungi RouterLink
dan tidak melakukan apa-apa dengan acara klik, ia hanya menerima acara klik.
Pilihan untuk menyelesaikan masalah ini ialah:
mount
而不是shallowMount
dan jadikan ujian integrasi dan bukannya ujian unit ButtonRouterLink
的测试中。一旦测试了ButtonRouterLink
的任何:to
是否正确转换为{ name: to }
并传递给RouterLink
,你只需要测试这些:to
是否正确传递给使用它们的任何组件中的<ButtonRouterLink />
. Masalah kedua yang timbul dengan memindahkan fungsi ini ke dalam komponennya sendiri adalah lebih halus sedikit. Secara amnya, saya menjangkakan ujian berikut untuk ButtonRouterLink berfungsi:
import { RouterLinkStub } from '@vue/test-utils'
const wrapper = shallowMount(YourComp, {
stubs: {
RouterLink: RouterLinkStub
}
})
expect(wrapper.findComponent(RouterLinkStub).props('to')).toEqual({
name: RouterNames.GAME
})
Saya terkejut, ujian ini gagal dengan perkara yang sama :to
属性值不是{ name: RouterNames.GAME }
,而是'game'
,这是我传递给ButtonRouterLink
的值。就像我们的组件从未将value
转换为{ name: value }
ia mendakwa diterima dalam RouterLinkStub.
Agak pelik.
Ternyata masalahnya ialah nilai <RouterLink />
恰好是我们组件的根元素。这意味着组件(<BottomRouterLink>
)在DOM中被<RouterLinkStub>
替换,但:to
dibaca dari yang pertama dan bukan yang terakhir. Pendek kata, jika templat kelihatan seperti ini, ujian akan berjaya:
<span>
<RouterLink ... />
</span>
Untuk membetulkannya, kita perlu mengimport nilai RouterLink
组件(来自vue-router
),并找到它,而不是找到RouterLinkStub
。为什么?@vue/test-utils
足够聪明,可以找到存根组件而不是实际组件,但是这样,.findComponent()
只会匹配替换后的元素,而不是在它仍然是ButtonRouterLink
(未处理)时。此时,:to
的值已经被解析为RouterLink
sebenar yang diterima.
Ujian lengkap adalah seperti berikut:
import { shallowMount } from '@vue/test-utils' import { describe, it, expect } from 'vitest' import ButtonRouterLink from '../src/ButtonRouterLink.vue' import { RouterLinkStub } from '@vue/test-utils' import { RouterLink } from 'vue-router' const TEST_STRING = 'this is a test string' describe('ButtonRouterLink', () => { it(`should transform 'to' into '{ name: to }'`, () => { const wrapper = shallowMount(ButtonRouterLink, { props: { to: TEST_STRING }, stubs: { RouterLink: RouterLinkStub } }) expect(wrapper.findComponent(RouterLink).props('to')).toEqual({ name: TEST_STRING }) }) })
Sedikit rumit.