【问题标题】:How would you simulate typing via Jest and Vue-Test-Utils?您将如何通过 Jest 和 Vue-Test-Utils 模拟打字?
【发布时间】:2020-05-03 14:36:57
【问题描述】:

对于我的测试,我希望它以长度 39 的值(最大长度:40)开始,当我按下一个键(即:'a')时,长度应该是 40。但是,任何我尝试或查找似乎不允许我触发 keypress/keydown/keyup 事件。

我的组件:

<q-input
  v-model="name"
  class="my-class"
  maxlength="40"
\>

我的测试:

it('Input should change', async() => {
  let wrapper = mount(Component, { name: 'M'.repeat(39) })
  let name = wrapper.find('.my-class')
  console.log(name.vm.$options.propsData.value) // prints 39 M's as expected
  name.trigger('click') // I try clicking the input. I've also tried triggering 'focus'
  await wrapper.vm.$nextTick() // I've also tried with and without this
  // I've also tried await name.vm.$nextTick()
  name.trigger('keydown', { key: 'a' }) // According to their testing docs, this should press 'a'
  // I've also tried name.trigger('keyup', { key: 'a' })
  // and name.trigger('keypress', { key: 'a' })
  await wrapper.vm.$nextTick()
  console.log(name.vm.$options.propsData.value) // prints 39 M's without the additional 'a'
  expect(name.vm.$options.propsData.value.length).toBe(40)
})

【问题讨论】:

  • 如果 q-input 根标签不是输入标签,那么您应该尝试在输入而不是 q-input 根标签上触发点击并按下键

标签: vue.js jestjs vue-test-utils


【解决方案1】:

为什么触发keydown后值没有变化?

简而言之:您无法通过以编程方式调度 KeyboardEvent 来更改 input/texarea 的值。

字符实际上是如何进入input 的?在MDN上可以找到Keyboardevent sequence的描述(假设preventDefault没有被调用):

  • 首先触发keydown 事件。如果进一步按住该键并且该键生成一个字符键,则该事件将继续在依赖于平台实现的间隔内发出,并且KeyboardEvent.repeat 只读属性设置为 true。
  • 如果键生成的字符键会导致将字符插入可能的 &lt;input&gt;&lt;textarea&gt; 或 HTMLElement.contentEditable 设置为 true 的元素中,则 beforeinputinput 事件类型为按那个顺序开火。请注意,如果支持,其他一些实现可能会触发 keypress 事件。按住键时将重复触发事件。
  • 释放键后会触发 keyup 事件。这样就完成了整个过程。

所以,keydown 默认会导致 input 事件。但这仅适用于trusted events

大多数不受信任的事件不会触发默认操作,click 事件除外...所有其他不受信任的事件的行为就像在该事件上调用了 preventDefault() 方法一样。

基本上受信任的事件是由用户发起的,不受信任的事件是由脚本发起的。在大多数浏览器中,每个事件都有一个属性isTrusted 指示该事件是否可信。

那么如何在inputs 上测试KeyboardEvents?

嗯,这取决于您的 KeyboardEvent 处理程序中发生了什么。例如。如果您在某些情况下调用preventDefault,那么您可以检查它是否在使用间谍的测试中被调用。这是一个示例,sinon 作为间谍,chai 作为断言库。

const myEvent = new KeyboardEvent('keydown', { key: 'a' })
sinon.spy(myEvent, 'preventDefault')
await wrapper.find('input').element.dispatchEvent(myEvent)
expect(myEvent.preventDefault.calledOnce).to.equal(true)

但有时您甚至不需要KeyboardEvent 处理程序。例如。在您的问题中,您写了一个最大长度为 40 个字符的 input。实际上,您可以使用maxlength HTML 属性为input 防止输入超过40 个字符。但仅作为一个研究示例,我们可以在输入处理程序中剪切值(它不仅会控制用户键入时的长度,还会控制用户复制和粘贴字符串时的长度):

onInput (event) {
  event.target.value = event.target.value.substr(0, 40)
  ...
}

对此的测试可能如下所示:

 await wrapper.find('input').setValue('M'.repeat(41))
 expect(wrapper.find('input').element.value).to.equal('M'.repeat(40))

所以这里,我们直接更改input的值,而不是KeyboardEvent

【讨论】:

    【解决方案2】:

    我不知道dialog 是从哪里来的,但你不应该在wrapper 中搜索元素吗?

    wrapper.find('.my-class')
    

    此外,我看到的大多数示例都使用 mount 而不是 factory

    const wrapper = mount(component)
    

    这是文档中的一个示例:

    it('Magic character "a" sets quantity to 13', () => {
        const wrapper = mount(QuantityComponent)
        wrapper.trigger('keydown', {
          key: 'a'
        })
        expect(wrapper.vm.quantity).toBe(13)
      })
    })
    

    【讨论】:

    • 对不起,我在概括代码时忘记用包装器替换对话框。此外,在我的工厂方法中,我返回 mount 返回的内容,并附有一些选项。但是,是的,触发器('keydown')不会影响输入字段
    猜你喜欢
    • 2018-09-01
    • 2020-06-08
    • 2018-04-29
    • 1970-01-01
    • 2019-08-07
    • 2021-08-11
    • 2019-10-07
    • 2019-05-28
    • 2019-05-13
    相关资源
    最近更新 更多