ebbishop
ebbishop

Reputation: 1983

Testing Vue with Jest: custom event handled by parent, emitted by child component

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?

Upvotes: 4

Views: 5266

Answers (1)

tony19
tony19

Reputation: 138196

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.

Upvotes: 8

Related Questions