如何测试 Vuetify VHover?

Posted

技术标签:

【中文标题】如何测试 Vuetify VHover?【英文标题】:How to test Vuetify VHover? 【发布时间】:2019-06-14 08:39:02 【问题描述】:

我创建了以下包含 Vuetify VHover、VTooltip 和 VBtn 的组件来简化我的应用程序。

<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>

我想测试 VHover 和 VTooltip 并定义了以下规范文件。

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')
  )
)

wrapper.find('button').trigger('mouseenter') 无法按预期工作。当我查看nextTick 之后的html 代码时,它与调用trigger 之前相同。看起来我错过了 html 的一部分。我期待看到以下 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>

我得到的只是&lt;button&gt; 部分。

有什么建议可以让它工作吗?

【问题讨论】:

出于兴趣,测试悬停组件的结果是什么,因为 Vuetify 已经对其组件进行了测试。 好问题 :-) 一是我想了解它如何与 vue-test-utils 一起工作,二是我想确保我可以自信地更改我的组件并升级 Vuetify,现在我的组件仍然有效,因为测试通过了。 在我看来,如果您使用的是像 vuetify 这样的第三方库。我会把测试留在他们手中。在重大更新之前,他们清楚地指出哪些更改是破坏性更改。如果您想创建测试,将这些时间花在您的核心应用程序上会更有用,而不是花在已经有测试的第三方库上。我真的鼓励进行测试!但有用的测试。我所说的一切都是基于个人的感受和经验。 【参考方案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()
  )
)

【讨论】:

请考虑为您的回答添加一些解释。谢谢【参考方案2】:

我自己使用 Nuxt、Vuetify 和 Jest 时遇到了这个问题。我跟着 this example 用于 Vuetify 2.x。

下面是我对代码所做的一个非常简单的示例。

附带说明,当我尝试直接设置 wrapper.vm.[dataField] = [value] 时,Jest 抛出了一个错误,不允许直接 set 访问对象。在下面的 example.spec.js 中,调用 wrapper.setData(...) 将允许您毫无问题地设置数据值。

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')
  )
)

【讨论】:

谢谢。所以你只是为了测试目的将“hoverActive”变量添加到视图中?还是因为其他原因,您已经在课堂上设置了 hoverActive? v-slot:default=" hover " 监听是否悬停在生成的元素上。我根据 Vuetify 文档创建了模板。我遇到的一个问题是我无法让 v-hover 在测试中与模拟的鼠标悬停一起工作。但是,我知道我可以更改链接数据值并验证类更改。但是,为了回答您的问题,这是我的模板的简化示例以及用于测试模板的测试。【参考方案3】:

显式触发mouseenter 事件通常不会产生影响,可能是因为browsers ignore simulated/non-trusted events。相反,您可以将v-hovervalue 设置为true 以强制悬停状态:

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
)

【讨论】:

以上是关于如何测试 Vuetify VHover?的主要内容,如果未能解决你的问题,请参考以下文章

使用 Vue.js + Vuetify 有条件地绑定类?

Vue test-utils 如何使用 vuetify 测试导航栏按钮

javascript vue数据表是vuetiful。

html 标准的vuetiful数据表。

如何测试一个 vue vuetify v-autocomplete

单元测试包含 vuetify 的 vue 组件