I am writing unit tests for a Vue.js component that displays some radiobuttons and emits an event with the radio button id whenever a button is checked:
ApplicationElement.vue:
<template> <div id="element"> <label> <input type="radio" name="Element" id="element1" v-on:change="chooseElement" /> Element1 </label> <label> <input type="radio" name="Element" id="element2" v-on:change="chooseElement" /> Element2 </label> <label> <input type="radio" name="Element" id="element3" v-on:change="chooseElement" /> Element3 </label> <label> <input type="radio" name="Element" id="element4" v-on:change="chooseElement" /> Element4 </label> </div> </template> <script> export default { methods: { chooseElement () { var chosenElement = document.querySelector('input[name="Element"]:checked').id this.$emit('passChosenElement', {category: chosenElement}) } } } </script> <style> </style>
I wrote the following test for said component:
ApplicationElement.spec.js:
import { shallowMount, createLocalVue } from '@vue/test-utils' import 'regenerator-runtime/runtime' import ApplicationElement from '@/components/ApplicationElement.vue' const localVue = createLocalVue() describe('ApplicationElement tests', () => { it('should emit event with element1 parameter on corresponding radio button choice', async() => { const wrapper = shallowMount(ApplicationElement, { localVue, attachTo: document.body, propsData: { recursionNumber: 1 } }) await wrapper.find('input[type="radio"][id="element1"]').setChecked() expect(wrapper.emitted().passChosenElement[0]).toEqual([{element: 'element1'}]) wrapper.destroy() }) })
The test fails with: “TypeError: Cannot read property ‘id’ of null” If I remove the document.querySelector line from the chooseElement method in the component and emit the right id by hand, the test succeeds.
How can I get document.querySelector to work with vue-test-utils?
Advertisement
Answer
I know, this question is already a bit older, but I finally found a solution here. You need to attach your component with attachTo
(since May 2021) to an html element. The solution looks like this:
describe('ApplicationElement tests', () => { it('should emit event with element1 parameter on corresponding radio button choice', async() => { const elem = document.createElement('div') if (document.body) { document.body.appendChild(elem) } const wrapper = shallowMount(ApplicationElement, { localVue, propsData: { recursionNumber: 1 }, attachTo: elem, }) await wrapper.find('input[type="radio"][id="element1"]').setChecked() expect(wrapper.emitted().passChosenElement[0]).toEqual([{element: 'element1'}]) wrapper.destroy() }) });
As you already did, it is important to call wrapper.destroy()
after each test. Little refactoring tip: Put wrapper.destroy()
into an afterEach
callback function. Here you can find more about attachTo.