Riza Khan
Riza Khan

Reputation: 3158

Mocking $emit event of a child component in VueJS

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.

Upvotes: 11

Views: 10321

Answers (3)

nicoramirezdev
nicoramirezdev

Reputation: 603

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' })

Upvotes: 9

Riza Khan
Riza Khan

Reputation: 3158

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');

Upvotes: 2

P.B.UDAY
P.B.UDAY

Reputation: 483

From what I understand, you want to trigger an emit to test the snackbar. In that case you can use Vue.JS trigger functionality, which triggers an event asynchronously in the wrapper DOM.

You can find more information here : https://vue-test-utils.vuejs.org/api/wrapper/trigger.html

Also, for testing $emit, you can find more information here: https://lmiller1990.github.io/vue-testing-handbook/testing-emitted-events.html#write-a-component-and-test

Upvotes: 0

Related Questions