Vue Test Utils - Unable to correctly mount/shallow mount component, wrapper undefined - vue.js

I've tried almost everything I can think of but I'm unable to correctly mount/shallow mount my vue components for testing correctly. Everytime I console.log the wrapper I get the following print out:
VueWrapper {
isFunctionalComponent: undefined,
_emitted: [Object: null prototype] {},
_emittedByOrder: []
}
This question is similar to this question asked here:
Vue-test-utils wrapper undefined
I'm using Vuetify, Vuex and Vue Router. My test.spec.ts is below:
import { shallowMount, createLocalVue, mount } from "#vue/test-utils"
import Vuex from "vuex"
import Vuetify from "vuetify"
import VueRouter from "vue-router"
import TheExamAnswer from "#/components/common/TheExamAnswer.vue"
describe("TheExamAnswer.vue", () => {
const localVue = createLocalVue()
let getters: any
let store: any
let vuetify: any
let router: any
beforeEach(() => {
localVue.use(Vuex)
localVue.use(Vuetify)
localVue.use(VueRouter)
getters = {
getExam: () => true,
}
store = new Vuex.Store({
modules: {
// Need to add FlightPlanning for name spacing
FlightPlanning: {
namespaced: true,
getters,
},
},
})
vuetify = new Vuetify()
router = new VueRouter()
})
it("Renders the element if the exam has been submitted", () => {
const wrapper = mount(TheExamAnswer, { localVue, store, router })
console.log("This is the HTML", wrapper.html())
expect(wrapper.text()).toContain("Show Answer")
})
})
My view component is very simple and the code is below:
<template>
<div v-if="submitted" class="div">
<v-btn #click="answerHidden = !answerHidden" class="mb-10"
>Show Answer</v-btn
>
<div v-if="!answerHidden">
<slot name="questionAnswer"></slot>
</div>
</div>
</template>
<script>
export default {
data: () => {
return {
answerHidden: true,
}
},
computed: {
submitted() {
const exam = this.$store.getters["FlightPlanning/getExam"]
return exam.submitted
},
},
}
</script>
<style></style>
UPDATED: I've added the suggestion from the answer below however now I"m getting the following message.
TheExamAnswer.vue
✕ Renders the element if the exam has been submitted (49ms)
● TheExamAnswer.vue › Renders the element if the exam has been submitted
expect(received).toContain(expected) // indexOf
Expected substring: "Show Answer"
Received string: ""
38 | const wrapper = mount(TheExamAnswer, { localVue, store, router })
39 | console.log("This is the HTML", wrapper.html())
> 40 | expect(wrapper.text()).toContain("Show Answer")
| ^
41 | })
42 | })
43 |
at Object.it (tests/unit/test.spec.ts:40:28)
console.error node_modules/vuetify/dist/vuetify.js:43612
[Vuetify] Multiple instances of Vue detected
See https://github.com/vuetifyjs/vuetify/issues/4068
If you're seeing "$attrs is readonly", it's caused by this
console.log tests/unit/test.spec.ts:39
This is the HTML
Test Suites: 1 failed, 1 total
Tests: 1 failed, 1 total
As you can see the HTML is blank and therefore I'm presuming that's also the same reason it's failing this test as the received string is "".
SOLUTION -
I figured it out. The error was on my behalf by not looking at the logic of the computed property correctly.
In my test I had:
getters = {
getExam: () => true,
}
In my component I had:
computed: {
submitted() {
const exam = this.$store.getters["FlightPlanning/getExam"]
return exam.submitted
},
If you look at the logic of the computed property it going to take whats returned from the getter and assign it to the exam variable. Originally I was returning true, because that's what I wanted the submitted() function to return this means when I call exam.submitted I'm calling it on a boolean value which obviously gives me "undefined". The solution was to return exactly what the computed property was designed to deal with, an object i.e. {submitted:true}
Therefore the final test looks like this and is returning valid HTML.
import { shallowMount, createLocalVue, mount } from "#vue/test-utils"
import Vuex from "vuex"
import Vuetify from "vuetify"
import VueRouter from "vue-router"
import TheExamAnswer from "#/components/common/TheExamAnswer.vue"
const localVue = createLocalVue()
localVue.use(Vuex)
localVue.use(Vuetify)
localVue.use(VueRouter)
describe("test.vue", () => {
let getters: any
let store: any
let vuetify: any
let router: any
beforeEach(() => {
getters = {
getExam: () => {
return { submitted: true }
},
}
store = new Vuex.Store({
modules: {
// Need to add FlightPlanning for name spacing
FlightPlanning: {
namespaced: true,
getters,
},
},
})
vuetify = new Vuetify()
router = new VueRouter()
})
it("Renders the element if the exam has been submitted", () => {
const wrapper = mount(TheExamAnswer, { localVue, vuetify, store, router })
console.log("This is the HTML", wrapper.html())
})
})
This gives me the result of:
console.log tests/unit/test.spec.ts:44
This is the HTML <div><button type="button" class="mb-10 v-btn v-btn--contained theme--light v-size--default"><span class="v-btn__content">Show Answer</span></button>
<!---->
</div>
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 5.235s
Ran all test suites.

The console.log with that weird input for wrapper or elements is normal behaviour. I ran couple tests with your components and everything was working.
it("Renders the element if the exam has been submitted", () => {
const wrapper = mount(TheExamAnswer, { localVue, store, router });
expect(wrapper.text()).toContain("Show Answer");
});
If you want to console.log html in your wrapper:
console.log(wrapper.html())
UPDATED: the reason, why wrapper.html() return empty string is v-if="submitted" on your root component. The computed property return undefined, because getter return true, so true.submitted return undefined
Getter in test.spec.ts:
getters = {
getExam: () => {
return { submitted: true };
}
};

Related

Jest : TypeError: Cannot read property 'variable' of undefined

I am testing though Jest on the Vue 2.x, nuxtjs and #nuxtjs/composition-api.
However, the state value in the components has undefined value when testing though jest
List.spec.js
import Vue from 'vue';
import Vuetify from 'vuetify';
import { createLocalVue, shallowMount } from '#vue/test-utils';
import List from '#/components/home/list.vue';
Vue.use(Vuetify);
describe('List.vue', () => {
const localVue = createLocalVue();
let vuetify;
const $t = () => {};
const localePath = () => {};
beforeEach(() => {
vuetify = new Vuetify();
localVue.use(vuetify);
});
const mockOrder = [
{
coardshare: {
cs_id: 123,
},
},
{
talkboard: {
cs_id: 123,
},
},
];
it('11111', () => {
const wrapper = shallowMount(List, {
localVue,
vuetify,
propsData: { data: mockOrder },
mocks: { $t, localePath },
data() {
return {
data: mockOrder,
};
},
});
expect(wrapper.html()).toMatchSnapshot();
const title = wrapper.find('.v-card__title > span');
expect(title.text()).toBe('Foobar');
});
});
List.vue
<template>
...
<div v-for="item in state.data.talkboard" :key="item.cs_id">
<ListItem :item="item"></ListItem>
</div>
...
</template>
<script>
import { reactive, onMounted, useContext } from '#nuxtjs/composition-api';
import axios from 'axios';
import Header from './header';
import ListItem from './list-item.vue';
export default {
name: 'ListHome',
components: {
Header,
ListItem,
},
setup() {
const state = reactive({
data: [],
});
const { store } = useContext();
const fatch = async () => {
....
};
onMounted(fatch);
return {
state,
fatch,
};
},
};
</script>
error message
TypeError: Cannot read property 'data' of undefined
I am testing though Jest on the Vue 2.x, nuxtjs and #nuxtjs/composition-api.
However, the state value in the components has undefined value when testing though jest
why error on this ?? because of composition API that define the state with reactive() function ??
In your test file maybe you can try something like this:
it('11111', () => {
const wrapper = shallowMount(List, {
localVue,
vuetify,
propsData: { data: mockOrder },
mocks: { $t, localePath },
data: () => {
return {
data: mockOrder,
};
},
});

How to test a vue vuetify v-autocomplete

Somehow I'm not able to see the items of the v-autocomplete inside the html during the test and also setting an item does not work. Below the v-autocomplete (which is loading the items on mount) and the test.
// v-autocomplete.vue
<template>
<v-autocomplete
:items="items"
item-text="name"
item-value="id"
></v-autocomplete>
</template>
<script>
export default {
data() {
return {
items: [],
};
},
mounted() {
service.getItems().then((response) => {
this.items = response;
});
},
};
</script>
The test looks like this:
//v-autocomplete.spec.js
import Vue from 'vue';
import Vuetify from 'vuetify';
import VAutocomplete from '#/components/v-autocomplete.vue';
import '#testing-library/jest-dom';
import { createLocalVue, mount } from '#vue/test-utils';
import service from '#/service/service';
Vue.use(Vuetify);
const items= [
{ name: 'Item 1', id: 1 },
{ name: 'Item 2', id: 2 },
];
const getItemsSpy = jest
.spyOn(service, 'getItems')
.mockImplementation(() => {
return new Promise((resolve) => {
resolve(items);
});
});
describe('v-autocomplete.vue', () => {
let localVue;
let vuetify;
let wrapper;
beforeEach(() => {
jest.clearAllMocks();
localVue = createLocalVue();
vuetify = new Vuetify();
});
it('should load the items', async () => {
wrapper = mount(VAutocomplete, {
localVue,
vuetify,
propsData: {},
});
expect(getItemsSpy).toBeCalledTimes(1);
for (const item of items) {
expect(getByText(wrapper.element, item.name)).toBeTruthy(); // Will fail -> Unable to find an element with the text
}
});
});
The test expect(getByText(wrapper.element, item.name)).toBeTruthy(); will fail with the message Unable to find an element with the text. Also printing the html with console.log(wrapper.html()) does not show the items of the v-autocomplete. So my question would be:
How could I test, if the items were loaded?
How could I set one of the loaded as the selected item of the v-autocomplete?
You can open autocomplete menu on click .v-input__slot. I do no think, it is best practice to test library functionality.
Unit test:
it("should load the items", async () => {
wrapper = mount(VAutocomplete, {
localVue,
vuetify,
propsData: {}
});
const autocomplete = wrapper.element;
const autocompleteControls = autocomplete.find(".v-input__slot");
autocompleteControls.trigger("click");
await wrapper.vm.$nextTick();
expect(getItemsSpy).toBeCalledTimes(1);
for (const item of items) {
expect(getByText(wrapper.element, item.name)).toBeTruthy();
}
});
Source:
https://github.com/vuetifyjs/vuetify/blob/master/packages/vuetify/src/components/VSelect/\_\_tests__/VSelect.spec.ts

Vue-router: Using component method within the router

My first Vue project and I want to run a loading effect on every router call.
I made a Loading component:
<template>
<b-loading :is-full-page="isFullPage" :active.sync="isLoading" :can-cancel="true"></b-loading>
</template>
<script>
export default {
data() {
return {
isLoading: false,
isFullPage: true
}
},
methods: {
openLoading() {
this.isLoading = true
setTimeout(() => {
this.isLoading = false
}, 10 * 1000)
}
}
}
</script>
And I wanted to place inside the router like this:
router.beforeEach((to, from, next) => {
if (to.name) {
Loading.openLoading()
}
next()
}
But I got this error:
TypeError: "_components_includes_Loading__WEBPACK_IMPORTED_MODULE_9__.default.openLoading is not a function"
What should I do?
Vuex is a good point. But for simplicity you can watch $route in your component, and show your loader when the $route changed, like this:
...
watch: {
'$route'() {
this.openLoading()
},
},
...
I think it's fast and short solution.
I don't think you can access a component method inside a navigation guard (beforeEach) i would suggest using Vuex which is a vue plugin for data management and then making isLoading a global variable so before each route navigation you would do the same ... here is how you can do it :
Of course you need to install Vuex first with npm i vuex ... after that :
on your main file where you are initializing your Vue instance :
import Vue from 'vue'
import Vuex from 'vue'
Vue.use(Vuex)
const store = new Vuex.Store({
state: {
isLoading: false,
},
mutations: {
openLoading(state) {
state.isLoading = true
setTimeout(() => {
state.isLoading = false
}, 10000)
},
},
})
// if your router is on a separated file just export the store and import it there
const router = new VueRouter({
routes: [
{
// ...
},
],
})
router.beforeEach((to, from, next) => {
if (to.name) {
store.commit('openLoading')
}
next()
})
new Vue({
/// ....
router,
store,
})
In your component:
<b-loading :is-full-page="isFullPage" :active.sync="$store.state.isLoading" :can-cancel="true"></b-loading>

Quasar Unknown custom element error in unit test

I have a simple Vue component that uses Quasar button
<template>
<div>
<span class="count">{{ count }}</span>
<q-btn #click="increment">Increment</q-btn>
</div>
</template>
<script>
export default {
name: 'TestComponent',
data() {
return {
count: 0,
};
},
methods: {
increment() {
this.count += 1;
},
},
};
</script>
I create a unit test for it
import { mount, createLocalVue } from '#vue/test-utils';
import { Quasar, QBtn } from 'quasar';
import TestComponent from '../TestComponent';
describe('TestComponent', () => {
let wrapper;
beforeEach(() => {
const localVue = createLocalVue();
localVue.use(Quasar, { components: { QBtn } });
wrapper = mount(TestComponent, { localVue });
});
it('renders the correct markup', () => {
expect(wrapper.html()).toContain('<span class="count">0</span>');
});
// it's also easy to check for the existence of elements
it('has a button', () => {
expect(wrapper.contains('button')).toBe(true);
});
});
My problem:
If I run the test cases (it function) one by one at a time the test will pass. For example, remove the second it('has a button'...) then run the test. It'll pass. It's the same when removing the first it('renders the correct markup'...)
However, If I keep all test cases then run the test. The second test case will fail with an error
console.error node_modules/vue/dist/vue.common.dev.js:630
[Vue warn]: Unknown custom element: <q-btn> - did you register the component correctly? For recursive components, make sure to provide the "name" option.
found in
---> <TestComponent>
<Root>
What am I doing wrong?
Try removing the before-each. I saw this problem too. Can't remember what exactly fixed it but this is how I have my describe block.
describe('Mount Quasar', () => {
const localVue = createLocalVue()
localVue.use(Quasar, { components })
const wrapper = shallowMount(Register, {
localVue,
stubs: ['router-link', 'router-view']
})
const vm = wrapper.vm
it('passes the sanity check and creates a wrapper', () => {
expect(wrapper.isVueInstance()).toBe(true)
})
})
You will need to import quasar into either webpack, babel, or jest.
In the jest.config.js file
Add
moduleNameMapper: {
quasar: "quasar-framework/dist/umd/quasar.mat.umd.min.js"
},

How to write test that mocks the $route object in vue components

I have a component that contains statement like this.$route.fullPath, how should I mock value of fullPathof $route object if I want to test that component?
I disagree with the top answer - you can mock $route without any issue.
On the other hand, installing vue-router multiple times on the base constructor will cause you problems. It adds $route and $router as read only properties. Which makes it impossible to overwrite them in future tests.
There are two ways to achieve this with vue-test-utils.
Mocking vue-router with the mocks option
const $route = {
fullPath: 'full/path'
}
const wrapper = mount(ComponentWithRouter, {
mocks: {
$route
}
})
wrapper.vm.$route.fullPath // 'full/path'
You can also install Vue Router safely by using createLocalVue:
Installing vue-router safely in tests with createLocalVue
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')
Best not mock vue-router but rather use it to render the component, that way you get a proper working router. Example:
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()
})
})
})
Things to note:
I'm using the runtime-only version of vue, hence render: h => h('router-view').
I'm only testing the totest component, but others might be required if they're referenced by totest eg. another_component in this example.
You need nextTick for the HTML to have rendered before you can look at it/test it.
One of the problems is that most of the examples I found referred to the old version of vue-router, see the migrations docs, eg. some examples use router.go() which now doesn't work.
No answer was helping me out, So I dig into vue-test-utils documentation and found myself a working answer, so you need to import.
import { shallowMount,createLocalVue } from '#vue/test-utils';
import router from '#/router.ts';
const localVue = createLocalVue();
We created a sample vue instance. While testing you need to use shallowMount so you can provide vue app instance and router.
describe('Components', () => {
it('renders a comment form', () => {
const COMMENTFORM = shallowMount(CommentForm,{
localVue,
router
});
})
})
You can easily pass router and to shallow mount and it does not gives you the error. If you want to pass store you use:
import { shallowMount,createLocalVue } from '#vue/test-utils';
import router from '#/router.ts';
import store from '#/store.ts';
const localVue = createLocalVue();
And then pass store:
describe('Components', () => {
it('renders a comment form', () => {
const COMMENTFORM = shallowMount(CommentForm,{
localVue,
router,
store
});
})
})
This solution solved the following errors:
Cannot read property 'params' of undefined when using this.$route.params.id
Unknown custom element router-link
✔
Easiest method i found is to use localVue
import { createLocalVue, mount } from '#vue/test-utils';
import VueRouter from 'vue-router';
import Vuex from 'vuex';
import ComponentName from '#/components/ComponentName.vue';
// Add store file if any getters is accessed
import store from '#/store/store';
describe('File name', () => {
const localVue = createLocalVue();
localVue.use(VueRouter);
// Can also be replaced with route(router.js) file
const routes = [
{
path: '/path',
component: ComponentName,
name: 'Route name'
}
];
const router = new VueRouter({ routes });
// if needed
router.push({
name: 'Route name',
params: {}
});
const wrapper = mount(ComponentName, {
localVue,
router,
store
});
test('Method()', () => {
wrapper.vm.methodName();
expect(wrapper.vm.$route.path)
.toEqual(routes[0].path);
});
});
Hope it helps!!!
Why are all answers so complicated? You can just do:
...
wrapper = mount(HappyComponent, {
mocks: {
$route: { fullPath: '' }
},
})
...
You dont have to specifically "mock" a router. Your application can set VueRouter in the global vue scope and you can still make it do what you want in your tests without issue.
Read the localVue usage with VueRouter: https://vue-test-utils.vuejs.org/guides/#using-with-vue-router.
I am currently pulling in a complex router from our main app and am able to jest.spyOn() calls to router.push() as well as setting the path before the component is created running shallowMount() for some route handling in a created() hook.
The Workaround
// 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
})
The above is done with the idea that I need the $route state changed before SomeVueComponent.vue is created/mounted. Assuming you can create the wrapper and want to test that the component this.$router.push('/something') based on some other state or action you can always spy on the wrapper.vm instance
let routerPushSpy = jest.spyOn(wrapper.vm.$router, 'push') // or before hooks, etc
As of this writing there seems to be an open defect which keeps the following from working because vm.$route will always be undefined, making the above the only option (that I know of) as there is no other way to "mock" the $route because installing VueRouter writes read only properties to $route.
From the vue-test-utils docs 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
If your interested here is the github link to a reproduction of the issue: https://github.com/vuejs/vue-test-utils/issues/1136
All kudos to #SColvin for his answer; helped find an answer in my scenario wherein I had a component with a router-link that was throwing a
ERROR: '[Vue warn]: Error in render function: (found in <RouterLink>)'
during unit test because Vue hadn't been supplied with a router. Using #SColvin answer to rewrite the test originally supplied by vue-cli from
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');
});
to
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');
});
});
Not needing to pass parameters in to the view I could simplify the component as the default render, no need to push and no need to wait nextTick. HTH someone else!
Adding to the great answer from #SColvin, here's an example of this working using 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
})
})
I believe this should work with vue-test-utils, too.
Take a look at this example using vue-test-utils, where I'm mocking both router and store.
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>`
)
})
})
This is what I've been doing as per this article:
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');
});
You can mock to vm.$router by setting vm._routerRoot._router
For example
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!
You can double check their source code here: https://github.com/vuejs/vue-router/blob/dev/dist/vue-router.js#L558
Easiest way i've found is to mock the $route.
it('renders $router.name', () => {
const $route = {
name: 'test name - avoriaz'
}
const wrapper = shallow(Component, {
mocks: {
$route
}
})
expect(wrapper.text()).to.equal($route.name)
})