I'm writing unit tests for the following component:
<template>
<sub-component
@foo="bar"
/>
</template>
<script>
import SubComponent from './SubComponent';
export default {
name: 'MyComponent',
components: { SubComponent },
methods: {
bar(payload) {
this.$emit('baz', ...payload);
}
}
}
</script>
And the test would be:
import { shallowMount } from '@vue/test-utils';
import _ from 'lodash';
import MyComponent from '../../components/MyComponent';
describe('MyComponent.vue', () => {
let wrapper;
beforeEach(() => {
wrapper = shallowMount(MyComponent);
});
it('should emit baz on subcomponent foo', () => {
const subComp = wrapper.find('sub-component-stub');
expect(subComp.exists()).toBe(true); // passes
subComp.vm.$emit('foo');
return wrapper.vm.$nextTick().then(() => {
expect(wrapper.emitted().baz).toBeTruthy(); // does not pass;
// upon logging:
console.log(_.isEqual(wrapper, subComp)); // => true
})
})
})
The example is oversimplified, but the principle here is I want a reusable <sub-component>
(a modal) and various functional wrappers around it (related to one particular task the modal type performs) which map additional functionality. I don't want the functionality in the parent components, as it would violate DRY - i'd have to place it in each component containing a particular type of modal.
This would work fine if <sub-component>
was not the direct child of <template>
. Somehow, it appears wrapper
and subComp
are hosted on the same element.
How should this be tested properly?
Another possibility it's to find your element in the dom and check the emitted value of your root component.
import { shallowMount } from '@vue/test-utils'
import MyComponent from './MyComponent.vue'
import SubComponent from './SubComponent.vue'
describe('MyComponent', () => {
it('should emit baz on subcomponent foo', () => {
const wrapper = shallowMount(MyComponent)
const subComponent = wrapper.find(SubComponent)
expect(subComponent.exists()).toBe(true)
expect(wrapper.emitted('baz')).toBeUndefined()
subComponent.vm.$emit('foo', ['hello'])
expect(wrapper.emitted('baz')[0]).toEqual(['hello'])
// or expect(wrapper).toEmit('baz', 'hello') cf. below for toEmit
})
})
If you want a custom matcher for Jest:
toEmit(received, eventName, data) {
if (data) {
expect(received.emitted()[eventName][0]).toEqual([data])
} else {
expect(received.emitted()[eventName][0]).toEqual([])
}
return { pass: true }
}