在从 vuex 操作返回的承诺中测试 VueJS 方法
Testing VueJS method inside of a promise which is returned from a vuex action
我有一个 Vue 组件,它使用来自 vuex 存储的映射操作,returns 这是一个承诺。当组件调用mapped action,并且mapped action resolve时,我在调用另一个vue方法vm.$router.push()
。我想断言 push
方法被调用。这是我的组件、测试和我创建的一些辅助方法,用于使用 vuex 和 vue-router 分出组件。
这是我的 .vue
组件,其中包含一些 console.logs 来跟踪正在发生的事情。
<template>
<div>
<button @click="promise" class="click-promise">Promise</button>
</div>
</template>
<script>
import { mapActions } from 'vuex'
export default {
methods: {
...mapActions(['promiseAction']),
promise(){
const vm = this
vm.$router.push('/some/route')
console.log('before promiseAction')
console.log(vm.promiseAction())
return vm.promiseAction().then(function (response) {
console.log('inside promiseAction')
vm.$router.push('/some/other/route')
})
}
}
}
</script>
这是我的测试。我正在使用 Mocha、Karma、Chai 和 jquery-chia
import Testing from '@/components/Testing'
describe('Testing.vue', () => {
const mount = componentHelper(Testing)
it.only('assert something in a promise returned from an action', () => {
const promise = new Promise(resolve => resolve('success'))
const promiseAction = stubAction('promiseAction').returns(promise)
const vm = mount()
const routerPush = sinon.spy(vm.$router, 'push')
$('.click-promise').click()
expect(promiseAction).to.have.been.called
expect(routerPush).to.have.been.calledWith('/some/route') //this passes
return vm.$nextTick(() => {
console.log('inside nextTick')
expect(routerPush).to.have.been.calledWith('/some/other/routes') //this never happens
})
})
})
这是我的助手文件。我不确定这是否 100% 必要,但我想在 post
中包含所有内容
import Vue from 'vue'
import Vuex from 'vuex'
import VueRouter from 'vue-router'
Vue.use(Vuex)
Vue.use(VueRouter)
let div
beforeEach(() => {
// create a dom element for the component to mount to
div = document.createElement('div')
document.body.appendChild(div)
})
afterEach(() => {
// clean up the document nodes after each test
Array.prototype.forEach.call(document.querySelectorAll('body *:not([type="text/javascript"])'), node => {
node.parentNode.removeChild(node)
})
})
// stub out a store config object
const storeConfig = {
actions: {}
}
/**
* Set up a function that will attach the mock store to the component
* and mount the component to the test div element
*
* Use like this:
* const mount = componentHelper(YourComponent)
* do some setup
* call mount() to instantiate the mocked component
*
* @param component
* @returns {function()}
*/
window.componentHelper = function (component) {
const router = new VueRouter({})
return () => {
// 1. attaches the stubbed store to the component
component.store = new Vuex.Store(storeConfig)
component.router = router
// 2. mounts the component to the dom element
// 3. returns the vue instance
return new Vue(component).$mount(div)
}
}
/**
* Creates an action to be added to the fake store
* returns a sinon stub which can be asserted against
* @param actionName
*/
window.stubAction = (actionName) => {
// 1. create a stub
const stub = sinon.stub()
// 2. create the action function that will be placed in the store and add it to the store
storeConfig.actions[actionName] = function (context, ...args) {
// 3. when this action is called it will call the stub
// return the stub so you can assert against the stubbed return value
// example: stubAction('fakeAction').returns('xyz')
return stub(...args)
}
// 4. return the stub that was placed in the return of the action for assertions
return stub
}
当我运行这个测试这就是我得到的。
LOG LOG: 'before promiseAction'
LOG LOG: Promise{_c: [], _a: undefined, _s: 1, _d: true, _v: 'success', _h: 0, _n: true}
Testing.vue
✓ assert something in a promise returned from an action
PhantomJS 2.1.1 (Linux 0.0.0): Executed 1 of 4 SUCCESS (0.045 secs / 0.018 secs)
TOTAL: 1 SUCCESS
=============================== Coverage summary ===============================
Statements : 31.58% ( 6/19 )
Branches : 100% ( 0/0 )
Functions : 0% ( 0/2 )
Lines : 31.58% ( 6/19 )
================================================================================
LOG LOG: 'inside nextTick'
ERROR LOG: '[Vue warn]: Error in nextTick: "AssertionError: expected push to have been called with arguments /some/other/routes
/some/route /some/other/routes "
(found in <Root>)'
ERROR LOG: AssertionError{message: 'expected push to have been called with arguments /some/other/routes
/some/route /some/other/routes ', showDiff: false, actual: push, expected: undefined, stack: undefined, line: 210, sourceURL: 'http://localhost:9877/absolute/home/doug/Code/projects/vue-testing-sandbox/node_modules/chai/chai.js?ab7cf506d9d77c111c878b1e10b7f25348630760'}
LOG LOG: 'inside promiseAction'
如您所见,测试通过了,但是 promise 中的代码在测试完成之前不会 运行。我说的是这一段
return vm.promiseAction().then(function (response) {
console.log('inside promiseAction')
vm.$router.push('/some/other/route')
})
我也注销了promise函数console.log(vm.promiseAction())
,你可以看到它是你所期望的。
如何才能得到测试等待承诺?我认为 nextTick
可能是答案,但它似乎不起作用。
感谢您的帮助。
没有一种非常好的方法可以通过单击按钮来执行您想要的操作。此外,我不确定是否真的值得通过单击按钮对其进行测试。如果 Vue 的事件处理程序不能正常工作,你会遇到更大的问题。
相反,我建议您只调用 promise
方法并在从该方法返回的 promise 的成功回调中执行测试。
//execute the handler
const test = vm.promise()
// test that the pre-async actions occured
expect(promiseAction).to.have.been.called
expect(routerPush).to.have.been.calledWith('/some/route')
// test the post-async action occurred
return test.then(() => {
expect(routerPush).to.have.been.calledWith('/some/other/routes')
})
我有一个 Vue 组件,它使用来自 vuex 存储的映射操作,returns 这是一个承诺。当组件调用mapped action,并且mapped action resolve时,我在调用另一个vue方法vm.$router.push()
。我想断言 push
方法被调用。这是我的组件、测试和我创建的一些辅助方法,用于使用 vuex 和 vue-router 分出组件。
这是我的 .vue
组件,其中包含一些 console.logs 来跟踪正在发生的事情。
<template>
<div>
<button @click="promise" class="click-promise">Promise</button>
</div>
</template>
<script>
import { mapActions } from 'vuex'
export default {
methods: {
...mapActions(['promiseAction']),
promise(){
const vm = this
vm.$router.push('/some/route')
console.log('before promiseAction')
console.log(vm.promiseAction())
return vm.promiseAction().then(function (response) {
console.log('inside promiseAction')
vm.$router.push('/some/other/route')
})
}
}
}
</script>
这是我的测试。我正在使用 Mocha、Karma、Chai 和 jquery-chia
import Testing from '@/components/Testing'
describe('Testing.vue', () => {
const mount = componentHelper(Testing)
it.only('assert something in a promise returned from an action', () => {
const promise = new Promise(resolve => resolve('success'))
const promiseAction = stubAction('promiseAction').returns(promise)
const vm = mount()
const routerPush = sinon.spy(vm.$router, 'push')
$('.click-promise').click()
expect(promiseAction).to.have.been.called
expect(routerPush).to.have.been.calledWith('/some/route') //this passes
return vm.$nextTick(() => {
console.log('inside nextTick')
expect(routerPush).to.have.been.calledWith('/some/other/routes') //this never happens
})
})
})
这是我的助手文件。我不确定这是否 100% 必要,但我想在 post
中包含所有内容import Vue from 'vue'
import Vuex from 'vuex'
import VueRouter from 'vue-router'
Vue.use(Vuex)
Vue.use(VueRouter)
let div
beforeEach(() => {
// create a dom element for the component to mount to
div = document.createElement('div')
document.body.appendChild(div)
})
afterEach(() => {
// clean up the document nodes after each test
Array.prototype.forEach.call(document.querySelectorAll('body *:not([type="text/javascript"])'), node => {
node.parentNode.removeChild(node)
})
})
// stub out a store config object
const storeConfig = {
actions: {}
}
/**
* Set up a function that will attach the mock store to the component
* and mount the component to the test div element
*
* Use like this:
* const mount = componentHelper(YourComponent)
* do some setup
* call mount() to instantiate the mocked component
*
* @param component
* @returns {function()}
*/
window.componentHelper = function (component) {
const router = new VueRouter({})
return () => {
// 1. attaches the stubbed store to the component
component.store = new Vuex.Store(storeConfig)
component.router = router
// 2. mounts the component to the dom element
// 3. returns the vue instance
return new Vue(component).$mount(div)
}
}
/**
* Creates an action to be added to the fake store
* returns a sinon stub which can be asserted against
* @param actionName
*/
window.stubAction = (actionName) => {
// 1. create a stub
const stub = sinon.stub()
// 2. create the action function that will be placed in the store and add it to the store
storeConfig.actions[actionName] = function (context, ...args) {
// 3. when this action is called it will call the stub
// return the stub so you can assert against the stubbed return value
// example: stubAction('fakeAction').returns('xyz')
return stub(...args)
}
// 4. return the stub that was placed in the return of the action for assertions
return stub
}
当我运行这个测试这就是我得到的。
LOG LOG: 'before promiseAction'
LOG LOG: Promise{_c: [], _a: undefined, _s: 1, _d: true, _v: 'success', _h: 0, _n: true}
Testing.vue
✓ assert something in a promise returned from an action
PhantomJS 2.1.1 (Linux 0.0.0): Executed 1 of 4 SUCCESS (0.045 secs / 0.018 secs)
TOTAL: 1 SUCCESS
=============================== Coverage summary ===============================
Statements : 31.58% ( 6/19 )
Branches : 100% ( 0/0 )
Functions : 0% ( 0/2 )
Lines : 31.58% ( 6/19 )
================================================================================
LOG LOG: 'inside nextTick'
ERROR LOG: '[Vue warn]: Error in nextTick: "AssertionError: expected push to have been called with arguments /some/other/routes
/some/route /some/other/routes "
(found in <Root>)'
ERROR LOG: AssertionError{message: 'expected push to have been called with arguments /some/other/routes
/some/route /some/other/routes ', showDiff: false, actual: push, expected: undefined, stack: undefined, line: 210, sourceURL: 'http://localhost:9877/absolute/home/doug/Code/projects/vue-testing-sandbox/node_modules/chai/chai.js?ab7cf506d9d77c111c878b1e10b7f25348630760'}
LOG LOG: 'inside promiseAction'
如您所见,测试通过了,但是 promise 中的代码在测试完成之前不会 运行。我说的是这一段
return vm.promiseAction().then(function (response) {
console.log('inside promiseAction')
vm.$router.push('/some/other/route')
})
我也注销了promise函数console.log(vm.promiseAction())
,你可以看到它是你所期望的。
如何才能得到测试等待承诺?我认为 nextTick
可能是答案,但它似乎不起作用。
感谢您的帮助。
没有一种非常好的方法可以通过单击按钮来执行您想要的操作。此外,我不确定是否真的值得通过单击按钮对其进行测试。如果 Vue 的事件处理程序不能正常工作,你会遇到更大的问题。
相反,我建议您只调用 promise
方法并在从该方法返回的 promise 的成功回调中执行测试。
//execute the handler
const test = vm.promise()
// test that the pre-async actions occured
expect(promiseAction).to.have.been.called
expect(routerPush).to.have.been.calledWith('/some/route')
// test the post-async action occurred
return test.then(() => {
expect(routerPush).to.have.been.calledWith('/some/other/routes')
})