简体   繁体   English

如何对 Vue 应用程序中的嵌套操作进行单元测试?

[英]How to unit test nested Actions in a Vue application?

I have a TypeScript-based Vue project with Jest as a test framework.我有一个以Jest作为测试框架的基于 TypeScript 的 Vue 项目。 I have Actions in a Module which I am trying to test.我正在尝试测试的模块中有操作。

My Actions look like this:我的操作如下所示:

  @Action({})
  saveSomeData (payload: any): Promise<any> {
    const { isActive, id, routes } = payload
    return this.context.dispatch('otherModule/createId', '', { root: true })
        .then((id: string) => {
          payload = { isActive, id, routes, type: 'postRoutes' }
          return this.context.dispatch('submitRoutes', payload)
        })
  }

  @Action({})
  submitRoutes (payload: any): Promise<any> {
    const { isActive, id, routes, type } = payload
    return ActiveService.setActive(id)
        .then(() => this.context.dispatch(type, { id, routes }))
  }

Here is how my test looks like:这是我的测试的样子:

// Mocking createId in otherModule module to return ID
jest.mock('@/store/modules/otherModule', () => ({
  createId: jest.fn(() => Promise.resolve([
    {
      id: 'someId'
    }
  ]))
}))

...

describe('Testing save MyModule data', () => {
    let store: any

    beforeEach(() => {
      store = new Vuex.Store({
        modules: {
          myModule,
          otherModule
        }
      })
    })

    test('Should call createId and then call submitRoutes if ID is empty', async () => {
      const payload = {
        isActive: true,
        id: '',
        routes: []
      }
      const pld = {
        isActive: true,
        id: 'someId',
        routes: [],
        type: 'postRoutes'
      }

      store.dispatch = jest.fn()
      await store.dispatch('myModule/saveSomeData', payload)
      expect(store.dispatch).toHaveBeenCalledWith('myModule/saveSomeData', payload)
      expect(store.dispatch).toHaveBeenCalledWith('otherModule/createId') // <-- here I get an error
      expect(store.dispatch).toHaveBeenCalledWith('myModule/submitRoutes', pld)
    })
  })

Problem: My test fails and I haven't found any way to make it work.问题:我的测试失败了,我还没有找到任何方法让它工作。

The error:错误:

Error: expect(jest.fn()).toHaveBeenCalledWith(...expected)

Expected: "otherModule/createId"
Received: "myModule/saveSomeData", {"id": "", "isActive": true, "routes": []}

Number of calls: 1

What I've tried我试过的

I've followed the Vuex documentation together with Jest , I also tried different solutions from the internet - unfortunately no luck.我和Jest一起关注了Vuex文档,我还尝试了来自互联网的不同解决方案 - 不幸的是没有运气。

I would appreciate any help.我将不胜感激任何帮助。

store.dispatch = jest.fn() makes dispatch function a no-op, it isn't expected to call saveSomeData and, therefore, dispatch other actions. store.dispatch = jest.fn()使调度 function 成为无操作,它不应该调用saveSomeData ,因此调度其他操作。

This assertion isn't useful because it basically tests the previous line:这个断言没有用,因为它基本上测试了前一行:

expect(store.dispatch).toHaveBeenCalledWith('myModule/saveSomeData', payload)

store.dispatch spy or stub isn't supposed to affect context.dispatch in actions because the context is created on store initialization and already uses original dispatch . store.dispatch spy 或 stub 不应该影响操作中的context.dispatch ,因为上下文是在商店初始化时创建的并且已经使用原始dispatch It may be unnecessary to do this because these are actions that should be tested, not Vuex itself.可能没有必要这样做,因为这些是应该测试的操作,而不是 Vuex 本身。

Actions can be spied on module level with jest.mock and jest.requireActual , or locally on Vuex module object if necessary.可以使用jest.mockjest.requireActual在模块级别监视操作,或者在必要时在 Vuex 模块 object 上本地监视操作。 Module spies and mocks should happen on top level.模块间谍和模拟应该发生在顶层。 Object spies and mocks should happen prior to store instantiation. Object 间谍和模拟应该在存储实例化之前发生。

In this case a tested units are myModule actions, ActiveService.setActive and otherModule/createId can be considered different units and should be mocked.在这种情况下,测试的单元是myModule操作, ActiveService.setActiveotherModule/createId可以被认为是不同的单元并且应该被模拟。 If postRoutes contains side effects, they can be mocked as well.如果postRoutes包含副作用,它们也可以被模拟。

jest.spyOn(otherModule.actions, 'createId');
jest.spyOn(ActiveService, 'setActive');
store = new Vuex.Store(...)

...

otherModule.actions.createId.mockValue(Promise.resolve('stubbedId'));
ActiveService.setActive.mockValue(Promise.resolve());
await store.dispatch('myModule/saveSomeData', payload)
// assert otherModule.actions.createId call
// assert ActiveService.setActive call
// assert otherModule.actions.postRoutes call

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM