Vuex:使用 API 调用测试操作

Posted

技术标签:

【中文标题】Vuex:使用 API 调用测试操作【英文标题】:Vuex: Testing actions with API calls 【发布时间】:2017-05-22 18:49:24 【问题描述】:

我一直在遵循these 测试指南来测试我的 vuex 商店。 但是当我谈到动作部分时,我觉得有很多我无法理解的事情。

第一部分是这样的:

// actions.js
import shop from '../api/shop'

export const getAllProducts = ( commit ) => 
  commit('REQUEST_PRODUCTS')
  shop.getProducts(products => 
    commit('RECEIVE_PRODUCTS', products)
  )

// actions.spec.js

// use require syntax for inline loaders.
// with inject-loader, this returns a module factory
// that allows us to inject mocked dependencies.
import  expect  from 'chai'
const actionsInjector = require('inject!./actions')

// create the module with our mocks
const actions = actionsInjector(
  '../api/shop': 
    getProducts (cb) 
      setTimeout(() => 
        cb([ /* mocked response */ ])
      , 100)
    
  
)

我推断这是在操作内部模拟服务。

接下来的部分是:

// helper for testing action with expected mutations
const testAction = (action, payload, state, expectedMutations, done) => 
  let count = 0

  // mock commit
  const commit = (type, payload) => 
    const mutation = expectedMutations[count]
    expect(mutation.type).to.equal(type)
    if (payload) 
      expect(mutation.payload).to.deep.equal(payload)
    
    count++
    if (count >= expectedMutations.length) 
      done()
    
  

  // call the action with mocked store and arguments
  action( commit, state , payload)

  // check if no mutations should have been dispatched
  if (expectedMutations.length === 0) 
    expect(count).to.equal(0)
    done()
  


describe('actions', () => 
  it('getAllProducts', done => 
    testAction(actions.getAllProducts, null, , [
       type: 'REQUEST_PRODUCTS' ,
       type: 'RECEIVE_PRODUCTS', payload:  /* mocked response */  
    ], done)
  )
)

这是我难以理解的地方。

我的商店看起来像:

import * as NameSpace from '../NameSpace'
import  ParseService  from '../../Services/parse'

const state = 
  [NameSpace.AUTH_STATE]: 
    auth: ,
    error: null
  


const getters = 
  [NameSpace.AUTH_GETTER]: state => 
    return state[NameSpace.AUTH_STATE]
  


const mutations = 
  [NameSpace.AUTH_MUTATION]: (state, payload) => 
    state[NameSpace.AUTH_STATE] = payload
  


const actions = 
  [NameSpace.ASYNC_AUTH_ACTION]: ( commit , payload) => 
    ParseService.login(payload.username, payload.password)
      .then((user) => 
        commit(NameSpace.AUTH_MUTATION, auth: user, error: null)
      )
      .catch((error) => 
        commit(NameSpace.AUTH_MUTATION, auth: [], error: error)
      )
  


export default 
  state,
  getters,
  mutations,
  actions

这就是我要测试的方式:

import * as NameSpace from 'src/store/NameSpace'
import AuthStore from 'src/store/modules/authorization'
const actionsInjector = require('inject!../../../../../src/store/modules/authorization')
// This file is present at: test/unit/specs/store/modules/authorization.spec.js 
// src and test are siblings


describe('AuthStore Actions', () => 
  const injectedAction = actionsInjector(
    '../../Services/parse': 
      login (username, password) 
        return new Promise((resolve, reject) => 
          setTimeout(() => 
            if (Math.random() > 0.5) 
              resolve()
             else 
              reject()
            
          , 300)
        )
      
    
  )

  it('Gets the user profile if the username and password matches', () => 
    const testAction = (action, payload, state, mutations, done) => 
      const commit = (payload) => 
        if (payload) 
          expect(mutations.payload).to.deep.equal(payload)
        
      
      action( commit, state , payload)
        .then(result => 
          expect(state).to.deep.equal(auth: result, error: null)
        )
        .catch(error => 
          expect(state).to.deep.equal(auth: [], error: error)
        )
    
    testAction(injectedAction.login, null, , [])
  )
)

如果我尝试这样做,我会得到:

"Gets the user profile if the username and password matches"
undefined is not a constructor (evaluating 'action( commit: commit, state: state , payload)')
"testAction@webpack:///test/unit/specs/store/modules/authorization.spec.js:96:13 <- index.js:26198:14
webpack:///test/unit/specs/store/modules/authorization.spec.js:104:15 <- index.js:26204:16"

我需要帮助了解我应该做什么来测试这些操作。

【问题讨论】:

【参考方案1】:

我知道这已经有一段时间了,但我遇到了这个问题,因为我遇到了类似的问题。如果你在调用 testAction 之前 console.log injectionActions,你会看到 injectionAction 对象实际上是这样的:

Objectdefault: ObjectFUNC_NAME: function FUNC_NAME(_ref) ...

所以这里的主要解决方案是将 testAction 调用更改为:

testAction(injectedAction.default.login, null, , [], done)

因为您将您的操作导出为商店中的默认设置。

与您的特定错误无关的其他一些问题...您不需要操作 testAction 样板代码。只要您传入正确的参数,它就会按预期工作。此外,请务必将 done 传递给 testAction,否则您的测试将超时。希望这可以帮助遇到此问题的其他人!

【讨论】:

我还没有测试过这个,真的很忙。我会尽快接受你的回答。

以上是关于Vuex:使用 API 调用测试操作的主要内容,如果未能解决你的问题,请参考以下文章

测试是不是使用特定参数(来自组件)调用了 Vuex 操作

异步api调用后如何使用vuex getter

如何在 Vuex 的操作中使用 axios 获取 Rest API 数据?

返回承诺的 Vuex 操作永远不会解析或拒绝

如何使用 vuex 和 typescript 将 axios 调用移动到自己的方法中

Vuex 在开始时从 API 调用中填充数据