Mar*_*gar 5 unit-testing vue.js
项目: https: //github.com/marioedgar/webpack-unit-test
我有一个使用 vue CLI 生成的 Vue.js 应用程序。我只稍微编辑了 HelloWorld 组件以从我的测试服务中获取一些异步数据,您可以在这里看到:
<template>
<h1>{{ message }}</h1>
</template>
<script>
import service from './test.service'
export default {
name: 'HelloWorld',
created () {
service.getMessage().then(message => {
this.message = message
})
},
data () {
return {
message: 'A'
}
}
}
</script>
<style scoped>
</style>Run Code Online (Sandbox Code Playgroud)
测试服务位于同一目录中,非常简单:
class Service {
getMessage () {
return new Promise((resolve, reject) => {
console.log('hello from test service')
resolve('B')
})
}
}
const service = new Service()
export default serviceRun Code Online (Sandbox Code Playgroud)
因此,为了模拟此服务,我使用 webpack vue-loader 来注入模拟服务,如官方文档中所述:
https://vue-loader.vuejs.org/en/workflow/testing-with-mocks.html
这是我的测试,与示例几乎相同:
import Vue from 'vue'
const HelloInjector = require('!!vue-loader?inject!../../../src/components/HelloWorld')
const Hello = HelloInjector({
// mock it
'./test.service': {
getMessage () {
return new Promise((resolve, reject) => {
resolve('C')
})
}
}
})
describe('HelloWorld.vue', () => {
it('should render', () => {
const vm = new Vue({
template: '<div><test></test></div>',
components: {
'test': Hello
}
}).$mount()
expect(vm.$el.querySelector('h1').textContent).to.equal('C')
})
})Run Code Online (Sandbox Code Playgroud)
我面临两个问题:
it('should render', (done) => {
const vm = new Vue({
template: '<div><test></test></div>',
components: {
'test': Hello
}
}).$mount()
Vue.nextTick(() => {
expect(vm.$el.querySelector('h1').textContent).to.equal('C')
done()
})
})Run Code Online (Sandbox Code Playgroud)
然而,除非我嵌套 3 个 nextTicks,否则这不起作用,这对我来说似乎非常老套。为了让它发挥作用,我缺少什么吗?这个例子看起来非常简单,但是如果没有大量的 nextTicks 我就无法让这个测试通过
[vue warn] 组件挂载失败:模板或渲染函数未定义
同样,这种情况只是有时发生。我可以运行完全相同的单元测试而不进行任何更改,并且它会在 50% 的时间内向我显示此消息。
我真的不明白为什么有时组件无法安装。我什至不确定它与注射器有关,但无论如何,我通过不使用它来保持测试的一致性;尝试不同的方法。
如果通过注入服务props而不是直接使用服务,则该组件可能更具可测试性。
<template>
<div>
<h1>{{ message }}</h1>
</div>
</template>
<script>
import service from './test.service'
export default {
name: 'HelloWorld',
created () {
this.service.getMessage().then(message => {
this.message = message
})
},
data () {
return {
message: 'A'
}
},
props: {
service: {
default: service
}
}
}
</script>
<style scoped>
</style>
Run Code Online (Sandbox Code Playgroud)
这使得注入器变得不必要,因为可以将模拟服务传递给propsData构造函数中使用的组件。
import Vue from 'vue'
import Async from '@/components/Async'
const service = {
getMessage () {
return new Promise((resolve, reject) => {
resolve('C')
})
}
}
describe('Async.vue', () => {
let vm
before(() => {
const Constructor = Vue.extend(Async)
vm = new Constructor({
propsData: {
service: service
}
}).$mount()
})
it('should render', function () {
// Wrapping the tick inside a promise, bypassing PhantomJS's lack of support
return (new Promise(resolve => Vue.nextTick(() => resolve()))).then(() => {
expect(vm.$el.querySelector('h1').textContent).to.equal('C')
})
})
})
Run Code Online (Sandbox Code Playgroud)