Mocking $emit event of a child component in VueJS

Viewed 4069

I have a snackbar component which I am writing tests for. It contains a child component (A button, when clicked closes the snackbar).

This button emits a @click event which the parent listens to and runs a method to either close the snackbar or open another.

Is there a way of mocking the $emit? I can't seem to find something anywhere related to this.

import { render, fireEvent, waitFor } from '@testing-library/vue';
import Snackbar from '../Snackbar.vue';
import EventBus from '@/services/EventBus';

describe('Snackbar', () => {
    const role = 'alert';
    
    it('should close snackbar on button click', async () => {
        const type = 'success';

        const { getByRole } = render(Snackbar, {
            // with this the button is inaccessible
            stubs: ['OBButton'],
        });

        await EventBus.$emit('addSnack', {
            type,
        });

        const snackbar = getByRole('alert');

        // this is wrong...
        await fireEvent.click(button);
  
        // this expect should be appropriate.
        expect(snackbar).not.toBeInTheDocument;
    });
});

This is the template of the component:

<template>
    <div class="snackbar-wrapper elevated">
        <transition name="snack-slide" v-on:after-leave="checkForMoreSnacks">
            <div
                role="alert"
                class="snack-data"
                v-if="currentSnack != null"
            >
                <span class="snack-text">{{ currentSnack.text }}</span>
                <OBButton
                    :text="currentSnack.buttonText"
                    @click="closeCurrentSnack"
                    :type="buttonType"
                ></OBButton>
            </div>
        </transition>
    </div>
</template>

Additional Info:

  1. This component is never unmounted. Closing it means setting the currentSnack value to null which hides it.
3 Answers

Use trigger to emit an event from a child component. You could do:

import ButtonComponent from '@/components/ButtonComponent.vue';
import Snackbar from '@/components/Snackbar.vue';

it('should foo', () => {
  const wrapper = shallowMount(Snackbar);
  wrapper.find(ButtonComponent).trigger('click');
  // Your assertions here

})

EDIT: For a custom event is more tricky. I am currently mocking the event like this:

const wrapper = shallowMount(Snackbar);
const childWrapper = wrapper.find(ButtomComponent);
childWrapper.vm.$emit('custom', { foo: 'bar' })

Turns out this is quite simple:

import ButtonComponent from '@/components/ButtonComponent.vue';

const { getByRole, getByText } = render(Snackbar, {
  components: { ButtonComponent } ,
  mocks: { $t: msg => msg }
})

After which point you can use this component like such:

const button = getByRole('button');
Related