vue-testing-library: VTL for Vue 3: The routes option does not work correctly
Describe the bug When using the routes option of the render function, it throws up some warnings that have to do with the _history property and the asynchronic handling that vue router 4 has. This causes you to not be able to use the routes option correctly.
To Reproduce
import { render, screen } from '@testing-library/vue'
import '@testing-library/jest-dom'
import { defineComponent } from 'vue'
import { RouteRecordRaw } from 'vue-router'
test('Component with route', () => {
const ComponentA = defineComponent({
name: 'ComponentA',
props: {
to: {
type: Object,
required: true
}
},
template: `<router-link :to="to" role="button">Learn More</router-link>`
})
const ComponentB = defineComponent({
name: 'ComponentB'
})
const routeRecordRaw: RouteRecordRaw = {
path: '/',
name: 'componentB',
component: ComponentB
}
const to = { name: routeRecordRaw.name }
render(ComponentA, {
props: { to },
routes: [routeRecordRaw]
})
const button = screen.getByRole('button')
expect(button).toBeInTheDocument()
expect(button?.getAttribute('href')).toBe(routeRecordRaw.path)
})
This throws the following warning
console.warn node_modules/vue-router/dist/vue-router.cjs.js:75
[Vue Router warn]: Unexpected error when starting the router: TypeError: Cannot read property '_history' of null
The warning is known. This is explained in the vue-test-utils v2 documentation https://vue-test-utils.vuejs.org/v2/guide/vue-router.html#with-a-real-router
So to solve it apply what is indicated in documentation
import { render, screen } from '@testing-library/vue'
import '@testing-library/jest-dom'
import { defineComponent } from 'vue'
import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router'
test('Component with route', async () => {
const ComponentA = defineComponent({
name: 'ComponentA',
props: {
to: {
type: Object,
required: true
}
},
template: `<router-link :to="to" role="button">Learn More</router-link>`
})
const ComponentB = defineComponent({
name: 'ComponentB'
})
const routeRecordRaw: RouteRecordRaw = {
path: '/',
name: 'componentB',
component: ComponentB
}
const router = createRouter({
history: createWebHistory(process.env.BASE_URL),
routes: [routeRecordRaw]
})
router.push('/')
await router.isReady()
const to = { name: routeRecordRaw.name }
render(ComponentA, {
props: { to },
global: {
plugins: [router]
}
})
const button = screen.getByRole('button')
expect(button).toBeInTheDocument()
expect(button?.getAttribute('href')).toBe(routeRecordRaw.path)
})
Expected behavior Be able to correctly use the routes option provided by the render function
Related information:
@testing-library/vueversion: ^6.3.1Vueversion: ^3.0.0nodeversion: 14.4.0npmversion: 6.14.9
About this issue
- Original URL
- State: closed
- Created 4 years ago
- Comments: 25 (16 by maintainers)
I have definitely seen the
_historyerror before. It was related to awaiting the router to be read, but you’ve already done that.I wonder if this is a bug here? I feel like it might be either in Test Utils or something else. I wonder if we can reproduce it without Testing Library (VTU + Jest). I wonder if you need to have a top level component (like
<app>) with a<router-view />for this to work as expected.Going back to this. As I see it, we’re down to two options:
Make
renderasync whenroutesis present, and then callrouter.isReady()internally. API change: you’d need toawait render(Comp, { routes }), but not when routes is not there. We could warn users somehow (plus, TS types would help, too).Remove vuex/router integration for Vue 3, and leave it to users. This would make users responsible for setting up router (and store) and call
router.isReady(), which is an implementation detail (even though it is on the Arrange section of tests, which is OK, I guess), and would keeprendersync. This solution makes VTL more aligned to other Testing Lib flavors.To be fair, setting up your own router/vuex isn’t that bad now with VTU 2 since there’s no need to set up a local vue instance. On the other hand, “hiding” the need to mke router ready feels… right for users.
I thought about my previous comment, it’s a bad idea, actually. We did something similar for Vue 2 (“sync mode”) and it had a lot of knock on effects where tests vs the real thing were different. We had both “sync mode” for test utils and something in Vue core.
And with the mock router, I guess XTL philosophy could be a problem. I assume the preference would be to use the real router where possible, but that brings things back to square one.
If we don’t want
renderto beasyncthen we will not be able to do this for the user. I suppose we just expose a method and document it well.Maybe we should just expose the entire router - that seems useful. Eg:
Although this may not fit with the VTL philosophy. I think this idea (expose some kind of router key) is probably the way to go.