【发布时间】:2020-05-22 09:38:47
【问题描述】:
我有一个 Vue 按钮单击处理程序,它基于它所接受的参数,可以:
- 只调用请求A
- 只调用请求 B
- 调用请求A和B - 但它应该一个接一个地调用它们(如果请求A成功返回,则调用请求B。基本上,实现不能使用
Promise.all())。
我的问题是我不知道如何使用 Jest 对“依次调用 A 和 B”行为进行单元测试。
实施
这是事件处理程序,它在单击按钮后运行:
const loadA = this.$store.dispatch['loadA']; //note these are FUNCTIONS THAT RETURNS A PROMISE
const loadB = this.$store.dispatch['loadB'];
async makeRequests(shouldMakeRequestA, shouldMakeRequestB) {
const requests = [];
if(shouldMakeRequestA) requests.push(loadA);
if(shouldMakeRequestB) requests.push(loadB);
for(const request in requests) {
await request(); //waits for request to return before calling for second one
}
}
测试
正确的测试用例应该:
-
失败❌当:
-
实现同时调用两个请求,例如:
() => { Promise.all([loadA(), loadB()]) }() => { loadA(); loadB() }
-
-
通过✔️何时:
- 实现调用 loadA,等待它的 promise 解决,然后调用 loadB,例如:
() => {await loadA(); await loadB();}
- 实现调用 loadA,等待它的 promise 解决,然后调用 loadB,例如:
这是我对我描述的测试用例的看法,但它似乎很容易受到竞争条件的影响,而且我假设的同事很难理解。
//component.spec.js
import MyCustomButton from '@/components/MyCustomButton.vue'
import TheComponentWeAreTesting from '@/components/TheComponentWeAreTesting'
describe('foo', () => {
const resolveAfterOneSecond = () => new Promise(r => setTimeout(r, 1000));
let wrapper;
const loadA = jest.fn(resolveAfterOneSecond);
const loadB = jest.fn(resolveAfterOneSecond);
beforeEach(() => {
wrapper = shallowMount(TheComponentWeAreTesting, store: new Vuex.Store({actions: {loadA, loadB}});
})
it('runs A and B one after the other', async () => {
wrapper.find(MyCustomButton).vm.$emit('click');
/*
One of the major problems with my approach is that
I don't know how much time has passed after I await $nextTick.
Both requests resolve after 2000 ms total (as mocked above with setTimeout)
But how much time has passed after $nextTick is resolved?
700ms? 1300? 1999ms?
*/
await wrapper.vm.$nextTick();
/*
Because I don't know how much time did it take for $nextTick to resolve
I need to wait a few extra ms so the test passes at all
Basically, you have to take my word for it that "500ms" is the value that makes the test pass
*/
awat new Promise(r => setTimeout(r, 500));
const callCount = loadA.mock.calls.length + loadB.mock.calls.length;
expect(callCount).toBe(1); //expect first request to have been sent out, but the second one shouldn't be sent out yet at this point
}
}
有没有更好的方法来测试这种行为?我知道例如jest.advanceTimersByTime,但这会提前所有计时器,而不是当前计时器。
【问题讨论】:
标签: javascript unit-testing vue.js jestjs vue-test-utils