this.$route.fullPath
のようなステートメントを含むコンポーネントがあります。そのコンポーネントをテストする場合、fullPath
of $route
オブジェクトの値をどのようにモックする必要がありますか?
_vue-router
_をモックするのではなく、それを使用してコンポーネントをレンダリングし、適切に機能するルーターを取得することをお勧めします。例:
_import Vue from 'vue'
import VueRouter from 'vue-router'
import totest from 'src/components/totest'
describe('totest.vue', () => {
it('should totest renders stuff', done => {
Vue.use(VueRouter)
const router = new VueRouter({routes: [
{path: '/totest/:id', name: 'totest', component: totest},
{path: '/wherever', name: 'another_component', component: {render: h => '-'}},
]})
const vm = new Vue({
el: document.createElement('div'),
router: router,
render: h => h('router-view')
})
router.Push({name: 'totest', params: {id: 123}})
Vue.nextTick(() => {
console.log('html:', vm.$el)
expect(vm.$el.querySelector('h2').textContent).to.equal('Fred Bloggs')
done()
})
})
})
_
注意事項:
render: h => h('router-view')
です。totest
コンポーネントのみをテストしていますが、totest
で参照されている場合は他のコンポーネントが必要になる場合があります。この例では_another_component
_。nextTick
が必要です。問題の1つは、私が見つけた例のほとんどが_vue-router
_の古いバージョンを参照していることです。たとえば、 移行ドキュメント 一部の例ではrouter.go()
を使用していますが、現在は機能しません。
トップの答えに同意しません-$route
を問題なくモックできます。
一方、ベースコンストラクターにvue-routerを複数回インストールするとwillが問題になります。 $route
および$router
を読み取り専用プロパティとして追加します。これにより、将来のテストでそれらを上書きすることができなくなります。
vue-test-utils でこれを達成するには2つの方法があります。
mocksオプションでvue-routerをモックする
const $route = {
fullPath: 'full/path'
}
const wrapper = mount(ComponentWithRouter, {
mocks: {
$route
}
})
wrapper.vm.$route.fullPath // 'full/path'
CreateLocalVueを使用してVue Routerを安全にインストールすることもできます。
createLocalVueを使用したテストでのvue-routerの安全なインストール
const localVue = createLocalVue()
localVue.use(VueRouter)
const routes = [
{
path: '/',
component: Component
}
]
const router = new VueRouter({
routes
})
const wrapper = mount(ComponentWithRouter, { localVue, router })
expect(wrapper.vm.$route).to.be.an('object')
答えは私を助けてくれなかったので、私はvue-test-utils
ドキュメントを掘り下げ、自分自身が有効な答えを見つけたので、インポートする必要があります。
import { shallowMount,createLocalVue } from '@vue/test-utils';
import router from '@/router.ts';
const localVue = createLocalVue();
サンプルvue
インスタンスを作成しました。テスト中はshallowMount
を使用して、vue
アプリインスタンスとルーターを提供する必要があります。
describe('Components', () => {
it('renders a comment form', () => {
const COMMENTFORM = shallowMount(CommentForm,{
localVue,
router
});
})
})
簡単にルーターを浅いマウントに渡すことができ、エラーは発生しません。あなたが使用する店を渡したい場合:
import { shallowMount,createLocalVue } from '@vue/test-utils';
import router from '@/router.ts';
import store from '@/store.ts';
const localVue = createLocalVue();
そして、ストアを渡します:
describe('Components', () => {
it('renders a comment form', () => {
const COMMENTFORM = shallowMount(CommentForm,{
localVue,
router,
store
});
})
})
このソリューションは、次のエラーを解決しました。
this.$route.params.id
を使用すると、未定義のプロパティ 'params'を読み取れませんrouter-link
✔
彼の答えに対して@SColvinに感謝します。私のシナリオで答えを見つけるのを助けました
ERROR: '[Vue warn]: Error in render function: (found in <RouterLink>)'
Vueにはルーターが提供されていなかったため、ユニットテスト中。
describe('Hello.vue', () =>
{
it('should render correct contents', () =>
{
const Constructor = Vue.extend(Hello);
const vm = new Constructor().$mount();
expect(vm.$el.querySelector('.hello h1').textContent)
.to.equal('Welcome to Your Vue.js App');
});
に
describe('Hello.vue', () =>
{
it('should render correct contents', () =>
{
Vue.use(VueRouter);
const router = new VueRouter({
routes: [
{ path: '/', name: 'Hello', component: Hello },
],
});
const vm = new Vue({
el: document.createElement('div'),
/* eslint-disable object-shorthand */
router: router,
render: h => h('router-view'),
});
expect(vm.$el.querySelector('.hello h1').textContent)
.to.equal('Welcome to Your Vue.js App');
});
});
ビューにパラメーターを渡す必要がないので、コンポーネントをデフォルトのレンダリングとして単純化でき、プッシュする必要もnextTickを待つ必要もありません。 HTH他の誰か!
私が見つけた最も簡単な方法は、localVueを使用することです
import { createLocalVue, mount } from '@vue/test-utils'
import ComponentName from 'componentPath'
import Vuex from 'vuex'
import store from '@/store/store' //Add store file if any getters is accessed
import VueRouter from 'vue-router'
describe('File name', () => {
const localVue = createLocalVue()
localVue.use(VueRouter)
const routes = [ //Can also be rreplaced with route(router.js) file
{
path: '/path',
component: ComponentName,
name: 'Route name'
}
]
const router = new VueRouter({
routes
})
router.Push({
name: 'Route name',
params: {}
}) //if needed
const wrapper = mount(ComponentName, {localVue, router, store })
beforeEach(function() {
});
it('Method()', () => {
wrapper.vm.methodName()
expect(wrapper.vm.$route.path).toBe(routes[0].path)
});
});
それが役に立てば幸い!!!
これは、私が この記事 に従って行ってきたことです。
it('renders $router.name', () => {
const scopedVue = Vue.extend();
const mockRoute = {
name: 'abc'
};
scopedVue.prototype.$route = mockRoute;
const Constructor = scopedVue.extend(Component);
const vm = new Constructor().$mount();
expect(vm.$el.textContent).to.equal('abc');
});
Vue-test-utilsを使用してこの例を見てみましょう。ここでは、ルーターとストアの両方をモックしています。
import ArticleDetails from '@/components/ArticleDetails'
import { mount } from 'vue-test-utils'
import router from '@/router'
describe('ArticleDetails.vue', () => {
it('should display post details', () => {
const POST_MESSAGE = 'Header of our content!'
const EXAMPLE_POST = {
title: 'Title',
date: '6 May 2016',
content: `# ${POST_MESSAGE}`
}
const wrapper = mount(ArticleDetails, {
router,
mocks: {
$store: {
getters: {
getPostById () {
return EXAMPLE_POST
}
}
}
}
})
expect(wrapper.vm.$el.querySelector('h1.post-title').textContent.trim()).to.equal(EXAMPLE_POST.title)
expect(wrapper.vm.$el.querySelector('time').textContent.trim()).to.equal(EXAMPLE_POST.date)
expect(wrapper.vm.$el.querySelector('.post-content').innerHTML.trim()).to.equal(
`<h1>${POST_MESSAGE}</h1>`
)
})
})
特にルーターを「モック」する必要はありません。アプリケーションは、グローバルvueスコープでVueRouterを設定できますが、テストで問題なく実行することができます。
VueRouter
を使用してlocalVueの使用方法を読み取ります: https://vue-test-utils.vuejs.org/guides/#using-with-vue-router 。
現在、メインアプリから複雑なルーターを取得し、jest.spyOn()
をrouter.Push()
に呼び出し、一部のコンポーネントでshallowMount()
を実行してコンポーネントを作成する前にパスを設定できますcreated()
フックでのルート処理。
回避策
// someVueComponent.vue
<template>
... something
</template>
<script>
...
data () {
return {
authenticated: false
}
},
...
created () {
if(!this.authenticated && this.$route.path !== '/'){
this.$router.Push('/')
}
}
</script>
// someVueComponent.spec.js
import Vuex from 'vuex'
import VueRouter from 'vue-router'
import { shallowMount, createLocalVue } from '@vue/test-utils'
import SomeVueComponent from 'MyApp/components/someVueComponent'
import MyAppRouter from 'MyApp/router'
import MyAppCreateStore from 'MyApp/createStore'
import merge from 'lodash.merge'
function setVueUseValues (localVue) {
localVue.use(Vuex)
localVue.use(VueRouter)
// other things here like custom directives, etc
}
beforeEach(() => {
// reset your localVue reference before each test if you need something reset like a custom directive, etc
localVue = createLocalVue()
setVueUseValues(localVue)
})
let localVue = createLocalVue()
setVueUseValues(localVue)
test('my app does not react to path because its default is "/"', () => {
const options = {
localVue,
router: MyAppRouter,
store: MyAppCreateStore()
}
const routerPushSpy = jest.spyOn(options.router, 'Push')
const wrapper = shallowMount(SomeVueComponent, options)
expect(routerPushSpy).toHaveBeenCalledTimes(0)
})
test('my app reacts to path because its not "/" and were not authenticated', () => {
const options = {
localVue,
router: MyAppRouter,
store: MyAppCreateStore()
}
const routerPushSpy = jest.spyOn(options.router, 'Push')
options.router.Push('/nothomepath')
expect(routerPushSpy).toHaveBeenCalledWith('/nothomepath') // <- SomeVueComponent created hook will have $route === '/nothomepath' as well as fullPath
const wrapper = shallowMount(SomeVueComponent, options)
expect(routerPushSpy).toHaveBeenCalledWith('/') // <- works
})
上記は、$route
が作成/マウントされる前にSomeVueComponent.vue
状態を変更する必要があるという考えで行われます。ラッパーを作成でき、他の状態またはアクションに基づいてコンポーネントthis.$router.Push('/something')
をテストしたい場合は、wrapper.vm
インスタンスを常にスパイできます。
let routerPushSpy = jest.spyOn(wrapper.vm.$router, 'Push') // or before hooks, etc
この記事の執筆時点では、vm.$route
は常に未定義であるため、以下を動作させない未解決の欠陥があるようです。 VueRouterをインストールすると、読み取り専用プロパティが$route
に書き込まれるため、$route
。
Vue-test-utilsドキュメントから https://vue-test-utils.vuejs.org/guides/#mocking-route-and-router :
import { shallowMount } from '@vue/test-utils'
const $route = {
path: '/some/path'
}
const wrapper = shallowMount(Component, {
mocks: {
$route
}
})
wrapper.vm.$route.path // /some/path
ここに興味がある場合は、問題の再現へのgithubリンクがあります: https://github.com/vuejs/vue-test-utils/issues/1136
@SColvinからのすばらしい答えに加えて、 Avoriaz を使用したこの作業の例を示します。
import { mount } from 'avoriaz'
import Vue from 'vue'
import VueRouter from 'vue-router'
import router from '@/router'
import HappyComponent from '@/components/HappyComponent'
Vue.use(VueRouter)
describe('HappyComponent.vue', () => {
it('renders router links', () => {
wrapper = mount(HappyComponent, {router})
// Write your test
})
})
これも vue-test-utils で動作するはずだと思います。
vm。$ routerにモックできますvm._routerRoot._router
例えば
var Constructor = Vue.extend(Your_Component)
var vm = new Constructor().$mount()
var your_mock_router = {hello:'there'}
vm.$router = your_mock_router //An error 'setting a property that has only a getter'
vm._routerRoot._router = your_mock_router //Wow, it works!
ここでソースコードを再確認できます: https://github.com/vuejs/vue-router/blob/dev/dist/vue-router.js#L558
私が見つけた最も簡単な方法は、$ routeをモックすることです。
it('renders $router.name', () => {
const $route = {
name: 'test name - avoriaz'
}
const wrapper = shallow(Component, {
mocks: {
$route
}
})
expect(wrapper.text()).to.equal($route.name)
})