Reputation: 1415
I have created the following component that wraps Vuetify VHover, VTooltip and VBtn to simplify my app.
<template>
<div>
<v-hover v-if="tooltip">
<v-tooltip
slot-scope="{ hover }"
bottom
>
<v-btn
slot="activator"
:theme="theme"
:align="align"
:justify="justify"
:disabled="disabled"
:depressed="type === 'depressed'"
:block="type === 'block'"
:flat="type === 'flat'"
:fab="type === 'fab'"
:icon="type === 'icon'"
:outline="type === 'outline'"
:raised="type === 'raised'"
:round="type === 'round'"
:color="hover ? colorHover : color"
:class="{ 'text-capitalize': label, 'text-lowercase': icon }"
:size="size"
@click="onClick()"
>
<span v-if="label">{{ label }}</span>
<v-icon v-else>{{ icon }}</v-icon>
</v-btn>
<span>{{ tooltip }}</span>
</v-tooltip>
</v-hover>
<v-hover v-else>
<v-btn
slot-scope="{ hover }"
:theme="theme"
:align="align"
:justify="justify"
:disabled="disabled"
:depressed="type === 'depressed'"
:block="type === 'block'"
:flat="type === 'flat'"
:fab="type === 'fab'"
:icon="type === 'icon'"
:outline="type === 'outline'"
:raised="type === 'raised'"
:round="type === 'round'"
:color="hover ? colorHover : color"
:class="{ 'text-capitalize': label, 'text-lowercase': icon }"
:size="size"
@click="onClick()"
>
<span v-if="label">{{ label }}</span>
<v-icon v-else>{{ icon }}</v-icon>
</v-btn>
</v-hover>
</div>
</template>
<script>
import VueTypes from 'vue-types'
export default {
name: 'v-btn-plus',
props: {
align: VueTypes.oneOf(['bottom', 'top']),
justify: VueTypes.oneOf(['left', 'right']),
color: VueTypes.string.def('primary'),
colorHover: VueTypes.string.def('secondary'),
disabled: VueTypes.bool.def(false),
icon: VueTypes.string,
label: VueTypes.string,
position: VueTypes.oneOf(['left', 'right']),
tooltip: VueTypes.string,
size: VueTypes.oneOf(['small', 'medium', 'large']).def('small'),
theme: VueTypes.oneOf(['light', 'dark']),
type: VueTypes.oneOf(['block', 'depressed', 'fab', 'flat', 'icon', 'outline', 'raised', 'round']).def('raised')
},
methods: {
onClick() {
this.$emit('click')
}
},
created: function() {
// Workaround as prop validation on multiple props is not possible
if (!this.icon && !this.label) {
console.error('[Vue warn]: Missing required prop, specify at least one of the following: "label" or "icon"')
}
}
}
</script>
<style scoped>
</style>
I want to test VHover and VTooltip and have defined the following spec file.
import { createLocalVue, mount } from '@vue/test-utils'
import Vuetify from 'vuetify'
import VBtnPlus from '@/components/common/VBtnPlus.vue'
describe('VStatsCard.vue', () => {
let localVue = null
beforeEach(() => {
localVue = createLocalVue()
localVue.use(Vuetify)
})
it('renders with default settings when only label is specified', async () => {
const label = 'Very cool'
const defaultColor = 'primary'
const defaultType = 'raised'
const defaultSize = 'small'
const wrapper = mount(VBtnPlus, {
localVue: localVue,
propsData: { label }
})
expect(wrapper.text()).toMatch(label)
expect(wrapper.html()).toContain(`${defaultType}="true"`)
expect(wrapper.html()).toContain(`size="${defaultSize}"`)
expect(wrapper.html()).toContain(`class="v-btn theme--light ${defaultColor} text-capitalize"`)
expect(wrapper.html()).not.toContain(`v-icon"`)
wrapper.find('button').trigger('mouseenter')
await wrapper.vm.$nextTick()
const btnHtml = wrapper.find('.v-btn').html()
expect(btnHtml).toContain('secondary')
expect(btnHtml).not.toContain('primary')
const tooltipId = btnHtml.match(/(data-v-.+?)(?:=)/)[1]
const tooltips = wrapper.findAll('.v-tooltip_content')
let tooltipHtml = null
for (let tooltip of tooltips) {
const html = tooltip.html()
console.log(html)
if (html.indexOf(tooltipId) > -1) {
tooltipHtml = html
break
}
}
expect(tooltipHtml).toContain('menuable_content_active')
})
})
The wrapper.find('button').trigger('mouseenter')
does not work as expected. When I look at the html code after the nextTick
it is the same as before trigger
was called. It looks like I'm missing a part of the html. I was excpecting to see the following html.
<div data-v-d3e326b8="">
<span data-v-d3e326b8="" class="v-tooltip v-tooltip--bottom">
<span>
<button data-v-d3e326b8="" type="button" class="v-btn v-btn--depressed theme--light orange text-lowercase" size="small">
<div class="v-btn__content"><i data-v-d3e326b8="" aria-hidden="true" class="v-icon mdi mdi-account theme--light"></i></div>
</button>
</span>
</span>
</div>
All I'm getting is the <button>
part.
Any suggestions how to get this to work?
Upvotes: 1
Views: 3662
Reputation: 1
https://github.com/vuejs/vue-test-utils/issues/1421
it('2. User interface provides one help icon with tooltip text', async (done) => {
// stuff
helpIcon.trigger('mouseenter')
await wrapper.vm.$nextTick()
requestAnimationFrame(() => {
// assert
done()
})
})
Upvotes: 0
Reputation: 2256
I just ran into this myself using Nuxt, Vuetify, and Jest. I followed this example for Vuetify 2.x.
Below is a very simple example of what I did with my code.
As a side note, when I tried to set the wrapper.vm.[dataField] = [value]
directly, Jest threw an error not allowing direct set
access on the object. In the example.spec.js below, calling wrapper.setData({...})
will allow you to set the data value without any issue.
example.vue:
<template lang="pug">
v-hover(
v-slot:default="{ hover }"
:value="hoverActive"
)
v-card#hoverable-card(
:elevation="hover ? 20 : 10"
)
</template>
<script>
export default {
data() {
return {
hoverActive: false
}
}
</script>
example.spec.js
import { mount, createLocalVue } from '@vue/test-utils'
import Vuetify from 'vuetify'
import example from '@/components/example.vue'
const localVue = createLocalVue()
localVue.use(Vuetify)
describe('example', () => {
const wrapper = mount(example, {
localVue
})
it('should have the correct elevation class on hover', () => {
let classes = wrapper.classes()
expect(classes).toContain('elevation-10')
expect(classes).not.toContain('elevation-20')
wrapper.setData({ hoverActive: true })
classes = wrapper.classes()
expect(classes).not.toContain('elevation-10')
expect(classes).toContain('elevation-20')
})
})
Upvotes: 1
Reputation: 138336
Explicitly triggering mouseenter
events doesn't normally have an effect, likely because browsers ignore simulated/non-trusted events. Instead, you could set v-hover
's value
to true
to force the hover state:
VBtnPlus.vue
<template>
<div>
<v-hover :value="hovering">...</v-hover>
</div>
</template>
<script>
export default {
data() {
return {
hovering: false,
}
},
//...
}
</script>
VBtnPlus.spec.js
it('...', async () => {
wrapper.vm.hovering = true;
// test for hover state here
})
Upvotes: 1