2

In my Vue 3 component I have a link that uses @click.prevent to call a method that emits and event. I'm unable to figure out why my attempts to test if this method is called or event is emitted fail.

Component:

<script setup lang="ts">
const emit = defineEmits<{
  closeMinicart: any[];
}>();

const closeDialog = (ev: Event) => {
  console.log('------------- close dialog ----------------');
  emit('closeMinicart');
};
</script>
<template>
  <a
   href="#"
   @click.prevent="closeDialog($event)">
    Continue shopping
  </a>
</template>

Test:

it('should emit `closeDialog` when clicked', async () => {
 const user = userEvent.setup();
 const { emitted } = render(EmptyCart);
 const el = screen.getByText(/Continue shopping/i);
 await user.click(el);
 await waitFor(() => {
   expect(emitted()).toHaveProperty('closeMinicart');
 })
});

It fails with this message:

 FAIL  src/components/EmptyCart.test.ts > Continue shopping link > should emit `closeDialog` when clicked
AssertionError: expected { pointerover: [ [ …(1) ] ], …(11) } to have property "closeMinicart"

But the console.log inside the function is always printed out in the terminal.

I've tried using the plain vue-test-utils with mount and adding wrapper.vm.$nextTick() but that doesn't work for me either.

I tried changing the link to a button as well as removing the .prevent (putting preventDefault in the method) but they don't work either.

I also attempted to create a spy on the closeDialog method like so:

it('...', () => {
//...
const spy = vi.spyOn(wrapper.vm, 'closeDialog');
//...
expect(spy).toHaveBeenCalled();

But I kept getting errors talking about not being able to call a spy on undefined or something similar.

Edit

An even more bare-bones example. Making my component look like this:

<script setup lang="ts">
import { onMounted } from 'vue';

const emit = defineEmits<{
  (e: 'myEvent'): void;
  (e: 'foobar', value: string): void;
}>();

onMounted(() => {
  emit('foobar', 'something to talk about');
});
</script>
<template>
  <a href="#"
     @click.prevent="$emit('myEvent')">
     Continue shopping
  </a>
</template>

With this test:

it('should emit `myEvent` when clicked', async () => {
  const wrapper = mount(MyComponent);
  expect(wrapper.emitted()).toHaveProperty('foobar');
  await wrapper.find('a').trigger('click');
  expect(wrapper.emitted()).toHaveProperty('myEvent');
});

I get:

AssertionError: expected { click: [ [ …(1) ] ] } to have property "foobar"

If I console.log JSON.stringify emitted, it returns this:

{"click":[[{"isTrusted":false,"_vts":1691539798806}]]}
3
  • Did you find a solution to this? Otherwise, could you show us a little bit more of what your test looks like? Commented Sep 6, 2023 at 20:09
  • I haven't found a solution to this yet. There isn't anything else to show in the test for the second/edit example. The only things I've left out of it are the standard imports and the describe block. Commented Sep 10, 2023 at 20:19
  • Hey! could you found a solution? i'm having the exact same issue and can't find anything about it Commented Apr 12, 2024 at 1:55

1 Answer 1

0

This works for me, using Vue 3 and Vitest:

describe("handleEmit", () => {
  it("Should emit 'myEvent' with 'myPayload', on method invocation", async () => {
    const wrapper = mount(MyComponent)
    await wrapper.vm.handleEmit()
    expect(wrapper.emitted().myEvent).toBeTruthy()
    expect(wrapper.emitted().myEvent[0][0]).toEqual('myPayload')
  })
})

Hope this helps.

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

1 Comment

This looks good, but I’m no longer on that project. Hopefully this solution works for others having the same problem.

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.