最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - How to trigger event with Vue Test Utils on a BootstrapVue element? - Stack Overflow

programmeradmin0浏览0评论

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?

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?

Share Improve this question edited Mar 5, 2020 at 9:30 cezar asked Mar 5, 2020 at 9:17 cezarcezar 12k6 gold badges50 silver badges90 bronze badges 7
  • To get your console.log running, you could try this: wrapper.vm.play() – lucas Commented Mar 5, 2020 at 9:31
  • @lucas Thanks, but my goal is not to get the console.log running by explicitly calling the method. I want to test that triggering the click event will call the method. – cezar Commented Mar 5, 2020 at 9:41
  • got it. But does it work? Another option is trying to change this to wrapper.find('b-button').trigger('click') instead – lucas Commented Mar 5, 2020 at 9:51
  • @lucas No, wrapper.find('b-button') won't work. Neither wrapper.find('button') will. You have to pass the component name to the find method of wrapper when using BoostrapVue. I don't how to proceed further in order to trigger an event. – cezar Commented Mar 5, 2020 at 9:54
  • 1 I'm not familiar with BootstrapVue, but I have an idea that might help you. Check how they test the buttons on their repository. It hopefully might give you some insight. github.com/bootstrap-vue/bootstrap-vue/blob/dev/src/components/… – lucas Commented Mar 5, 2020 at 9:58
 |  Show 2 more comments

2 Answers 2

Reset to default 14

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.

While still performing a shallowMount you should be able to do this:

wrapper.find(BButton).vm.$listeners.click();

发布评论

评论列表(0)

  1. 暂无评论