使用 Jest 在 Vue 中为组件中的方法编写单元测试

Posted

技术标签:

【中文标题】使用 Jest 在 Vue 中为组件中的方法编写单元测试【英文标题】:Write unit test for a method in a component in Vue with Jest 【发布时间】:2021-09-05 17:57:36 【问题描述】:

我开始使用 Jest Vue 进行单元测试。我想测试一个 Vue 组件中的现有方法,我写了一个测试但它没有通过。而且我不知道如何在测试中模拟和调用该方法。

如何编写一个好的单元测试,以传递 'goPage()' 方法的功能?

我的方法是:

goPage(id, name, categoryId) 
   this.headerSearchInput = name
   this.$router.push(
      path: '/categories/' + categoryId + '/courses/' + id,
      query:  query: this.headerSearchInput ,
   )

我的测试是:

import  shallowMount, createLocalVue  from '@vue/test-utils'
import HeaderSearch from '../../components/header/HeaderSearch.vue'

const localVue = createLocalVue()
localVue.use(VueRouter)
const router = new VueRouter()

describe('Header search component', () => 
   const mockRoute = 
      path: '/categories/' + 2 + '/courses/' + 4,
      query: 
        query: searchedText,
      ,
   
   const mockRouter = 
      push: jest.fn(),
   
   const wrapper = shallowMount(HeaderSearch, 
      router,
      localVue,
      stubs: 
        NuxtLink: true,
      ,
      global: 
        mocks: 
          $route: mockRoute,
          $router: mockRouter,
        ,
      ,
   )
   test('redirect to course page, goPage', async () => 
      const courseId = 4
      const courseTitle = 'Inbound Marketing'
      const categoryId = 2

      const mockedFunction = jest.fn()
      wrapper.vm.goPage(courseId, courseTitle, categoryId)
      await wrapper.setData(
        headerSearchInput: courseTitle,
      )
      const expectedRouter = 
        path: '/categories/3/courses/4',
        query:  query: wrapper.vm.headerSearchInput ,
      
      expect(mockedFunction).toBeCalledWith(courseId, courseTitle, categoryId)
      expect(wrapper.vm.$router.path).toEqual(expectedRouter.path)
   )
)

【问题讨论】:

【参考方案1】:

当您测试路由时,您应该只使用模拟而不在您的 local Vue 实例上安装 VueRouter。正如官方documentation 所说:

在 localVue 上安装 Vue 路由器还会将 $route 和 $router 作为只读属性添加到 localVue。这意味着在使用安装了 Vue Router 的 localVue 安装组件时,您不能使用 mocks 选项覆盖 $route 和 $router。

所以你需要在shallowMount 调用中获取localVue 的reed,只留下$router 嘲笑:

然后在测试中,您只需调用您的 goPage 方法并检查 $router.push() 是否使用特定参数调用。 不检查 $route.path 是否已更改,将其留给端到端测试。

let wrapper
describe('HelloWorld.vue', () => 
  beforeEach(() => 
    wrapper = shallowMount(HelloWorld, 
      global:  mocks:  $router:  push: jest.fn()   
    )
  )

  test('redirect to course page, goPage', async () => 
    const courseId = 4
    const courseTitle = 'Inbound Marketing'
    const categoryId = 2
    const expectedRouter = 
      path: '/categories/' + categoryId + '/courses/' + courseId,
      query:  query: 'Inbound Marketing' 
    
    wrapper.vm.goPage(courseId, courseTitle, categoryId)
    expect(wrapper.vm.$router.push).toBeCalledWith(expectedRouter)
  )
)

【讨论】:

我像你说的那样写了测试,但是它抛出了Cannot read property 'push' of undefined 错误。我该如何解决? @爱德华多 请提供带有包装器实例化的测试代码。 代码很长,所以我用2个cmets来写。 const wrapper = shallowMount(HeaderSearch, stubs: NuxtLink: true, , global: mocks: $router: push: jest.fn(), , , , ) test('redirect to course page, goPage', async () => const courseId = 4 const courseTitle = 'Inbound Marketing' const categoryId = 2 const expectedRouter = path: '/categories/' + categoryId + '/courses/' + courseId, query: query: wrapper.vm.headerSearchInput , wrapper.vm.goPage(courseId, courseTitle, categoryId) await wrapper.setData( headerSearchInput: courseTitle, ) expect(wrapper.vm.$router.push).toBeCalledWith(expectedRouter) ) 我已经更新了我的答案,请检查一下。【参考方案2】:

我解决了我的问题,如下所示:

let wrapper
describe('HeaderSearch', () => 
   const $route = 
     path: '/categories/2/courses/4',
   
   const $router = 
     push: jest.fn(),
   
   beforeEach(() => 
   wrapper = shallowMount(HeaderSearch, 
      mocks: 
        $route,
        $router,
      ,
  )
)

test('go to each course page', () => 
  const courseId = 4
  const categoryId = 2
  const courseTitle = 'Inbound Marketing'

  wrapper.vm.goPage(courseId, courseTitle, categoryId)
  const expectedRouter = 
    path: '/categories/' + categoryId + '/courses/' + courseId,
    query:  query: courseTitle ,
  
  expect(wrapper.vm.$router.push).toBeCalledWith(expectedRouter)
  )
)

【讨论】:

以上是关于使用 Jest 在 Vue 中为组件中的方法编写单元测试的主要内容,如果未能解决你的问题,请参考以下文章

使用 <script setup> 时无法使用 Jest 访问 Vue 单文件组件中的方法

Vue Test Utils / Jest - 如何测试是不是在组件方法中调用了类方法

Vue 组合 API + Jest

用 jest 测试 Vue 过滤器

Vue & Jest。子组件发出事件时调用测试方法

使用 Jest 运行测试时,为啥 Trix 编辑器不会安装在 Vue 组件中?