Vue-test-utils: Events emitted on mount not captured

Created on 29 Nov 2017  路  7Comments  路  Source: vuejs/vue-test-utils

Events emitted immediately in the mounted hook are not captured by wrapper.emitted(). With something like the below

  • event something is not captured
  • event something-else is not captured on first emit in the immediate watcher, but is captured on subsequent watcher callbacks
  • event toggle is captured if the toggle method is called after mount, e.g. on user click
{
  mounted() {
    this.$emit('something');

    this.$watch('foo', (v) => {
      this.$emit('something-else');
    }, { 
      immediate: true 
    });

  },
  methods: {
    toggle() {
      this.$emit('toggle');
    }
  }
}
bug

Most helpful comment

Ok, so what worked for me was this (using the logEvents method in src/lib/log-events.js):

localVue.mixin({
  beforeCreate: function() {
    this.$_emitted = {}
    this.$_emittedByOrder = []
    logEvents(this, this.$_emitted, this.$_emittedByOrder)
  }
})

It does catch all events from beforeCreate on in a variable of the component (in this case $._emitted). In the constructor we could then copy these self-tracked events to the wrapper. The mixin could be added in every localVue instance when creating it.

This approach is quite naive and the installed listener should be removed after the wrapper is created. It also seems a bit hacky and not too clean to use a field on the component.

Those are just my ideas. I would be interested if you know a better way to add the listener.

All 7 comments

This happens, because the wrapper attaches to the component after the component was created and mounted.

I do not know if there is a way to change this, but I have the feeling if we do not attach the wrapper earlier there might be more edge cases where the wrapper is not ready when the component gets created.

One possibility I see is to install the wrapper earlier is via beforeCreate-mixin. It would be called by the Vue-framework after the vm-object is instiated but before the Vue-component is created and mounted, and so we could do the setup then already. We might have to split the actions done in vue-wrapper.js in several hooks.

But maybe there are other ways as well.

I was thinking we could add a listener object before mount and pass it to VueWrapper when it's created and merge that listener object with the current listener object.

Ok, so what worked for me was this (using the logEvents method in src/lib/log-events.js):

localVue.mixin({
  beforeCreate: function() {
    this.$_emitted = {}
    this.$_emittedByOrder = []
    logEvents(this, this.$_emitted, this.$_emittedByOrder)
  }
})

It does catch all events from beforeCreate on in a variable of the component (in this case $._emitted). In the constructor we could then copy these self-tracked events to the wrapper. The mixin could be added in every localVue instance when creating it.

This approach is quite naive and the installed listener should be removed after the wrapper is created. It also seems a bit hacky and not too clean to use a field on the component.

Those are just my ideas. I would be interested if you know a better way to add the listener.

I can't think of a better way. Would you like to implement @wtho ?

@eddyerburgh I will submit a PR this weekend

Fixed in 1.0.0-beta.7, thanks @wtho!

I'm having similar issues when trying to test a component that has an updated method with an emit in it. Could it be that there is an issue with this as well?

component:

updated () {
    this.$emit('table-updated')
}

in my test:

console.log(wrapper.emitted('table-updated'))

result:

    console.log test/unit/specs/Table/Table.spec.js:73
      undefined

coverage documentation shows that the lines are being executed properly.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

vilarinholeo picture vilarinholeo  路  3Comments

vwxyutarooo picture vwxyutarooo  路  3Comments

jonyoder picture jonyoder  路  3Comments

eddyerburgh picture eddyerburgh  路  4Comments

benm-eras picture benm-eras  路  3Comments