testing-library / vue-testing-library

🦎 Simple and complete Vue.js testing utilities that encourage good testing practices.
http://testing-library.com/vue
MIT License
1.09k stars 109 forks source link

Testing emit from $root #169

Closed jskogelin closed 4 years ago

jskogelin commented 4 years ago

Any recommendations on testing functionality that depends on listening to events emitted via $root.$emit? Like you would via wrapper.vm.$root.$emit for example using vue-test-utils. Haven't been able to find anything in the docs.

Thanks for a great library!

afontcu commented 4 years ago

Hi! Can you share a component/test example?

jskogelin commented 4 years ago

Sure! The created hook of the component I would like to test looks something like this:

export default {
  name: 'ComponentToTest',
  created () {
    this.$root.$on('event', () => {
      // This runs an axios request and conditionally displays a component based on the response
      this.fetchFromServerAndDisplayElement()
    })
  }
  ...
}

Template of ComponentToTest

<template>
  <component-to-display v-if="requestReturnedTrue">
    displayThis
  </component-to-display>
</template>

Then, in my test

it('should display a component on root emit', function () {
  const { getByText } = render(ComponentToTest, ...)

  // Here I somehow want to test that the component responds to the event
  // emitted via $root.$emit

  expect(getByText('displayThis')).toBeInTheDocument()
})
afontcu commented 4 years ago

Hi! Vue Testing Library offers a third parameter which gives you access to the vue instance (https://github.com/testing-library/vue-testing-library/blob/master/src/vue-testing-library.js#L51-L53):

render(Component, {}, vue => {})

maybe you can leverage it to trigger the event? let me know how it goes!

jskogelin commented 4 years ago

Been digging through the instance and haven't been able to find anything that helps me trigger the event unfortunately.

I've also attempted to mock $root by setting it to a Vue instance i have access to, but no luck.

jskogelin commented 4 years ago

Let me know if this is a feature the library needs and I'll send in a PR!

jueinin commented 4 years ago

need to get the vue instance object too! in some special environmens, I need to mock some methods on vm

lmiller1990 commented 4 years ago

Can you just wrap the component?

const Wrapper = (comp) => {
  return {
    render: (h) => h('div', h(comp))
  }
}

Now you can do mount(Wrapper) and since Wrapper is the $root, you should be able to do see the emitted events on it. Note: I have not tried this, I just made it up on the spot. It might not work at all.

I also noticed $on no longer exists in Vue 3, you might want to keep this in mind.

jskogelin commented 4 years ago

Can you just wrap the component?

Thank you! Can't believe I didn't think of this sooner. This was my solution:

it('should respond to root emit', function () {
    const Wrapper = {
      mounted () {
        this.$root.$emit('emit-to-test')
      },

      render (h) {
        return h('div', [ h(ComponentToTest) ])
      }
    }

    // ...assert stuff
})

I also noticed $on no longer exists in Vue 3, you might want to keep this in mind.

Thanks for the heads up!