Search code examples
vue.jstestingjestjsvue-test-utilsslots

Jest / Vue test utils - Method coming from subcomponent scoped slot - [Vue warn]: Invalid handler for event "click": got undefined


I'm trying to test one of my component which calls a subcomponent (ie. b-modal).

My tested component uses scoped slots from b-modal to grab the close() method from it and attach it to another event listener. Have a look :

// My custom parent component
<template>
    <b-modal>
        <template #modal-header="{close}">
            <h2 class="card-header-title">
                Coordonnées
            </h2>
            <button class="close close-profile text-dark" @click="close">
                <i class="far fa-times" />
            </button>
        </template>
    </b-modal>
</template>

In my test, I mount my component like this :

return shallowMount(MyCustomParentComponent, {
    ...options,
    localVue,
    store,
    stubs: [
        "b-modal"
    ],
});

My test passes but Jest is throwing console.error warnings :

[Vue warn]: Invalid handler for event "click": got undefined
      
      found in
      
      ---> <Anonymous>
             <Root>
      

I guess my b-modal subcomponent is not fully mounted (stub, shallowMount) and the close() method is not injected.

What can I do ? Should I mock the close() method ? Silent the warnings ? Something else ?

Thanks for your help !


Solution

  • You could customize the stub of b-modal, rendering a modal-header slot with a mocked close():

    it('should call close() on button click', async () => {
      const close = jest.fn()
      const ok = jest.fn()
      const cancel = jest.fn()
      const wrapper = shallowMount(MyModal, {
        stubs: {
          BModal: {
            render(h) {
              return h('div', [
                                this.$scopedSlots['modal-header']?.({close}),
                                this.$scopedSlots['default']?.({ok, cancel})
                              ]
                      )
            }
          }
        }
      });
      await wrapper.find('button.close').trigger('click')
      expect(close).toHaveBeenCalled()
    })