我正在开发一个使用Vue loader's webpack template创建的应用。
我在创建项目时将Karma作为一个选项进行了测试,因此它已全部设置完毕并且我没有更改任何配置。
该应用程序是一个Github用户查找,目前包含三个组件; App.vue
,Stats.vue
和UserForm.vue
。统计信息和表单组件是包含应用程序组件的子项。
以下是App.vue
:
<template>
<div id="app">
<user-form
v-model="inputValue"
@go="submit"
:input-value="inputValue"
></user-form>
<stats
:username="username"
:avatar="avatar"
:fave-lang="faveLang"
:followers="followers"
></stats>
</div>
</template>
<script>
import Vue from 'vue'
import axios from 'axios'
import VueAxios from 'vue-axios'
import _ from 'lodash'
import UserForm from './components/UserForm'
import Stats from './components/Stats'
Vue.use(VueAxios, axios)
export default {
name: 'app',
components: {
UserForm,
Stats
},
data () {
return {
inputValue: '',
username: '',
avatar: '',
followers: [],
faveLang: '',
urlBase: 'https://api.github.com/users'
}
},
methods: {
submit () {
if (this.inputValue) {
const api = `${this.urlBase}/${this.inputValue}`
this.fetchUser(api)
}
},
fetchUser (api) {
Vue.axios.get(api).then((response) => {
const { data } = response
this.inputValue = ''
this.username = data.login
this.avatar = data.avatar_url
this.fetchFollowers()
this.fetchFaveLang()
}).catch(error => {
console.warn('ERROR:', error)
})
},
fetchFollowers () {
Vue.axios.get(`${this.urlBase}/${this.username}/followers`).then(followersResponse => {
this.followers = followersResponse.data.map(follower => {
return follower.login
})
})
},
fetchFaveLang () {
Vue.axios.get(`${this.urlBase}/${this.username}/repos`).then(reposResponse => {
const langs = reposResponse.data.map(repo => {
return repo.language
})
// Get most commonly occurring string from array
const faveLang = _.chain(langs).countBy().toPairs().maxBy(_.last).head().value()
if (faveLang !== 'null') {
this.faveLang = faveLang
} else {
this.faveLang = ''
}
})
}
}
}
</script>
<style lang="stylus">
body
background-color goldenrod
</style>
以下是Stats.vue
:
<template>
<div class="container">
<h1 class="username" v-if="username">{{username}}</h1>
<img v-if="avatar" :src="avatar" class="avatar">
<h2 v-if="faveLang">Favourite Language: {{faveLang}}</h2>
<h3 v-if="followers.length > 0">Followers ({{followers.length}}):</h3>
<ul v-if="followers.length > 0">
<li v-for="follower in followers">
{{follower}}
</li>
</ul>
</div>
</template>
<script>
export default {
name: 'stats',
props: [
'username',
'avatar',
'faveLang',
'followers'
]
}
</script>
<style lang="stylus" scoped>
h1
font-size 44px
.avatar
height 200px
width 200px
border-radius 10%
.container
display flex
align-items center
flex-flow column
font-family Comic Sans MS
</style>
这是UserForm.vue
:
<template>
<form @submit.prevent="handleSubmit">
<input
class="input"
:value="inputValue"
@input="updateValue($event.target.value)"
type="text"
placeholder="Enter a GitHub username..."
>
<button class="button">Go!</button>
</form>
</template>
<script>
export default {
props: ['inputValue'],
name: 'user-form',
methods: {
updateValue (value) {
this.$emit('input', value)
},
handleSubmit () {
this.$emit('go')
}
}
}
</script>
<style lang="stylus" scoped>
input
width 320px
input,
button
font-size 25px
form
display flex
justify-content center
</style>
我为UserForm.vue
编写了一个简单的测试,测试<button>
的外部HTML:
import Vue from 'vue'
import UserForm from 'src/components/UserForm'
describe('UserForm.vue', () => {
it('should have a data-attribute in the button outerHTML', () => {
const vm = new Vue({
el: document.createElement('div'),
render: (h) => h(UserForm)
})
expect(vm.$el.querySelector('.button').outerHTML)
.to.include('data-v')
})
})
这很好用;运行npm run unit
时的输出是:
UserForm.vue
✓ should have a data-attribute in the button outerHTML
但是,当我尝试根据the documentation为Stats.vue
编写类似的简单测试时,我遇到了问题。
以下是测试:
import Vue from 'vue'
import Stats from 'src/components/Stats'
// Inspect the generated HTML after a state update
it('updates the rendered message when vm.message updates', done => {
const vm = new Vue(Stats).$mount()
vm.username = 'foo'
// wait a "tick" after state change before asserting DOM updates
Vue.nextTick(() => {
expect(vm.$el.querySelector('.username').textContent).toBe('foo')
done()
})
})
以下是运行npm run unit
时的相应错误:
ERROR LOG: '[Vue warn]: Error when rendering root instance: '
✗ updates the rendered message when vm.message updates
undefined is not an object (evaluating '_vm.followers.length')
我尝试了以下尝试以使测试正常运行:
vm
测试中Stats
创建的方式与UserForm
测试相同 - 返回相同的错误textContent
- 返回相同的错误为什么错误是指_vm.followers.length
?前面有下划线的_vm
是什么?如何解决此问题才能成功测试我的组件?
(包含所有代码的回复:https://github.com/alanbuchanan/vue-github-lookup-2)
答案 0 :(得分:1)
为什么错误是指
_vm.followers.length
?前面有下划线的_vm
是什么?
这段代码来自Vue将您的模板编译成的渲染功能。 _vm
是一个占位符,当vue-loader在构建期间将模板转换为渲染函数时,它会自动插入到所有Javascript表达式中 - 它可以提供对组件的访问。
在模板中执行此操作时:
{{followers.length}}
这段代码的render函数中的编译结果将是:
_vm.followers.length
现在,为什么错误发生在第一位?因为您已在组件上定义了道具followers
,但没有为其提供任何数据 - 因此,道具的值为undefined
解决方案:要么为prop提供默认值:
// Stats.vue
props: {
followers: { default: () => [] }, // function required to return fresh object
// ... other props
}
或者你为道具提供了实际值:
// in the test:
const vm = new Vue({
...Stats,
propsData: {
followers: [/* ... actual data*/]
}
}).$mount()