destroytoday.com

Testing v-on="$listeners" in Vue.js

Before Cushion, I used to keep a super scrappy Tumblr blog for solutions to all the code problems I navigated throughout the day. I called it This Solved My Problem. Even eight years later, I still seem to stumble upon just as many issues that force me to stop and troubleshoot. One of the many from yesterday involved testing v-on="$listeners" in Vue.js. If you’re unfamiliar, this is a handy way to “forward” all of the events from an element to its parent component. For example, if I have a TextInput component that enhances the input element, I can use <input v-on="$listeners">, then listen to the change event with <TextInput @change="handleChange" />.

This is really useful when you’re building a wrapper component of an HTML element and potentially need to listen to an event it emits, but I was surprised to see that Vue’s test utils don’t factor $listeners into the emitted helper method. Instead, you get an empty object and a few more wrinkles on your forehead.

After a quick google search, I found this GitHub Issues comment, which pointed out the solution. It involves adding a mock function to the listeners object of the mount/shallowMount, then simply using toHaveBeenCalled on the mock function. Altogether, it looks like this:

it("emits click event when clicked", () => {
  const handleClick = jest.fn();
  const wrapper = shallowMount(MyButton, listeners: {
    click: handleClick
  });
  wrapper.find("button").trigger("click");
  expect(handleClick).toHaveBeenCalled();
});

This solution makes sense and instantly unblocked me, but the interesting part was seeing the comments before this solution. The first person to respond explained that emitted doesn’t work the way the OP expects it to behave and that it only works on components—not HTML elements. Then, the next person indicates that the ticket can be closed.

Luckily for me, and who knows how many others, the person who took the time to provide the solution noticed that these responses didn’t give the OP any guidance to actually solve their problem. So, he took it upon himself to share his solution because he also experienced the issue. This alone has inspired me to bring back these “quick fixes”. Hopefully, one of them might unblock a dev who, like myself, would otherwise be scraping the bottom of the StackOveflow barrel for clues.