unit-testing - vue test utils
Cómo escribir una prueba que simula el objeto $ route en componentes vue (10)
Tengo un componente que contiene una declaración como this.$route.fullPath
, ¿cómo debo fullPath
valor de fullPath
del objeto $route
si quiero probar ese componente?
Agregando a la gran respuesta de @SColvin, aquí hay un ejemplo de este trabajo usando 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
})
})
Creo que esto debería funcionar también con vue-test-utils .
Eche un vistazo a este ejemplo utilizando vue-test-utils, donde me burlo tanto del enrutador como de la tienda.
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>`
)
})
})
El método más fácil que encontré es usar 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)
});
});
¡¡¡Espero eso ayude!!!
Esto es lo que he estado haciendo según este artículo :
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'');
});
La forma más fácil que he encontrado es burlarse de la ruta $.
it(''renders $router.name'', () => {
const $route = {
name: ''test name - avoriaz''
}
const wrapper = shallow(Component, {
mocks: {
$route
}
})
expect(wrapper.text()).to.equal($route.name)
})
Lo mejor es no vue-router
sino usarlo para renderizar el componente, de esa forma obtendrá un enrutador que funcione correctamente. Ejemplo:
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()
})
})
})
Cosas a tener en cuenta:
- Estoy usando la versión solo en tiempo de ejecución de vue, por
render: h => h(''router-view'')
tantorender: h => h(''router-view'')
. - Solo estoy probando el componente
totest
, pero es posible que se requieran otros si están referenciados portotest
por ejemplo.another_component
en este ejemplo. - Necesita
nextTick
para que el HTML se haya procesado antes de poder verlo / probarlo.
Uno de los problemas es que la mayoría de los ejemplos que encontré se refieren a la versión anterior de vue-router
, consulte la documentación de migraciones , por ejemplo. algunos ejemplos usan router.go()
que ahora no funciona.
Ninguna respuesta me ayudó, así que profundizo en la documentación de vue-test-utils
y encontré una respuesta funcional, por lo que necesitas importar.
import { shallowMount,createLocalVue } from ''@vue/test-utils'';
import router from ''@/router.ts'';
const localVue = createLocalVue();
Creamos una instancia de vue
muestra. Mientras realiza las pruebas, debe usar shallowMount
para poder proporcionar una instancia de aplicación vue
y un enrutador.
describe(''Components'', () => {
it(''renders a comment form'', () => {
const COMMENTFORM = shallowMount(CommentForm,{
localVue,
router
});
})
})
Usted puede pasar fácilmente al enrutador y al montaje superficial, y no le da el error. Si quieres pasar la tienda utilizas:
import { shallowMount,createLocalVue } from ''@vue/test-utils'';
import router from ''@/router.ts'';
import store from ''@/store.ts'';
const localVue = createLocalVue();
Y luego pasar la tienda:
describe(''Components'', () => {
it(''renders a comment form'', () => {
const COMMENTFORM = shallowMount(CommentForm,{
localVue,
router,
store
});
})
})
Esta solución resolvió los siguientes errores:
- No se puede leer la propiedad ''params'' de undefined al usar
this.$route.params.id
- Elemento personalizado desconocido
router-link
✔
No estoy de acuerdo con la respuesta principal: puedes burlarte de $route
sin ningún problema.
Por otro lado, la instalación de vue-router varias veces en el constructor base le causará problemas. Agrega $route
y $router
como propiedades de solo lectura. Lo que hace que sea imposible sobrescribirlos en futuras pruebas.
Hay dos maneras de lograr esto con vue-test-utils .
Burlándose de vue-router con la opción de mocks
const $route = {
fullPath: ''full/path''
}
const wrapper = mount(ComponentWithRouter, {
mocks: {
$route
}
})
wrapper.vm.$route.fullPath // ''full/path''
También puede instalar Vue Router de forma segura utilizando createLocalVue:
Instalar vue-router de forma segura en las pruebas con 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'')
Puede simularse con vm. $ Router configurando vm._routerRoot._router
Por ejemplo
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!
Puede verificar su código fuente aquí: https://github.com/vuejs/vue-router/blob/dev/dist/vue-router.js#L558
Todas las felicitaciones a @SColvin por su respuesta; Ayudé a encontrar una respuesta en mi escenario donde tenía un componente con un enrutador-enlace que estaba lanzando un
ERROR: ''[Vue warn]: Error in render function: (found in <RouterLink>)''
durante la prueba de unidad porque a Vue no se le había suministrado un enrutador. Usando la respuesta de @SColvin para volver a escribir la prueba originalmente suministrada por vue-cli desde
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'');
});
a
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'');
});
});
Sin necesidad de pasar parámetros a la vista, podría simplificar el componente como el procesamiento predeterminado, sin necesidad de empujar y sin necesidad de esperar el siguiente clic. HTH alguien más!