Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to trigger event with Vue Test Utils on a BootstrapVue element?

This issue gives me a hard time and I can't understand how to make Vue Test Utils and BootstrapVue play nice together.

A minimal example would look like this:

MyComponent.vue

<template>
  <div>
    <b-button variant="primary" @click="play">PLAY</b-button>
  </div>
</template>

<script>
export default {
  name: 'MyComponent',
  methods: {
    play() {
      console.log("Let's play!");
    }
  }
}
</script>

In the main.js we use BootstrapVue: Vue.use(BootstrapVue).

This is how I'm trying to test that the click event has been triggered:

import { expect } from 'chai';
import sinon from 'sinon';
import Vue from 'vue';
import { shallowMount, createLocalVue } from '@vue/test-utils';
import BootstrapVue, { BButton } from 'bootstrap-vue';
import MyComponent from '@/components/MyComponent.vue';

const localVue = createLocalVue();
localVue.use(BootstrapVue);

describe('MyComponent.vue', () => {
  it('should call the method play when button is clicked', () => {
    const playSpy = sinon.spy();
    const wrapper = shallowMount(MyComponent, {
      localVue,
      methods: {
        play: playSpy,
      },
    });
    wrapper.find(BButton).trigger('click');
    expect(playSpy.called).to.equal(true);
  });
});

This gives me:

  AssertionError: expected false to equal true
  + expected - actual

  -false
  +true

I checked How to test for the existance of a bootstrap vue component in unit tests with jest?, but it doesn't apply to BButton.

When running the test I also don't see any output on the command line, where I would expect this line to be executed:

console.log("Let's play!");

What's wrong here?

like image 650
cezar Avatar asked Mar 05 '20 09:03

cezar


People also ask

How do I trigger an event at the Vue?

We can trigger events on an element with Vue. js by assigning a ref to the element we want to trigger events for. Then we can call methods on the element assigned to the ref to trigger the event.

Does VUE test utils use jest?

The plugin pulls all required dependencies (including jest), creates a jest. config. js file with sensible defaults, and generates a sample test suite. After that, all you need to do is to install Vue Test Utils.


1 Answers

The reason why the event click couldn't be triggered is the way how shallowMount works in contrast to mount.

As we know, Vue Test Utils provide two methods to mount a component, i.e. render the template and generate a DOM tree:

  • mount
  • shallowMount

The first method mount generates a complete DOM tree and traverses through all child components. Most of the time this is not necessary, so the method shallowMount is preferred - it stubs the child components just one level below the parent component.

In my case this was also the root of the problem. BootstrapVue provides components, like BButton, which can be used in your own Vue templates. That means that in the following template:

<template>
  <div>
    <b-button variant="primary" @click="play">PLAY</b-button>
  </div>
</template>

the b-button is a child component, which is stubbed when using shallowMount in the unit tests for our component. That's the reason why we can't find an element button:

const wrapper = shallowMount(MyComponent);
wrapper.find('button'); // won't work

We can find the child component like this:

wrapper.find(BButton); // BButton has to be imported from bootstrap-vue

but if we try to output the rendered element:

console.log(wrapper.find(BButton).element);

we'll get:

HTMLUnknownElement {}

The BButton as a child component hasn't been fully rendered and there is no button element in the DOM tree. But when we use mount we have this behaviour:

const wrapper = mount(MyComponent);
console.log(wrapper.find(BButton).element);

we'll get:

HTMLButtonElement { _prevClass: 'btn btn-primary' }

We see that mount has rendered the child component. When we use mount we can directly access the button element:

wrapper.find('button');

Now that we have the button we can trigger an event like click on it.

I hope this helps other beginners too. The examples are very simplified, don't forget to create localVue using createLocalVue and pass it to the mount method as illustrated in the question.

When using BootstrapVue think very carefully which mounting method you need.

like image 72
cezar Avatar answered Nov 02 '22 23:11

cezar