I am trying to write a basic unit test for a component called CompanyBioPanel. Here is a simplified version of the component:
// template
<v-card-text>
<v-tabs v-model="companyTabs">
<v-tab value="generalData">
<h2>Details</h2>
</v-tab>
<v-tab value="companyConfiguration">
<h2>Company Configuration</h2>
</v-tab>
</v-tabs>
<v-divider />
<v-window
v-if="companyData.company_id != null"
v-model="companyTabs"
>
<v-window-item value="generalData">
<v-list>
<company-data-item
v-for="item in generalData"
:key="item.label"
:label="item.label"
:value="item.value"
/>
</v-list>
</v-window-item>
<v-window-item value="companyConfiguration">
<v-list>
<company-data-item
v-for="item in companyConfiguration"
:key="item.label"
:label="item.label"
:value="item.value"
/>
</v-list>
</v-window-item>
</v-window>
</v-card-text>
// script
import type { Company } from './types'
import {
computed,
toRefs,
ref,
type ComputedRef
} from 'vue'
import CompanyDataItem from './CompanyDataItem.vue'
const props = defineProps<{ companyData: { [key: string]: string } }>()
const companyTabs = ref(null)
const { companyData } = toRefs(props)
const companyIdOrNull = computed(() => {
return companyData.value?.company_id ?? null
})
const generalData: ComputedRef<CompanyDataItemProps[]> = computed(() => {
if (companyData.value == null) {
return []
}
return [
{
label: 'Name',
value: companyData.value.name,
fieldName: 'name',
isEditable: true
}
]
})
In my test, I would like to assert that when I pass the companyData
object as a prop to my component, it renders the company-data-item
component.
Here is my test:
import { mount } from '@vue/test-utils'
import { h } from 'vue'
import { VApp } from 'vuetify/components'
import CompanyBioPanel from './CompanyBioPanel.vue'
it('renders the company bio panel', async () => {
const companyData = {
company_id: 'abc',
name: 'Test Company'
}
const wrapper = mount(VApp, { slots: { default: h(CompanyBioPanel, { props: { companyData } }) } })
expect(wrapper.exists()).toBe(true)
const html = wrapper.html()
expect(html).toContain('Test Company')
const companyName = wrapper.find('h1')
expect(companyName.text()).toBe('Test Company')
const companyDataItems = wrapper.findAllComponents({ name: 'company-data-item' })
expect(companyDataItems.length).toBe(1)
})
This is a simple test asserting that child components are generated from data passed as props. However, I get the following error when I attempt to run my test:
⎯⎯⎯ Failed Tests 1 ⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯
FAIL src/components/company-view/company-bio-panel/CompanyBioPanel.test.ts > renders the company bio panel
TypeError: Cannot read properties of undefined (reading 'company_id')
❯ src/components/company-view/company-bio-panel/CompanyBioPanel.vue:45:27
43| <v-divider />
44| <v-window
45| v-if="companyData.company_id != null"
| ^
46| v-model="companyTabs"
47| >
This doesn’t make sense to me, because I am passing the props in my test, so how could companyData
be undefined
?
I’ve also tried modifying the way I pass props to be like this:
const wrapper = mount(VApp, { slots: { default: h(CompanyBioPanel, { companyData }) } })
but that leads to an even stranger error:
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Unhandled Errors ⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯
Vitest caught 1 unhandled error during the test run.
This might cause false positive tests. Resolve unhandled errors to make sure your tests are not affected.
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Unhandled Rejection ⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯
TypeError: Cannot create property '_destroyed' on number '-1'
❯ clearImmediate node:timers:325:24
❯ GlobalWindow.cancelAnimationFrame ../../node_modules/happy-dom/src/window/Window.ts:921:10
❯ node_modules/vuetify/lib/components/VSlideGroup/VSlideGroup.mjs:104:9
❯ callWithErrorHandling ../../node_modules/@vue/runtime-core/dist/runtime-core.cjs.js:156:18
❯ callWithAsyncErrorHandling ../../node_modules/@vue/runtime-core/dist/runtime-core.cjs.js:164:17
❯ job ../../node_modules/@vue/runtime-core/dist/runtime-core.cjs.js:1831:9
❯ flushPreFlushCbs ../../node_modules/@vue/runtime-core/dist/runtime-core.cjs.js:308:7
❯ updateComponentPreRender ../../node_modules/@vue/runtime-core/dist/runtime-core.cjs.js:5876:5
❯ ReactiveEffect.componentUpdateFn [as fn] ../../node_modules/@vue/runtime-core/dist/runtime-core.cjs.js:5794:11
❯ ReactiveEffect.run ../../node_modules/@vue/reactivity/dist/reactivity.cjs.js:182:19