36

我有一个包含类似语句的组件,如果我想测试该组件,我this.$route.fullPath应该如何模拟对象的值fullPath$route

4

12 回答 12

47

我不同意最佳答案-您可以$route毫无问题地嘲笑。

另一方面,在基础构造函数上多次安装 vue-router会给你带来问题。它添加$route$router作为只读属性。这使得在未来的测试中无法覆盖它们。

使用vue-test-utils有两种方法可以实现这一点。

使用mocks 选项模拟 vue-router

const $route = {
    fullPath: 'full/path'
}
const wrapper = mount(ComponentWithRouter, { 
  mocks: {
    $route
  } 
})

wrapper.vm.$route.fullPath // 'full/path'

您还可以使用 createLocalVue 安全地安装 Vue Router:

使用createLocalVue在测试中安全安装 vue-router

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')
于 2017-06-18T20:43:32.437 回答
40

最好不要模拟vue-router,而是使用它来渲染组件,这样你就可以获得一个正常工作的路由器。例子:

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()
    })
  })
})

注意事项:

  1. 我正在使用仅运行时版本的 vue,因此render: h => h('router-view').
  2. 我只是在测试该totest组件,但如果它们被totest例如引用,则可能需要其他组件。another_component在这个例子中。
  3. 您需要nextTick先呈现 HTML,然后才能查看/测试它。

问题之一是我发现的大多数示例都引用了旧版本vue-router,请参阅迁移文档,例如。一些示例使用router.go()现在不起作用。

于 2017-01-08T15:47:20.993 回答
7

没有答案可以帮助我,所以我深入研究了vue-test-utils文档并发现自己是一个有效的答案,所以你需要导入。

import { shallowMount,createLocalVue } from '@vue/test-utils';
import router from '@/router.ts';
const localVue = createLocalVue();

我们创建了一个示例vue实例。在测试时您需要使用shallowMount,以便您可以提供vue应用程序实例和路由器。

describe('Components', () => {
  it('renders a comment form', () => {
    const COMMENTFORM = shallowMount(CommentForm,{
      localVue,
      router
    });
  })
})

您可以轻松地通过路由器和浅层安装,它不会给您错误。如果您想通过商店,请使用:

import { shallowMount,createLocalVue } from '@vue/test-utils';
import router from '@/router.ts';
import store from '@/store.ts';
const localVue = createLocalVue();

然后通过商店:

describe('Components', () => {
  it('renders a comment form', () => {
    const COMMENTFORM = shallowMount(CommentForm,{
      localVue,
      router,
      store
    });
  })
})

此解决方案解决了以下错误:

  • 使用时无法读取未定义的属性“参数”this.$route.params.id
  • 未知的自定义元素router-link

✔</p>

于 2018-12-06T08:36:36.513 回答
3

我发现最简单的方法是使用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);
  });
});

希望能帮助到你!!!

于 2018-10-13T16:44:31.203 回答
2

您不必专门“模拟”路由器。您的应用程序可以在全局 vue 范围内设置 VueRouter,您仍然可以让它在您的测试中做您想做的事情而不会出现问题。

阅读 localVue 用法VueRouterhttps ://vue-test-utils.vuejs.org/guides/#using-with-vue-router 。

我目前正在从我们的主应用程序中拉入一个复杂的路由器,并且能够在创建组件之前jest.spyOn()调用router.push()并设置路径,以便在挂钩中运行shallowMount()某些路由处理。created()

解决方法

// 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
})

上面的想法是我需要在创建/安装$route之前更改状态。假设您可以创建包装器并希望基于其他状态或操作SomeVueComponent.vue来测试组件,您可以随时监视实例this.$router.push('/something')wrapper.vm

let routerPushSpy = jest.spyOn(wrapper.vm.$router, 'push') // or before hooks, etc

在撰写本文时,似乎存在一个开放缺陷,它使以下内容无法正常工作,因为vm.$route将始终未定义,使上述唯一选项(我知道)因为没有其他方法可以“模拟”,$route因为安装 VueRouter 写道只读属性$route

来自 vue-test-utils 文档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

如果您对这里感兴趣的是该问题的 github 链接:https ://github.com/vuejs/vue-test-utils/issues/1136

于 2019-03-08T23:53:24.573 回答
1

为什么所有的答案都那么复杂?你可以这样做:

...
wrapper = mount(HappyComponent, {
  mocks: {
    $route: {fullPath: ''}
  },
})
...
于 2020-12-17T15:33:49.253 回答
1

感谢@SColvin 的回答;在我的场景中帮助找到了答案,其中我有一个带有路由器链接的组件正在抛出一个

ERROR: '[Vue warn]: Error in render function: (found in <RouterLink>)'

在单元测试期间,因为没有为 Vue 提供路由器。使用@SColvin 答案重写最初由 vue-cli 提供的测试

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');
  });

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');
  });
});

不需要将参数传递给视图,我可以将组件简化为默认渲染,无需推送,无需等待 nextTick。HTH 别人!

于 2017-04-09T21:45:38.880 回答
0

您可以通过设置vm._routerRoot._router来模拟vm.$router

例如

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!

你可以在这里仔细检查他们的源代码:https ://github.com/vuejs/vue-router/blob/dev/dist/vue-router.js#L558

于 2018-03-26T22:05:59.627 回答
0

我发现最简单的方法是模拟 $route。

it('renders $router.name', () => {
  const $route = {
    name: 'test name - avoriaz'
  }


 const wrapper = shallow(Component, {
    mocks: {
      $route
    }
  })
  expect(wrapper.text()).to.equal($route.name)
})
于 2018-09-06T08:51:03.633 回答
0

看看这个使用 vue-test-utils 的例子,我在其中模拟了路由器和存储。

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>`
    )
  })
})
于 2017-11-04T13:52:29.393 回答
0

这就是我根据这篇文章一直在做的事情:

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');
});
于 2017-12-12T22:36:27.923 回答
0

除了@SColvin 的出色回答之外,这是一个使用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
  })
})

我相信这也应该适用于vue-test-utils

于 2017-09-13T15:41:31.697 回答