The test source code:
import VueRouter from 'vue-router'
import { createLocalVue, shallow } from 'vue-test-utils'
import Breadcrumb from './breadcrumb.vue'
import Foo from './foo.vue'
const localVue = createLocalVue()
localVue.use(VueRouter)
const routes = [{ path: '/foo', component: Foo }]
const $route = { path: '/foo' }
const router = new VueRouter({
mode: 'history',
routes
})
const wrapper = shallow(Breadcrumb, {
localVue,
router,
mocks: {
$route
}
})
The error message:

Hi, this is a common problem with trying to set $route or $router when it's already been installed on the base Vue contstructor. Somewhere in your code you will be calling Vue.use(VueRouter).
You need to only install on a localVue, otherwise $route and $router are added as read-only properties to the base constructor, and you'll be unable to rewrite them.
We should add a better error message so that users know how to fix the problem.
Thanks a lot for your answer.
Actually I'm using jest and vue-jest to generate a snapshot, so I'm sure that I did not boot the app and the code posted above was excuted isolately.
What you pointed out:
Somewhere in your code you will be calling Vue.use(VueRouter).
may probably not the reason.
In my opinion, since localVue.use(VueRouter), $route or $routethe already exisited on instance of localVue. So what is the proper way to config $route?
If you call .use(VueRouter) on a localVue class, you can't overwrite $router. You'll need to create a fresh localVue class to mock $route or $router
In 2d4b999 we try/catch the attempt to add to the Vue prototype, and log this error if the property could not be written: could not overwrite property $store, this usually caused by a plugin that has added the property as a read-only value
I think @eddyerburgh's explanation should be added to the docs. The docs talk about installing the router on localVue, about mocking, but it doesn't say anything about the fact that we can't use both (perhaps it is obvious, but it wasn't for me).
I am in a situation where I installed VueRouter on localVue, but I also need to tell the component that I am in a certain route with certain parameters, therefore, I was doing:
const localVue = createLocalVue();
localVue.use(VueRouter);
const router = new VueRouter({ name: 'category-edit', params: { category_id: 1 }});
const wrapper = shallow(CategoryForm, {
localVue,
router,
mocks: {
$route: { name: 'category-edit', params: { category_id: 1 }}
}
});
But then this doesn't work for the reasons @eddyerburgh already explained. But then, how would one go about solving this situation?
@FernandoBasso Unfortunately, the only way to solve this problem is to create a fresh localVue and not install VueRouter on it.
If you need to use the RouterLink, or RouterView components, you can use the stubs option to pass in stubs. vue-test-utils includes a RouterLinkStub component:
const wrapper = mount(TestComponent, {
stubs: {
'router-link': RouterLinkStub,
'router-view': {
render: h => h('div')
}
}
})
I've added a note to the docs to help future readers avoid the issue you were having 😀
Sorry to tack on to this closed issue, but what was the resolution? I'm trying to mock a query param and test that the param was pushed, and I tried the code samples here as well as examples I found online — they all seem to show how to mock the params or spy on the router but not both.
I've tried asking around online, but the only way our team has been able to make this work is by installing the Vue Router to localVue (no arguments) and then in the test:
it('ensures the Redirect button navigates to Destination Page with \'some query param\', () => {
const query = { a: 'some query param' }
givenComponent(componentData) // shallowMounts component
component.$route.query.a = 'some query param' // writing to query directly doesn't work which seems increases our 'this is sus' feels
spyOn(component.$router, 'push') // we use Jasmine
expect(component.$router.push).toHaveBeenCalledWith({
name: 'Destination route name',
query,
})
})
But this smells off to us; should we be doing this differently? Is this comment about an issue with importing routers accurate/germane?
Update: Another approach we discovered is to push a route with the relevant query params before testing, but this doesn't feel right either.
Most helpful comment
@FernandoBasso Unfortunately, the only way to solve this problem is to create a fresh localVue and not install VueRouter on it.
If you need to use the RouterLink, or RouterView components, you can use the
stubsoption to pass in stubs. vue-test-utils includes a RouterLinkStub component:I've added a note to the docs to help future readers avoid the issue you were having 😀