2 回答

TA貢獻1812條經驗 獲得超5個贊
我的函數以“即發即忘”的方式調用私有異步函數,并且不添加任何錯誤處理。
不要那樣做。
外部庫處理所有未捕獲的承諾拒絕。在生產中,我希望 shell 來處理它,所以我不想在函數本身中處理它。
不要依賴這個外部庫。
您應該在函數中使用自己的全局錯誤處理函數。
在生產中,讓該錯誤處理函數簡單地重新拋出異常,以便環境能夠捕獲該異常,或者更好的是,如果可能的話,直接調用 shell 錯誤處理函數。
在測試中,您可以模擬自己的全局處理程序,并斷言它是使用預期參數調用的。

TA貢獻1835條經驗 獲得超7個贊
processAction是同步的并且不知道 Promise,這會導致懸空的 Promise。懸空承諾永遠不應該拒絕,因為這會導致未經處理的拒絕,這是一種例外。根據環境的不同,這可能會導致應用程序崩潰。即使異常是全局處理的,這也不應該成為不處理預期錯誤的理由。
正確的方法是在fetchTheThing拒絕發生的地方明確抑制拒絕:
private async fetchTheThing() {
try {
...
} catch {} finally {
this.isFetching = false;
}
}
或者在這種情況下,它更像processAction是導致懸而未決的承諾:
this.fetchTheThing().catch(() => {});
否則將調度未處理的拒絕事件。
如果沒有的話,可以通過監聽事件來測試:
...
let onRej = jest.fn();
process.once('unhandledRejection', onRej);
rej();
await Promise.sleep();
expect(onRej).toBeCalled();
expect(store.isFetching).toBe(false);
如果已經有另一個監聽器,這將無法按預期工作unhandledRejection,這在良好的 Jest 設置中是可以預期的。如果是這種情況,唯一不會影響其他測試的解決方法是在測試之前重置它們并在測試之后重新添加:
let listeners;
beforeEach(() => {
listeners = process.rawListeners('unhandledRejection');
process.removeAllListeners('unhandledRejection');
});
afterEach(() => {
(typeof listeners === 'function' ? [listeners] : listeners).forEach(listener => {
process.on('unhandledRejection', listener);
});
})
不建議這樣做,使用時應自行承擔風險,因為這表明錯誤處理存在更深層次的問題,而在正確設計的 JavaScript 應用程序中通常不可接受。
添加回答
舉報