Reputation: 90287
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?
Upvotes: 3
Views: 3447
Reputation: 99
When the child is the root, the selector will wrapper.find(SubComponent)
will refer to the root component,
so you should go with $children[0]
// subComponent here is the root which is actually MyComponent
const subComponent = wrapper.find(SubComponent);
// subComponent.vm.$children[0] is the actual SubComponent
subComponent.vm.$children[0].$emit('foo', ['hello'])
Upvotes: 0
Reputation: 1513
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 }
}
Upvotes: 5