vue-test-utils: Triggering mouseenter event on v-tooltip does not update the wrapper

Version

1.0.0-beta.31

Reproduction link

https://github.com/begueradj/test-vuetify-tooltip

Steps to reproduce

  1. In pages/index.vue:
<template>
  <component-with-tooltip tooltipText="Some information" />
</template>

<script>
import ComponentWithTooltip from '@/components/ComponentWithTooltip.vue'
export default {
  components: { ComponentWithTooltip }
}
</script>
  1. In components/ComponentWithTooltip.vue:
<template>
  <v-container>
    <v-row>
      <v-col cols="12">
        <v-tooltip bottom>
          <template v-slot:activator="{ on }">
            <v-icon v-on="on" color="grey">
              help
            </v-icon>
          </template>
          <span>
            {{ tooltipText }}
          </span>
        </v-tooltip>
      </v-col>
    </v-row>
  </v-container>
</template>

<script>
export default {
  name: 'ComponentWithTooltip',
  props: {
    tooltipText: {
      type: String,
      default: ''
    }
  }
}
</script>
  1. In test/components/ComponentWithTooltip.vue:
it('2. User interface provides one help icon with tooltip text', async () => {
    const icons = wrapper.findAll('.v-icon')
    expect(icons.length).toBe(1) // Ok

    const helpIcon = icons.at(0)
    expect(helpIcon.text()).toEqual('help') // Ok

    helpIcon.trigger('mouseenter')
    await wrapper.vm.$nextTick()
    expect(wrapper.text()).toEqual('science') // why this fails ?
  })

What is expected?

I expect when I trigger the mouseenter event in my test, the wrapper should be updated to show a new text which is the one I defined for the prop.

What is actually happening?

WHen I trigger the mouse event, the wrapper keeps its former state, meaning its only available text is related to the help icon text.

Thank you, Billal BEGUERADJ

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Comments: 16 (8 by maintainers)

Most upvoted comments

I think I am missing something. This works for me (added id and requestAnimationFrame). Removing mousenter makes it fail, which seems correct. Is there any other problem?

<template>
  <v-container>
    <v-row>
      <v-col cols="12">
        <v-tooltip bottom>
          <template v-slot:activator="{ on }">
            <v-icon v-on="on" color="grey">
              help
            </v-icon>
          </template>
          <span id='tooltip-text'>
            {{ tooltipText }}
          </span>
        </v-tooltip>
      </v-col>
    </v-row>
  </v-container>
</template>

<script>
export default {
  name: 'ComponentWithTooltip',
  props: {
    tooltipText: {
      type: String,
      default: ''
    }
  }
}
</script>
import Vuetify from 'vuetify'
import { mount } from '@vue/test-utils'
import ComponentWithTooltip from '@/components/ComponentWithTooltip.vue'

const vuetify = new Vuetify()
let wrapper = null

beforeEach(() => {
  wrapper = mount(ComponentWithTooltip, {
    vuetify,
    propsData: {
      tooltipText: 'science'
    }
  })
})

afterEach(() => {
  wrapper.destroy()
})

describe('ComponentWithTooltip.vue:', () => {
  it('1. Mounts properly', () => {
    expect(wrapper.isVueInstance()).toBe(true) // Ok
  })

  it('2. User interface provides one help icon with tooltip text', async (done) => {
    const icons = wrapper.findAll('.v-icon')
    expect(icons.length).toBe(1) // Ok

    const helpIcon = icons.at(0)
    expect(helpIcon.text()).toEqual('help') // Ok

    helpIcon.trigger('mouseenter')
    await wrapper.vm.$nextTick()
    requestAnimationFrame(() => {
      expect(wrapper.find('#tooltip-text').text()).toEqual('science') // why this fails ?
      done()
    })
  })
})

Ok, I figured the problem out. It’s because VTooltip uses requestAnimationFrame.

I got the test to pass:

import { mount } from '@vue/test-utils'
import Comp from '../../src/TooltipComp.vue'

it('2. User interface provides one help icon with tooltip text', async () => {
  const wrapper = mount(Comp)
  const icons = wrapper.findAll('.v-icon')
  expect(icons.length).toBe(1) // Ok

  const helpIcon = icons.at(0)
  expect(helpIcon.text()).toEqual('help') // Ok

  helpIcon.trigger('mouseenter')
  await wrapper.vm.$nextTick()
  requestAnimationFrame(() => {
    expect(wrapper.text()).toEqual('science') // why this fails ?
  })
})

Try that.

I don’t think is something we can easily fix in VTU.

No problem, glad you got it working

That’s not the case when I run it:

● ComponentWithTooltip.vue: › 2. User interface provides one help icon with tooltip text

    expect(received).toEqual(expected) // deep equality

    Expected: "sddjkdkjdkje"
    Received: "science"

      34 |     await wrapper.vm.$nextTick()
      35 |     requestAnimationFrame(() => {
    > 36 |       expect(wrapper.find('#tooltip-text').text()).toEqual('sddjkdkjdkje') // why this fails ?
         |                                                    ^
      37 |       done()
      38 |     })
      39 |   })

Anything other than science fails (so it should).

Or I misunderstood something - I can push a repo with my changes if you like.

Oh, you need done so Jest waits for the update:

// added done callback to the function
it('2. User interface provides one help icon with tooltip text', async (done) => {
  // stuff
  helpIcon.trigger('mouseenter')
  await wrapper.vm.$nextTick()
  requestAnimationFrame(() => {
    // assert
    done() // <- here
  })
})

Note both help and science will still be in the markup, from the looks of things (Vuetify does not seem to remove the template from the markup, just hide it somehow. Add a selector to the span:

          <span id="custom-tooltip">
            {{ tooltipText }}
          </span>

For example.

VTooltip [uses transitions(https://github.com/vuetifyjs/vuetify/blob/master/packages/vuetify/src/components/VTooltip/VTooltip.ts).

Can you try:

mount({
  stubs: {
    transition: true,
  }
})

and see if that works?