No doubt that Suspense feature leads to a cleaner code base, but as tidy as it is, it turns to be hard to test. Specifically it is not well documented yet.
case:
Regular app generated by VUE CLI
- Tech stack: Vuex, Router, PWA, jest for unit testing
Challenge:
I made use of Suspense component as recommended as follows:
<RouterView name="default" v-slot="{ Component, route }"> <transition :name="route.meta.transition" mode="out-in" :duration="300" :key="route.path"> <Suspense > <template #default> <component :is="Component" :key="route.path"/> </template> <template #fallback> <div class="top-0 right-0 h-screen w-screen z-50 flex justify-center items-center"> <div class="animate-spin rounded-full h-32 w-32 border-t-2 border-b-2 border-yellow-700"></div> </div> </template> </Suspense> </transition> </RouterView>
I have few routes and views:
- one of them is for Login view
// here is the gotcha, if ever I removed async from setup the test runs well otherwise it always returns empty vm. async setup(){ const router = useRouter() const route = useRoute() const form = reactive(new Form({ username:'', password:'', })) }
And my test suite as follows:
test('Shows login form', async () => { let wrapper = mount(Login,{ // tried set global.stubs.transition to false renderDefaultSlot: true // tried as well to move this attr to beforeEach hook }) expect(wrapper.exists()).toBe(true) // passes await nextTick() // tried to flushPromises() console.log(wrapper.vm) // always empty object {} expect(wrapper.findAll('div')).toBeTruthy() // fails accordingly as it can't run helper methods to get the parentElement })
Does any VUE veteran here can give a hint or workaround!
All open discussions on Github shows that I am not the only one stumbled on this issue, but for now it is just a discussion.
https://github.com/vuejs/vue-test-utils-next/issues/108#issue-611802592
https://github.com/vuejs/vue-test-utils/issues/956
Advertisement
Answer
After investigation wrote a little helper quoted from Github discussion above:
import {defineComponent,h,Suspense } from 'vue' import { mount } from '@vue/test-utils' import flushPromises from 'flush-promises'; const mountSuspense = async (component, options) => { const wrapper = mount(defineComponent({ render() { return h(Suspense, null, { default: h(component), fallback: h('div', 'fallback') }) }}), ...options) await flushPromises() return wrapper } describe('App renderes', ()=>{ test('About page renders',async()=>{ const wrapper = await mountSuspense(About) await console.log(wrapper.text()) // it works }) })