使用Jest运行测试时,为什么Trix编辑器无法安装在Vue组件中?

时间:2019-04-29 16:16:11

标签: unit-testing vue.js vuejs2 jestjs vue-component

我构建了一个包装Trix编辑器的简单Vue组件。我正在尝试为此编写测试,但是Trix似乎无法正确安装,并且没有像在浏览器中那样生成工具栏元素。我正在使用Jest测试运行程序。

TrixEdit.vue

<template>
  <div ref="trix">
    <trix-editor></trix-editor>
  </div>
</template>

<script>
import 'trix'

export default {
  mounted() {
    let el = this.$refs.trix.getElementsByTagName('trix-editor')[0]
    // HACK: change the URL field in the link dialog to allow non-urls
    let toolbar = this.$refs.trix.getElementsByTagName('trix-toolbar')[0]
    toolbar.querySelector('[type=url]').type = 'text'

    // insert content
    el.editor.insertHTML(this.value)

    el.addEventListener('trix-change', e => {
      this.$emit('input', e.target.innerHTML)
    })
  }
}
</script>

TrixEdit.spec.js

import { mount, shallowMount, createLocalVue } from '@vue/test-utils'
import TrixEdit from '@/components/TrixEdit.vue'

const localVue = createLocalVue()
localVue.config.ignoredElements = ['trix-editor']

describe('TrixEdit', () => {
  describe('value prop', () => {
    it('renders text when value is set', () => {
      const wrapper = mount(TrixEdit, {
        localVue,
        propsData: {
          value: 'This is a test'
        }
      })

      expect(wrapper.emitted().input).toEqual('This is a test')
    })
  })
})

expect()失败,并出现以下错误

    Expected value to equal:
      "This is a test"
    Received:
      undefined

    at Object.toEqual (tests/unit/TrixEdit.spec.js:19:39)

为什么Trix没有在我的测试中初始化?

2 个答案:

答案 0 :(得分:2)

trix-editor之所以未安装,主要是因为JSDOM 11不支持MutationObserver,并且未使用attachToDocument。下文描述的测试中还有其他几个错误。

GitHub demo w/issues fixed


缺少MutationObserverwindow.getSelection

Vue CLI 3.7.0使用JSDOM 11,它不支持MutationObserver,这是“自定义元素” polyfill触发connectedCallback所必需的。该生命周期挂钩通常会调用trix-editor的初始化,这将创建您的测试试图查询的trix-toolbar元素。

解决方案1:在您的测试中,先导入mutationobserver-shim TrixEdit.vue和存根window.getSelection(由{{1 }},并且目前不受JSDOM支持):

trix

解决方案2:在由setupTestFrameworkScriptFile配置的Jest设置脚本中执行上述操作:

  1. 将以下属性添加到import 'mutationobserver-shim' // <-- order important import TrixEdit from '@/components/TrixEdit.vue' window.getSelection = () => ({}) (或package.json中的jest.config.js)中的配置对象中:
jest
  1. 将以下代码添加到setupTestFrameworkScriptFile: '<rootDir>/jest-setup.js',
<rootDir>/jest-setup.js

缺少import 'mutationobserver-shim' window.getSelection = () => ({})

attachToDocument默认情况下不会将元素附加到文档,因此@vue/test-utils不会捕获trix-editor,这是初始化文件所必需的。

解决方案::安装connectedCallback时使用attachToDocument option

TrixEdit

过早引用const wrapper = mount(TrixEdit, { //... attachToDocument: true, // <-- needed for trix-editor }) 的编辑器

trix-editor错误地假设TrixEdit在挂载时立即初始化,但是直到启动trix-editor事件后才能保证初始化,因此访问trix-initialize的内部编辑器可能会导致trix-editor引用。

解决方案::为undefined事件添加一个event handler,该事件调用先前在trix-initialize中的初始化代码:

mounted()

在更改侦听器之前设置的值

初始化代码会在值已设置之后添加一个<template> <trix-editor @trix-initialize="onInit" /> </template> <script> export default { methods: { onInit(e) { /* initialization code */ } } } </script> 事件监听器 ,但缺少事件触发器。我以为还可以检测到第一个初始值设置,以便将其重新发送为trix-change事件。

解决方案1:首先添加事件监听器:

input

解决方案2:在模板中使用<script> export default { methods: { onInit(e) { //... el.addEventListener('trix-change', /*...*/) /* set editor value */ } } } </script> (或v-on:trix-change="..."),这将消除上面的设置顺序问题:

@trix-change

值设置导致错误

初始化代码使用以下代码设置编辑器的值,这会导致测试错误:

<template>
  <trix-editor @trix-change="onChange" />
</template>

<script>
export default {
  methods: {
    onChange(e) {
      this.$emit('input', e.target.innerHTML)
    },
    onInit(e) {
      //...
      /* set editor value */
    }
  }
}
</script>

解决方案::使用el.editor.insertHTML(this.value) // causes `document.createRange is not a function` 的{​​{1}}访问器,它执行等效的操作,同时避免了此错误:

trix-editor

答案 1 :(得分:1)

我可以确认问题出在trix lib中包含的不太理想的聚合物polyfill中。我做了一个实验来强制应用polyfill,然后即使在chrome浏览器环境中也可以重现相同的错误TypeError: Cannot read property 'querySelector' of undefined

进一步的调查将其缩小到MutationObserver的行为差异,但仍未深入探究。

繁殖方式:

TrixEdit.vue

<template>
  <div ref="trix">
    <trix-editor></trix-editor>
  </div>
</template>

<script>

// force apply polymer polyfill
delete window.customElements;
document.registerElement = undefined;

import "trix";

//...

</script>