我构建了一个包装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没有在我的测试中初始化?
答案 0 :(得分:2)
trix-editor
之所以未安装,主要是因为JSDOM 11不支持MutationObserver
,并且未使用attachToDocument
。下文描述的测试中还有其他几个错误。
MutationObserver
和window.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设置脚本中执行上述操作:
import 'mutationobserver-shim' // <-- order important
import TrixEdit from '@/components/TrixEdit.vue'
window.getSelection = () => ({})
(或package.json中的jest.config.js
)中的配置对象中:jest
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>