Vue3:在 'onMounted' 内的异步函数中测试加载状态失败
Vue3: Testing load state fails in async function inside 'onMounted'
我想测试是否显示加载占位符,同时从服务器获取的数据在 onMounted
挂钩中。这是我正在测试的组件:
<template>
<section class="container mx-auto p-4">
<div
v-if="collections && Object.keys(collections).length"
class="grid grid-cols-1 tablet:grid-cols-3 gap-4"
data-test="collectionCards"
>
<div
v-for="collection in collections"
:key="collection.cardSetId"
class="relative shadow-lg rounded-sm flex flex-col justify-between"
>
<div class="flex justify-end p-4 border-b border-b-spacer">
<p class="text-spacer uppercase text-sm">4 days ago</p>
</div>
<div class="flex flex-col justify-between h-full text-left">
<div>
<div class="card-cover"></div>
<div class="text-black font-bold relative p-4">
<h3 class="text-2xl" data-test="collectionName">{{ collection.name }}</h3>
<p class="text-sm my-2">
<span data-test="collectionLength">{{ collection.length }}</span> item(s)</p>
</div>
<div class="p-4">
<base-collapse data-test="collectionDescription">{{ collection.description }}</base-collapse>
</div>
</div>
<div class="flex justify-start p-4">
<p class="text-sm">Author: <span class="font-bold">Kanstantsin Lazouski</span></p>
</div>
</div>
</div>
</div>
<div v-else-if="isLoading" data-test="loadingCollections">Loading...</div>
<div v-else class="h-screen flex" data-test="emptyCollectionWrapper">
<EmptyCollection />
</div>
</section>
</template>
/*....*/
onMounted(async () => {
isLoading.value = true;
const collectionList = await getCollectionList(userId.value as string);
try {
collections.value = collectionList;
} catch(err) {
/* TODO: add more appropriate error handling */
console.error(err);
} finally {
isLoading.value = false;
}
})
但是我尝试的一切都不成功。据我了解,我们应该首先挂载组件然后调用 flushPromises
以使 Vue 等待直到 onMounted
中的承诺被解决。因此,在调用 mount
和 flushPromises
之间应该有一个时间跨度,当 isLoading
设置为 true 时。问题是,当我们在测试中记录 'isLoading' 时,它会显示 true
(这是正确的),但实际的 HTML 与它应该是的不同(我收到EmptyCollection
在 v-else
内)。这是我的测试,但它不起作用:
it('renders "EmptyCollection" if "collectionList" is empty and "Loading..." while data is fetching', async () => {
(getCollectionList as jest.Mock).mockResolvedValueOnce({});
const wrapper = mount(MyCollections, wrapperOptions);
expect(wrapper.find('[data-test="loadingCollections"]').exists()).toBe(true); // received: false
await flushPromises();
expect(wrapper.find('[data-test="collectionCards"]').exists()).toBe(false);
expect(wrapper.find('[data-test="emptyCollectionWrapper"]').exists()).toBe(true);
});
提前致谢。
const wrapper = mount(MyCollections, wrapperOptions);
await wrapper.vm.$nextTick();
expect(wrapper.find('[data-test="loadingCollections"]').exists()).toBe(true);
await flushPromises();
expect(wrapper.find('[data-test="loadingCollections"]').exists()).toBe(false);
您好!您需要等到 vue 更新 html。然后你需要等到所有的承诺都完成,然后你可以再次检查。
原因是 Vue 在 ticks 中更新了 html。首先,您的组件使用默认数据安装。然后调用 onMounted
挂钩,您在其中设置 isLoading
,它会更新 下一个报价 中的 DOM。您需要等待此 DOM 更改,然后您可以在测试中检查该元素的外观。
那你得等到api通话结束。这可以通过等待 flushPromises
来完成(副作用将包括 DOM 更新的 next tick)
我想测试是否显示加载占位符,同时从服务器获取的数据在 onMounted
挂钩中。这是我正在测试的组件:
<template>
<section class="container mx-auto p-4">
<div
v-if="collections && Object.keys(collections).length"
class="grid grid-cols-1 tablet:grid-cols-3 gap-4"
data-test="collectionCards"
>
<div
v-for="collection in collections"
:key="collection.cardSetId"
class="relative shadow-lg rounded-sm flex flex-col justify-between"
>
<div class="flex justify-end p-4 border-b border-b-spacer">
<p class="text-spacer uppercase text-sm">4 days ago</p>
</div>
<div class="flex flex-col justify-between h-full text-left">
<div>
<div class="card-cover"></div>
<div class="text-black font-bold relative p-4">
<h3 class="text-2xl" data-test="collectionName">{{ collection.name }}</h3>
<p class="text-sm my-2">
<span data-test="collectionLength">{{ collection.length }}</span> item(s)</p>
</div>
<div class="p-4">
<base-collapse data-test="collectionDescription">{{ collection.description }}</base-collapse>
</div>
</div>
<div class="flex justify-start p-4">
<p class="text-sm">Author: <span class="font-bold">Kanstantsin Lazouski</span></p>
</div>
</div>
</div>
</div>
<div v-else-if="isLoading" data-test="loadingCollections">Loading...</div>
<div v-else class="h-screen flex" data-test="emptyCollectionWrapper">
<EmptyCollection />
</div>
</section>
</template>
/*....*/
onMounted(async () => {
isLoading.value = true;
const collectionList = await getCollectionList(userId.value as string);
try {
collections.value = collectionList;
} catch(err) {
/* TODO: add more appropriate error handling */
console.error(err);
} finally {
isLoading.value = false;
}
})
但是我尝试的一切都不成功。据我了解,我们应该首先挂载组件然后调用 flushPromises
以使 Vue 等待直到 onMounted
中的承诺被解决。因此,在调用 mount
和 flushPromises
之间应该有一个时间跨度,当 isLoading
设置为 true 时。问题是,当我们在测试中记录 'isLoading' 时,它会显示 true
(这是正确的),但实际的 HTML 与它应该是的不同(我收到EmptyCollection
在 v-else
内)。这是我的测试,但它不起作用:
it('renders "EmptyCollection" if "collectionList" is empty and "Loading..." while data is fetching', async () => {
(getCollectionList as jest.Mock).mockResolvedValueOnce({});
const wrapper = mount(MyCollections, wrapperOptions);
expect(wrapper.find('[data-test="loadingCollections"]').exists()).toBe(true); // received: false
await flushPromises();
expect(wrapper.find('[data-test="collectionCards"]').exists()).toBe(false);
expect(wrapper.find('[data-test="emptyCollectionWrapper"]').exists()).toBe(true);
});
提前致谢。
const wrapper = mount(MyCollections, wrapperOptions);
await wrapper.vm.$nextTick();
expect(wrapper.find('[data-test="loadingCollections"]').exists()).toBe(true);
await flushPromises();
expect(wrapper.find('[data-test="loadingCollections"]').exists()).toBe(false);
您好!您需要等到 vue 更新 html。然后你需要等到所有的承诺都完成,然后你可以再次检查。
原因是 Vue 在 ticks 中更新了 html。首先,您的组件使用默认数据安装。然后调用 onMounted
挂钩,您在其中设置 isLoading
,它会更新 下一个报价 中的 DOM。您需要等待此 DOM 更改,然后您可以在测试中检查该元素的外观。
那你得等到api通话结束。这可以通过等待 flushPromises
来完成(副作用将包括 DOM 更新的 next tick)