长期使用StackOverflow的智能用户,但我第一次发布问题。多么里程碑!
我正在为大型Vue应用程序编写单元测试,我的组件之一使用了一种引用$ route的方法,以确定是否在使用查询参数/在参数中传递查询参数。调用this。$ route.query.article_id的方法效果很好,但是由于我正在测试中,因此测试无法识别出此。$ route.query
如文档中所述,我试图在使用shallowMount挂载我的localVue时模拟$ route对象,但是它不起作用,并且我继续遇到相同的错误。
这是我的组件:
<template>
<b-container fluid>
<div class="content-page-header"></div>
<b-row>
<b-col cols="3" class="outer-columns text-center" style="color:grey">
<font-awesome-icon
:icon="['fas', 'newspaper']"
class="fa-9x content-page-photo mb-3 circle-icon"
/>
<br />
<br />Get practical tips and helpful
<br />advice in clear articles written
<br />by our staff's experts.
</b-col>
<b-col cols="6" v-if="articlesExist">
<h1 class="header-text">
<b>Articles</b>
</h1>
<div v-if="!selectedArticle">
<div v-for="article in articles">
<article-card :article="article" @clicked="onClickRead" />
<br />
</div>
</div>
<div v-else>
<router-link to="articles" v-on:click.native="setSelectedArticle(null)">
<font-awesome-icon icon="chevron-circle-left" /> 
<b>Back to All Articles</b>
</router-link>
<article-header :article="selectedArticle" />
<br />
<span v-html="selectedArticle.text"></span>
</div>
</b-col>
<b-col cols="6" v-else>
<h1 class="header-text">
<b>Articles</b>
</h1>
<div class="text-center">Stay tuned for more Articles</div>
</b-col>
<b-col class="outer-columns">
<b class="text-color" style="font-size:14pt">Saved Articles</b>
<div v-for="article in userArticles">
<router-link
:to="{path:'articles', query: {article_id: article.article.id}}"
v-on:click.native="setSelectedArticle(article.article)"
>
<user-article :article="article.article" />
</router-link>
<br />
</div>
</b-col>
</b-row>
</b-container>
</template>
<script>
import ArticleCard from "./ArticleCard";
import UserArticle from "./UserArticle";
import ArticleHeader from "./ArticleHeader";
import { library } from "@fortawesome/fontawesome-svg-core";
import {
faNewspaper,
faChevronCircleLeft
} from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome";
library.add(faNewspaper, faChevronCircleLeft);
export default {
name: "Articles",
props: [],
components: {
ArticleCard,
ArticleHeader,
UserArticle,
library,
FontAwesomeIcon,
faNewspaper,
faChevronCircleLeft
},
mixins: [],
data() {
return {
selectedArticle: null
};
},
computed: {
articles() {
return this.$store.getters.articles.filter(article => article.text);
},
articlesExist() {
return Array.isArray(this.articles) && this.articles.length;
},
userArticles() {
return this.$store.getters.userArticles;
},
articleParam() {
return parseInt(this.$route.query.article_id);
}
},
methods: {
setSelectedArticle(article) {
this.selectedArticle = article;
},
onClickRead(article) {
this.selectedArticle = article;
}
},
mounted() {
if (this.articleParam) {
this.setSelectedArticle(
this.articles.filter(article => article.id === this.articleParam)[0]
);
}
}
};
</script>
<style lang="stylus" scoped>
.text-color {
color: #549DB0;
}
.header-text {
color: white;
margin-top: -50px;
margin-bottom: 20px;
}
.outer-columns {
background-color: #F2FBFD;
padding-top: 20px;
}
.nav-back {
color: #549DB0;
background-color: #F0FBFD;
padding: 5px;
}
</style>
这是我的测试:
import { shallowMount, createLocalVue } from '@vue/test-utils'
import VueRouter from 'vue-router'
import Articles from '../../../app/javascript/components/member-dashboard/Articles.vue'
const localVue = createLocalVue()
localVue.use(Vuex)
localVue.use(VueRouter)
localVue.use(BootstrapVue)
describe('Articles', () => {
let store
let getters
let state = {
articles: [
{
title: "Testing Vue Components"
},
{
title: "This One shows",
text: "<p>You can see me!</p>"
},
{
title: "Another One",
text: "<p>See me too!</p>"
}
],
userArticles: [
{article: {
title: "This One shows",
text: "<p>You can see me!</p>"
}},
{article: {
title: "Another One",
text: "<p>See me too!</p>"
}}
]
}
beforeEach(() => {
getters = {
articles: () => {
return state.articles
},
userArticles: () => {
return state.userArticles
}
}
store = new Vuex.Store({ getters })
})
it('only displays article with body text', () => {
const wrapper = shallowMount(Articles, {
store,
localVue
})
expect(wrapper.vm.articles.length).to.deep.equal(2)
})
})
正如我提到的,在浅层安装中,我尝试这样做:
const wrapper = shallowMount(Articles, {
store,
localVue,
mocks: {
$route: {
query: null
}
}
})
但是我继续收到此错误:
TypeError: Cannot read property 'query' of undefined
at VueComponent.articleParam (webpack-internal:///1:107:35)
当我从articleParam方法中删除行return parseInt(this.$route.query.article_id);
时,我的测试通过了。
如何解决对组件中this。$ route.query的调用?我的测试不是必需的,但会导致我在安装组件时测试失败。
答案 0 :(得分:2)
将import VueRouter from 'vue-router';
导入到您的联合测试文件中,并创建路由器的新对象(例如const router = new VueRouter();
)并在测试用例中使用它。
我在这里更新了代码:
import { shallowMount, createLocalVue } from '@vue/test-utils'
import VueRouter from 'vue-router'
import Articles from '../../../app/javascript/components/member-dashboard/Articles.vue'
const localVue = createLocalVue()
localVue.use(Vuex)
localVue.use(VueRouter)
localVue.use(BootstrapVue);
const router = new VueRouter();
describe('Articles', () => {
let store
let getters
let state = {
articles: [
{
title: "Testing Vue Components"
},
{
title: "This One shows",
text: "<p>You can see me!</p>"
},
{
title: "Another One",
text: "<p>See me too!</p>"
}
],
userArticles: [
{article: {
title: "This One shows",
text: "<p>You can see me!</p>"
}},
{article: {
title: "Another One",
text: "<p>See me too!</p>"
}}
]
}
beforeEach(() => {
getters = {
articles: () => {
return state.articles
},
userArticles: () => {
return state.userArticles
}
}
store = new Vuex.Store({ getters })
})
it('only displays article with body text', () => {
const wrapper = shallowMount(Articles, {
store,
router,
localVue
})
expect(wrapper.vm.articles.length).to.deep.equal(2)
})
})