Unit testing 如何编写模拟vue组件中$route对象的测试

Unit testing 如何编写模拟vue组件中$route对象的测试,unit-testing,sinon,vue-component,vuejs2,vue-loader,Unit Testing,Sinon,Vue Component,Vuejs2,Vue Loader,我有一个包含如下语句的组件:this.$route.fullPath,如果我想测试该组件,我应该如何模拟$route对象的fullPath的值?最好不要模拟vue router,而是使用它来渲染该组件,这样你就可以得到一个正常工作的路由器。例如: 从“Vue”导入Vue 从“vue路由器”导入VueRouter 从“src/components/totest”导入totest 描述('totest.vue',()=>{ 它('should totest renders stuff',done=>

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

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

从“Vue”导入Vue
从“vue路由器”导入VueRouter
从“src/components/totest”导入totest
描述('totest.vue',()=>{
它('should totest renders stuff',done=>{
Vue.use(VueRouter)
const router=new VueRouter({路由:[
{path:'/totest/:id',name:'totest',component:totest},
{path:'/where',name:'other_component',component:{render:h=>'-'},
]})
const vm=新的Vue({
el:document.createElement('div'),
路由器:路由器,,
render:h=>h('router-view')
})
push({name:'totest',params:{id:123}})
Vue.nextTick(()=>{
log('html:',vm.$el)
expect(vm.$el.querySelector('h2').textContent).to.equal('Fred Bloggs'))
完成()
})
})
})
注意事项:

  • 我使用的是仅运行时版本的vue,因此
    render:h=>h('router-view')
  • 我只测试
    totest
    组件,但是如果
    totest
    引用了其他组件,则可能需要其他组件,例如本例中的
    另一个组件
  • 在查看/测试HTML之前,需要
    nextTick
    ,才能呈现HTML

  • 其中一个问题是,我发现的大多数示例都提到了旧版本的
    vue路由器
    ,请参见,例如,一些示例使用了
    router.go()
    ,但现在不起作用。

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

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


    不需要将参数传递到视图中,我可以将组件简化为默认渲染,无需推送,也无需等待下一步。还有其他人

    我不同意上面的答案-你可以毫无疑问地模仿
    $route

    另一方面,在基本构造函数上多次安装vue路由器将导致出现问题。它将
    $route
    $router
    添加为只读属性。这使得在将来的测试中不可能覆盖它们

    有两种方法可以实现这一点

    const$route={
    完整路径:“完整/路径”
    }
    const wrapper=mount(ComponentWithRouter,{
    模拟:{
    $route
    } 
    })
    wrapper.vm.$route.fullPath/'full/path'
    
    您还可以使用createLocalVue安全地安装Vue路由器:

    在测试中使用安全安装vue路由器

    const localVue=createLocalVue()
    localVue.use(VueRouter)
    常数路由=[
    {
    路径:“/”,
    组件:组件
    }
    ]
    常量路由器=新的VueRouter({
    路线
    })
    const wrapper=mount(ComponentWithRouter,{localVue,router})
    expect(wrapper.vm.route).to.be.an('对象')
    
    除了@SColvin的精彩答案之外,下面是一个使用以下方法的示例:


    我相信这也可以用。

    看看这个使用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>`
        )
      })
    })
    
    从“@/components/ArticleDetails”导入ArticleDetails
    从“vue测试utils”导入{mount}
    从“@/router”导入路由器
    描述('ArticleDetails.vue',()=>{
    它('应显示帖子详细信息',()=>{
    const POST_MESSAGE='我们内容的标题!'
    const示例_POST={
    标题:“标题”,
    日期:“2016年5月6日”,
    内容:`${POST#u MESSAGE}`
    }
    const wrapper=mount(ArticleDetails{
    路由器,
    模拟:{
    $store:{
    吸气剂:{
    getPostById(){
    返回示例\u POST
    }
    }
    }
    }
    })
    expect(wrapper.vm.$el.querySelector('h1.post title').textContent.trim())to.equal(例如_post.title)
    expect(wrapper.vm.$el.querySelector('time').textContent.trim())到.equal(例如_POST.date)
    expect(wrapper.vm.$el.querySelector('.post-content').innerHTML.trim()).to.equal(
    `${POST_MESSAGE}`
    )
    })
    })
    
    这就是我一直在做的:


    通过设置vm.\u routerRoot.\u 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!
    

    您可以在这里仔细检查他们的源代码:

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

    it('renders $router.name', () => {
      const $route = {
        name: 'test name - avoriaz'
      }
    
    
     const wrapper = shallow(Component, {
        mocks: {
          $route
        }
      })
      expect(wrapper.text()).to.equal($route.name)
    })
    

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

    希望对你有帮助

    没有答案对我有帮助,所以我深入研究了
    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
    • 未知自定义元素
      路由器链接

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

    使用
    VueRouter
    阅读localVue用法:

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

    解决方法

    //萨姆威科
    import { shallowMount,createLocalVue } from '@vue/test-utils';
    import router from '@/router.ts';
    const localVue = createLocalVue();
    
    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
        });
      })
    })
    
    <template>
    ... something
    </template>
    <script>
    ...
    data () {
      return {
        authenticated: false
      }
    },
    ...
    created () {
      if(!this.authenticated && this.$route.path !== '/'){
        this.$router.push('/')
      }
    }
    </script>
    
    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
    })
    
    let routerPushSpy = jest.spyOn(wrapper.vm.$router, 'push') // or before hooks, etc
    
    import { shallowMount } from '@vue/test-utils'
    
    const $route = {
      path: '/some/path'
    }
    
    const wrapper = shallowMount(Component, {
      mocks: {
        $route
      }
    })
    
    wrapper.vm.$route.path // /some/path
    
    ...
    
    mocks: {
      $route: {fullPath: ''}
    },
    
    ...