-
Notifications
You must be signed in to change notification settings - Fork 668
Trigger events from child vue component #150
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
This will not work, when you do What you probably want to do is instead of // child component
<template>
<button id="child" @click="$emit('custom-event')">Btn</button>
</template> // parent
<template>
<child-component @custom-event="something" />
</template> // Test
const wrapper = mount(Parent)
wrapper.find('#child').trigger('click')
// this should work (or something like this) If you post Will try and put a small demo repo together later today, since I remember stuggling a little to test parent/child events. |
Mmmh I think I Understand... My problem is that I'm trying to do TDD and what I was attempting to do is create a Parent component that needs to react to events emitted from a yet undefined Child Component. I wanted to define the behaviour of the Parent before the Child. Maybe I'm not following a good strategy to do TDD as I'm used to from PHP. Maybe if I shallow the Parent component, the Child will be stubbed and the events will be triggered? Thanks for your help! |
It looks like you are just testing if Can you post the full code of what you are trying to test? There is no point to test if a component can react to a custom event, Vue already has internal tests for that. Check out #145 , i think it's related. |
No @lmiller1990, I don't want to test if The code I put before is the full code. I mean, I don't have a real Let's try again with this snippet: ParentComponent.vue<template>
<div class="ParentComponent">
<child class="child-component" @custom="onCustom"></child>
<p v-if="customTriggered">Triggered!</p>
</div>
</template>
<script>
export default {
name: 'parent-component',
data () {
return {
customEmitted: false
}
},
methods: {
onCustom () {
this.customEmitted = true
}
}
}
</script> ParentComponent.spec.jsdescribe('ParentComponent', () => {
test("It shows 'Triggered' when Child component allows to...", () => {
const wrapper = mount(ParentComponent) // Maybe shallow ?
const childComponent = wrapper.find('.child-component')
childComponent.trigger('custom')
expect(wrapper.html()).toContain('Triggered!')
})
}) Note: I'm trying to test the output, not the implementation details. That's why I don't want to test Of course, I could be wrong in how to do TDD in Vue Components. Maybe I hope this is clearer than before. Thanks! |
Thanks for the more detailed explanation, @Aferz . Since you haven't defined child yet, you could make a temporary element to test with. Something like <template>
<button @click="$emit('custom')"><button>
</template> And test with this. Then you can do an However, even if you do that, you are still just testing Vue. If a child component exposes an event api like you said, where I think what you are trying to do at the moment is:
What you should be doing is just the last two points, which is the logic you wrote. You can be confident if a child emits an event, the parent will respond. So should your unit test should look like this: describe('ParentComponent', () => {
test("It shows 'Triggered' when customEmitted is true", () => {
const wrapper = shallow(ParentComponent)
wrapper.setData({ customEmitted: true })
expect(wrapper.html()).toContain('Triggered!')
})
// or
test("It shows 'Triggered' when onCustom is called", () => {
const wrapper = shallow(ParentComponent)
wrapper.vm.onCustom()
wrapper.vm.update() // need to call to update UI
expect(wrapper.html()).toContain('Triggered!')
})
}) Of course, eventually in your app you will have to test that when something (say a button) is clicked, something else in a parent component happens - this is an integration or e2e test though, since it involves multiple components interacting, which is out of the scope of vue-test-utils. PS: your last sentence said: "I'm just trying to figure it out and wrap my mind around testing parent-child communication.". You definitely don't need to test that, but of course Vue internally does have tests for this functionality, if you are really keen you can take a look at the Vue source. Hopefully that helps. Let me know if something isn't clear or you have more questions, we are all still learning :) |
Thank you very much for your so good explanation. You cleared my mind a bit more about this topic. Thanks! |
This topic/question is indeed very much related to #145 which I asked last week. I was also wrapping my mind around unit tests and got stuck in stuff that is already in Vue and should not be tested. Thanks to @lmiller1990 for pointing this out and for the clarification/explanation! And thanks to @Aferz for sharing WW's quote :-) |
Sorry for coming late to the party. I get that there's no need to test that the event from the child is received by the parent but what I would like to test is not that the parent calls a method, but that it calls the correct method. Maybe I have two child components and the parent is supposed to call different methods depending on which child fires the event. That should be part of a unit test, I think, because it's logic that is inherent to the parent component. |
Sorry to bring up an old issue, but I agree with @Aferz. I don't think my unit tests should be aware of potentially private functions. E.g. both of these should pass the same unit test: <child @foo="gotFoo = true" />
// Or
<child @foo="setFoo" />
{ methods: {
foo() {
this.gotFoo = true;
}
}} Also the same applies to
|
Although I understand the explanation of @lmiller1990, I agree with @felixlublasser and @samboylett. In the example above: <template>
<div class="ParentComponent">
<child class="child-component" @custom="onCustom"></child>
<p v-if="customTriggered">Triggered!</p>
</div>
</template>
<script>
export default {
name: 'parent-component',
data () {
return {
customEmitted: false
}
},
methods: {
onCustom () {
this.customEmitted = true
}
}
}
</script> This test: test("It shows 'Triggered' when customEmitted is true", () => {
const wrapper = shallow(ParentComponent)
wrapper.setData({ customEmitted: true })
expect(wrapper.html()).toContain('Triggered!')
}) doesn't mean I want to test if the Could you reconsider adding a new feature to trigger custom events? |
You can emit from a child component by accessing the instance: test("triggers correctly", () => {
const wrapper = shallow(ParentComponent)
wrapper.find(Child).vm.$emit('custom')
expect(wrapper.html()).toContain('Triggered!')
}) I don't think we should add a method to emit from a component that doesn't yet exist |
@eddyerburgh Thanks for the tip! |
There's a small code example in the common tips page, in the testing emitting events section—https://vue-test-utils.vuejs.org/guides/#common-tips. We could also add an 'emitting an event on a child component' section. Would you like to make a PR? Perhaps we could add it to the tips section, although |
I may not have time this week, but I think I can make a PR next week. |
Hi.
I would like to be able to trigger events from children components of a given parent. Check this code out:
Parent Component (Only template):
Test:
The log generated in console is the following:
As you can see, events triggered in Vue Components are not being emitted, so the parent can't catch them and act in consequence.
Is this expected? Maybe I'm doing something wrong ?
Thanks !
The text was updated successfully, but these errors were encountered: