运行单元测试时,在onMounted中未定义Vue Pinia函数



我有一个组件和一个Pinia存储,其中包含一个状态和一些操作。该代码在浏览器和E2E(柏树(测试中运行良好,但在单元测试中失败。我正在使用vue测试utils和vitest。

当点击按钮时,可以从单元测试中调用存储函数,但如果该函数在已安装的或主脚本中,则它无法通过测试

src/components/UsersComponent.vue

<script setup>
import { onMounted } from 'vue'
import { useUsersStore } from '@/stores/users.store'
const usersStore = useUsersStore()
// usersStore.resetStatus() // <- This fails in the unit test
onMounted(() => {
usersStore.resetStatus() // <- This fails in the unit test
})
function changeStatus() {
usersStore.changeStatus() // <- This passes in the unit test
}
</script>
<template>
<div>
<p>Status: {{ usersStore.status }}</p>
<button @click="changeStatus()">Change Status</button>
</div>
</template>

src/stores/users.store.js

import { defineStore } from 'pinia'
import { usersAPI } from '@/gateways'
export const useUsersStore  = defineStore({
id: 'users',
persist: true,
state: () => ({
status: 'ready',
}),
getters: {},
actions: {
resetStatus() {
this.status = 'ready'
},
changeStatus() {
this.status = 'loading'
},
},
})

src/components/测试/UsersComponent.spec.js

import { describe, it, expect, vi, beforeEach } from 'vitest'
import { mount } from '@vue/test-utils'
import { createTestingPinia } from '@pinia/testing'
import UsersComponent from '@/components/UsersComponent.vue'
import { useUsersStore } from '@/stores/users.store'
const wrapper = mount(UsersComponent, {
global: {
plugins: [createTestingPinia({ createSpy: vi.fn() })],
},
})
const usersStore = useUsersStore()
describe('UsersComponent', () => {
it('store function is called', async () => {
// arrange
const spy = vi.spyOn(usersStore, 'resetStatus')
const button = wrapper.find('button')
// act
await button.trigger('click')
// assert
expect(spy).toHaveBeenCalled()
})
})

单元测试返回2个不同的错误。第一个是函数尝试在onMounted()中运行时的控制台日志,第二个是vitest返回的内容。

stderr | unknown test
[Vue warn]: Unhandled error during execution of mounted hook 
at <UsersComponent ref="VTU_COMPONENT" >
at <VTUROOT>
FAIL  src/components/__tests__/UsersComponent.spec.js [ src/components/__tests__/UsersComponent.spec.js ]
TypeError: usersStore.resetStatus is not a function
❯ src/components/UsersComponent.vue:16:14
16|
17| <template>
18|   <div>
|  ^
19|     <p>Status: {{ usersStore.status }}</p>
20|     <button @click="changeStatus()">Change Status</button>

我知道这个例子有点基础,并没有真正的用途,但我想知道如何在onMounted()(或类似的地方(中存储函数,而不会破坏我所有的单元测试。

也许这对你有用:

describe('UsersComponent',  () => {
it('changeStatus function is called', async () => {
const wrapper = mount(UsersComponent, {
mounted: vi.fn(), // With this you mock the onMounted
global: {
plugins: [createTestingPinia({
initialState: { // Initialize the state
users: { status: 'ready' }, 
}
})]
}
})  

// Spy the method you call...
const spy = vi.spyOn(wrapper.vm, 'changeStatus');
wrapper.vm.changeStatus()
expect(spy).toHaveBeenCalled()
expect(spy).toHaveBeenCalledTimes(1)
})
})

我使用vitest、pinia和测试库(基于vue测试utils(。IMHO,没有必要:

  • 模拟onMounted:您的目标不是检查onMounted是否被调用=>这是Vue内部测试

  • 要使用vi.spyOn,默认情况下,pinia会模拟所有方法。你可以在测试中直接这样做:

    const usersStore=useUsersStore((;

    expect(usersStore.resetStatus(.toHaveBeenColledTimes(1(;

我对所有从存储调用http调用的onBeforeMount、onMounted都这样做

onMounted(async() => {
await Promise.all([
valuesStore.getAllValues(),
serviceRequestStore.getServiceRequest(),
]);
});

在测试

it('gets the service request from the serviceRequest store', () => {
renderTheComponent();
const serviceRequestStore = useServiceRequestStore();
expect(serviceRequestStore.getServiceRequest).toHaveBeenCalledTimes(1);
});

我认为这应该以同样的方式与vue测试utils一起工作。我的组件的所有挂钩都是异步的,并返回promise。

最新更新