我在生产代码中使用Promise.protype.finally(((或在async
函数中尝试catch finally(来执行一些后续代码,而不更改当前Promise的解析/拒绝状态。
然而,在我的Jest测试中,我想检测finally块中的Promise没有被拒绝。
edit:但我不想在我的"生产";代码(在那里,我只关心catch中重新抛出的错误,而不关心finally中的错误(。
我该如何测试?或者至少如何模拟Promise.原型来拒绝来自finally的异常上的当前Promise?
例如,如果我要测试redux
操作创建者,即使有关于未处理的Promise拒绝的消息,测试也会通过:
https://codesandbox.io/s/reverent-dijkstra-nbcno?file=/src/index.test.js
test("finally", async () => {
const actions = await dispatchMock(add("forgottenParent", { a: 1 }));
const newState = actions.reduce(reducer, undefined);
expect(newState).toEqual({});
});
const dispatchMock = async thunk => {...};
// ----- simplified "production" code -----
const reducer = (state = {}, action) => state;
const add = parentId => async dispatch => {
dispatch("add start");
try {
await someFetch("someData");
dispatch("add success");
} catch (e) {
dispatch("add failed");
throw e;
} finally {
dispatch(get(parentId)); // tests pass if the promise here is rejected
}
};
const get = id => async dispatch => {
dispatch("get start");
try {
await someFetch(id);
dispatch("get success");
} catch (e) {
dispatch("get failed");
throw e;
}
};
const someFetch = async id => {
if (id === "forgottenParent") {
throw new Error("imagine I forgot to mock this request");
}
Promise.resolve(id);
};
dispatch(get(parentId)); // tests pass if an exception is thrown here
该行没有异常抛出。get(parentId)
可能返回一个被拒绝的promise(或稍后将被拒绝的挂起promise(,但这不是例外,不会影响控制流。
你可能正在寻找
const add = parentId => async dispatch => {
dispatch("add start");
try {
await someFetch("someData");
dispatch("add success");
} catch (e) {
dispatch("add failed");
throw e;
} finally {
await dispatch(get(parentId));
// ^^^^^
}
};
请注意,从finally
块抛出异常并不完全是最佳实践。
edit:上提供了更通用的解决方案https://stackoverflow.com/a/58634792/1176601
可以将Promise存储在某个辅助函数中可访问的变量中,该函数仅用于测试,例如:
export const _getPromiseFromFinallyInTests = () => _promiseFromFinally
let _promiseFromFinally
const add = parentId => async dispatch => {
...
} finally {
// not awaited here because I don't want to change the current Promise
_promiseFromFinally = dispatch(get(parentId));
}
};
并更新测试以等待测试仅承诺:
test("finally", async () => {
...
// but I want to fail the test if the Promise from finally is rejected
await _getPromiseFromFinallyInTests()
});