Currently it's not possible to find RouterLink and RouterView when using vue-test-utils. You can find the rendered content, but if you want to check that a RouterLink receives the correct to property, you need to check the tag renders an href:
wrapper.find('a').element.href
We're considering adding a RouterLink stub to vue-test-utils, so you can do this:
wrapper.find(RouterLink).props().to
But adding a stub basically means reimplimenting the RouterLink, since we don't actually need to stub it, we just need to have access to the component as a selector.
Instead, would we be able to expose RouterLink and RouterView from Vue Router?
We could import the components with the same name they are registered with:
import { RouterLink, RouterView } from 'vue-router'
Why not use Vue.component to attach them?
const RouterView = Vue.component('router-view');
const RouterLink = Vue.component('router-link');
@JounQin I didn't know you could use Vue component like that.
The problem is you need Vue Router installed on the Vue instance, which adds $route and $router as read-only values. So instead, you'd have to do something like this:
const localVue = createLocalVue()
localVue.use(VueRouter)
const RouterLink = localVue.component('router-link');
const wrapper = shallow(Comp, { localVue })
wrapper.find(RouterLink).props().to
Which I suppose isn't too bad 🤔
@eddyerburgh I "not too bad" good enough to close this? :-P
I think we still need the change for two reasons:
1) If you install Vue Router you can't mock $route or $router in a test, so you wouldn't be able to test a RouterLink component and mock the param value of $route.
2) We'd need to make users aware that they need to follow this pattern (installing VueRouter then calling Vue.component to access to RouterLink component). If we expose RouterLink and RouterView, users will be able to follow the recommended pattern for finding stubbed components
Looks good to me and it's very easy to add. What do you think? @yyx990803
I think that's good to have. Open to PR.
This would be a breaking change for the common js or browser build.
We can export them in vue-test-utils instead
It would be so much better if we could avoid Router injecting global router-link component and instead import it explicitly whenever it is needed with import Link from 'vue-router/link'.
That way we will have self-contained components. Right now they are relying on obscure globally injected component, which you need to re-added during tests by using whole router instance, instead of declaring it imports at first place — in the component itself.
I suppose this is rejected and we should follow https://github.com/vuejs/vue-router/issues/1976#issuecomment-356203955?
@ArmorDarks made a good case for this. I also just ran into this issue. Our component library, using its own set of node_modules, uses a different Vue instance which doesn't have the component. Being able to explicitly import it would solve this issue.
This seems like a simple non-breaking change.
@eddyerburgh @yyx990803
Here's a tentative PR: #2853
As mentioned by @eddyerburgh, we can't add additional exports to the umd/browser builds because they only support a single default export. We can however add them to the ES module builds without breaking backwards compatibility. I assume anyone interested in this feature is using ES modules anyway. I concede that it is a bit hacky though.
Finally, I am also convinced that this is not needed in vue-router. Here's the summary:
Vue.component to get a reference to the components:const RouterView = Vue.component('router-view');
const RouterLink = Vue.component('router-link');
If your problem is multiple Vue instances, refer to this issue: https://github.com/vuejs/vue/issues/8278
For testing, consider adding stubs instead.
Case closed, as far as I can tell.
Most helpful comment
It would be so much better if we could avoid Router injecting global
router-linkcomponent and instead import it explicitly whenever it is needed withimport Link from 'vue-router/link'.That way we will have self-contained components. Right now they are relying on obscure globally injected component, which you need to re-added during tests by using whole router instance, instead of declaring it imports at first place — in the component itself.