国产av日韩一区二区三区精品,成人性爱视频在线观看,国产,欧美,日韩,一区,www.成色av久久成人,2222eeee成人天堂

模擬Vue RouterView/RouterLink在Vitest(組合 API)中
P粉478188786
P粉478188786 2024-03-27 09:49:56
0
1
866

根據(jù)標(biāo)題,這有可能嗎?

我正在嘗試測(cè)試Vue應(yīng)用程序的一個(gè)簡(jiǎn)單組件,其中包含一個(gè)標(biāo)題和一個(gè)按鈕,該按鈕將用戶重定向到下一個(gè)頁(yè)面。我想測(cè)試一下,當(dāng)按鈕被點(diǎn)擊時(shí),是否會(huì)向路由器發(fā)送一個(gè)事件/消息,并檢查目標(biāo)路由是否正確。

應(yīng)用程序的結(jié)構(gòu)如下:

App.Vue - 入口組件

<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 - Vue Router配置文件

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 - App組件中RouterView的入口視圖

<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>

考慮到它使用CompositionAPI和TypeScript,有沒有辦法在Vitest測(cè)試中模擬路由器?

這是一個(gè)測(cè)試文件結(jié)構(gòu)的示例(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 });
    });
});

我嘗試了多種方法:vi.mock('vue-router'),vi.spyOn(useRoute,'push'),vue-router-mock庫(kù),但是我無法讓測(cè)試運(yùn)行起來,似乎路由器就是不可用的。

更新(15/04/23)

根據(jù) @tao 的建議,我意識(shí)到在HomeView中測(cè)試點(diǎn)擊事件并不是一個(gè)很好的測(cè)試(測(cè)試的是庫(kù)而不是我的應(yīng)用程序),所以我添加了一個(gè)測(cè)試 ButtonRouterLink,看看它是否正確渲染了Vue RouterLink,使用to參數(shù):

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();
    });
});

它渲染了一個(gè)空的HTML字符串""

exports[`ButtonRouterLink > correctly transforms 'to' param into a router-link prop 1`] = `""`;

伴隨著一個(gè)不太有用的Vue警告(未指定預(yù)期類型):

[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粉478188786
P粉478188786

全部回復(fù)(1)
P粉759451255

這是可能的。

你的示例和官方示例之間有一個(gè)重要的區(qū)別:在被測(cè)試的組件中,你將其放置在了一個(gè)中間組件中,而不是使用RouterLink(或使用router.push的按鈕)。

這會(huì)如何改變單元測(cè)試?

第一個(gè)問題是你使用了shallowMount,它會(huì)用空容器替換子組件。在你的情況下,這意味著ButtonRouterLink不再包含RouterLink,并且不會(huì)對(duì)點(diǎn)擊事件做任何操作,它只是接收點(diǎn)擊事件。

解決這個(gè)問題的選項(xiàng)有:

  • a) 使用mount而不是shallowMount,將其變成集成測(cè)試而不是單元測(cè)試
  • b) 將這個(gè)功能的測(cè)試移動(dòng)到ButtonRouterLink的測(cè)試中。一旦測(cè)試了ButtonRouterLink的任何:to是否正確轉(zhuǎn)換為{ name: to }并傳遞給RouterLink,你只需要測(cè)試這些:to是否正確傳遞給使用它們的任何組件中的<ButtonRouterLink />。

將這個(gè)功能移動(dòng)到自己的組件中所創(chuàng)建的第二個(gè)問題稍微微妙一些。通常,我期望以下ButtonRouterLink的測(cè)試可以工作:

import { RouterLinkStub } from '@vue/test-utils'

const wrapper = shallowMount(YourComp, {
  stubs: {
    RouterLink: RouterLinkStub
  }
})

expect(wrapper.findComponent(RouterLinkStub).props('to')).toEqual({
  name: RouterNames.GAME
})

令我驚訝的是,這個(gè)測(cè)試失敗了,它聲稱在RouterLinkStub中接收到的:to屬性值不是{ name: RouterNames.GAME },而是'game',這是我傳遞給ButtonRouterLink的值。就像我們的組件從未將value轉(zhuǎn)換為{ name: value }一樣。

相當(dāng)奇怪。
事實(shí)證明,問題是<RouterLink />恰好是我們組件的根元素。這意味著組件(<BottomRouterLink>)在DOM中被<RouterLinkStub>替換,但:to的值是從前者而不是后者讀取的。簡(jiǎn)而言之,如果模板是這樣的,測(cè)試就會(huì)成功:

  <span>
    <RouterLink ... />
  </span>

為了解決這個(gè)問題,我們需要導(dǎo)入實(shí)際的RouterLink組件(來自vue-router),并找到,而不是找到RouterLinkStub。為什么?@vue/test-utils足夠聰明,可以找到存根組件而不是實(shí)際組件,但是這樣,.findComponent()只會(huì)匹配替換后的元素,而不是在它仍然是ButtonRouterLink(未處理)時(shí)。此時(shí),:to的值已經(jīng)被解析為RouterLink實(shí)際接收的值。

完整的測(cè)試如下:

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
    })
  })
})

有點(diǎn)棘手。

最新下載
更多>
網(wǎng)站特效
網(wǎng)站源碼
網(wǎng)站素材
前端模板