Javascript 如何在promise.finally()中测试promise的状态,而无需在生产代码中等待它

Javascript 如何在promise.finally()中测试promise的状态,而无需在生产代码中等待它,javascript,promise,jestjs,try-catch-finally,Javascript,Promise,Jestjs,Try Catch Finally,我在生产代码中使用(或在async函数中尝试catch finally)执行一些后续代码,而不更改当前承诺的解决/拒绝状态 然而,在我的玩笑测试中,我想检测finally块中的承诺没有被拒绝 编辑:但我不想实际等待我的“生产”代码中的承诺(在那里,我只关心catch重新抛出的错误,而不关心finally中的错误) 我如何测试它?或者至少是如何模仿Promise.prototype来拒绝当前的承诺 例如,如果我要测试reduxaction创建者,即使有未处理承诺拒绝的消息,测试也会通过: tes

我在生产代码中使用(或在
async
函数中尝试catch finally)执行一些后续代码,而不更改当前承诺的解决/拒绝状态

然而,在我的玩笑测试中,我想检测finally块中的承诺没有被拒绝

编辑:但我不想实际等待我的“生产”代码中的承诺(在那里,我只关心catch重新抛出的错误,而不关心finally中的错误)

我如何测试它?或者至少是如何模仿Promise.prototype来拒绝当前的承诺

例如,如果我要测试
redux
action创建者,即使有未处理承诺拒绝的消息,测试也会通过:

test(“最终”,异步()=>{
const actions=await dispatchMock(add(“forgottenParent”,{a:1}));
const newState=actions.reduce(reducer,未定义);
expect(newState).toEqual({});
});
const dispatchMock=async thunk=>{…};
//----简化的“生产”代码-----
const reducer=(state={},action)=>state;
const add=parentId=>async dispatch=>{
调度(“添加启动”);
试一试{
等待someFetch(“someData”);
发送(“添加成功”);
}捕获(e){
发送(“添加失败”);
投掷e;
}最后{
dispatch(get(parentId));//如果此处的承诺被拒绝,则测试通过
}
};
const get=id=>async dispatch=>{
调度(“启动”);
试一试{
等待取数(id);
发送(“获得成功”);
}捕获(e){
调度(“获取失败”);
投掷e;
}
};
const someFetch=async id=>{
如果(id==“被遗忘的父母”){
抛出新错误(“想象我忘记模拟这个请求”);
}
承诺。解决(id);
};
在那一行没有例外
get(parentId)
可能会返回一个被拒绝的承诺(或稍后将被拒绝的挂起承诺),但这不是一个例外,不会影响控制流

你可能在找

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));
//  ^^^^^
  }
};

请注意。

编辑:更多通用解决方案可在


可以将承诺存储在某个仅用于测试的辅助函数中可访问的变量中,例如:

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()
});

您是说在
get
内部还是
dispatch
内部引发异常?如果在正常(同步)和
async
/
wait
中最终在
内部引发异常(而不是在使用承诺方法链接时)应该在顶层
await
重新抛出异常,除非它在两者之间的某个地方被吞没。如果您看到异常被默默地吞噬,我建议在JavaScript调试器中使用“在所有抛出的异常上中断”(或类似命名的选项)。默认情况下,大多数JS调试器仅因_未处理u/uncaught异常而中断。希望通过这种方式,您可以看到它在哪里被抓到和吞下。@Dai它被扔到
get
的catch block by
throw e
中。不,不,它是按照规范工作的,从外部承诺的已解决状态来看,内部的异常被忽略=>它被
最终
本身吞没了,这是正确的行为(但我想在我的测试中改变这种行为)-参见“测试”选项卡和“问题”子选项卡在链接的代码上执行Sandbox只是为了清楚起见,将在顶层重新引发异常。但它不会拒绝承诺,也不会使异步测试失败。等待被拒绝的承诺最终不会改变已解决的外部承诺。。。我知道这不是一个最佳实践,这就是为什么我想测试它不会发生=>如果它发生,我需要测试失败happens@Aprillion我无法复制<代码>异步函数示例({try{throw new Error(“internal”);}最终{wait Promise.reject(new Error(“outer”);}
肯定会以外部错误拒绝,并忽略内部错误。内部无throw
try
plz-
异步函数示例({try{return 1}最终{wait Promise.reject(new Error(“outer”);}}}
@Aprillion不管
try
块做什么-它总是从
最后抛出
外部
错误,并拒绝
示例()
,即使
返回1test("finally", async () => {
  ...
  // but I want to fail the test if the Promise from finally is rejected
  await _getPromiseFromFinallyInTests()
});