4

I have a set of parent & child vue components. The child emits an event that the parent handles. I'd like to test that it handles the custom event correctly, but I am stuck.

Parent.vue

<template>
  <div id="app" class="container">
    <!-- phonebook -->
    <ChildComponent
      class="row mt-4"
      @customEvent="val => customEventHandler(val)"
    ></ChildComponent>
  </div>
</template>

<script>
  import ChildComponent from './components/ChildComponent.vue'

  export default {
    name: 'App',
    components: {
      ChildComponent,
    },
    data() {
      return {
        test: [1, 2, 3, 4]
      };
    },
    methods: {
      customEventHandler(id) {
        // removes item `id` from the `test` array
        this.test = this.test.filter((item) => item !== id);
      },
    }
  };
</script>

This is one thing I've tried:

Parent.spec.js

import { mount, shallowMount } from "@vue/test-utils";
import  Parent from '../../src/Parent.vue';
import  ChildComponent from '../../src/components/ChildComponent.vue';

describe('customEvent event', () => {
  beforeEach(() => {
    parent = mount(Parent, {
      data() {
        return {
          test: [1, 2, 3, 4]
        };
      },
    });
  });

  it('should trigger the customEventHandler method', async() => {
    const spy = jest.spyOn(parent.vm, 'customEventHandler');
    await parent.findComponent(ChildComponent).trigger('customEvent', 2);

    expect(spy).toHaveBeenCalled();
  })
})

The test above fails and I'm not sure why.

I've also tried the following tests:

// check what the spy has been called with 
expect(spy).toHaveBeenCalledWith(2);

// test the side-effects of the `customEventHandler` method
expect(parent.vm.test.length).toEqual(3)

These also fail - it's as though the event isn't being triggered at all (is that it?), or I'm trying to test something that isn't possible.

Is there an accepted way to test a parent component's handling of an event emitted by a child component?

1 Answer 1

8

Triggering events

trigger() only works for native DOM events. For custom events, use wrapper.vm.$emit() (and no need to await it):

// await parent.findComponent(ChildComponent).trigger('customEvent', 2);
//                                            ^^^^^^^ ❌

parent.findComponent(ChildComponent).vm.$emit('customEvent', 2);

Spying on methods

Vue 2 does not support spying on methods from the wrapper.vm instance, so the spying needs to be done on the component definition (Parent.methods) before mounting:

// const spy = jest.spyOn(parent.vm, 'customEventHandler');
//                        ^^^^^^^^^ ❌ not supported in Vue 2

const spy = jest.spyOn(Parent.methods, 'customEventHandler')
const parent = mount(Parent)

demo

Note that Vue 3 does support spying via wrapper.vm.

Sign up to request clarification or add additional context in comments.

4 Comments

@paddotk I've updated the answer with a demo that shows spying on Parent.methods in Vue 2 works. And here's a demo that shows spying on parent.vm does not work in Vue 2. Can you share a link that shows what you're talking about?
Ah yeah indeed. Quite strange, because in my Vue2 project it doesn't work (Jest says Cannot spy on a primitive value). Maybe it's because of Typescript or the way I define components: export default Vue.extend<IData, any, any>({
@paddotk Can you share a link to an example where spying on parent.vm methods works in Vue 2? How did that work for you?
It's strange, looking up jest.spyOn yields no results in the docs at all, merely in questions/issues on Github etc. Here is an example. To my knowledge, this is the way to do it and it's the way I've always done it. PS I'm using Vue Test Utils v1.0.3 in case that matters.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.