Files
Genarrative/apps/ai-game-creator-shell/tests/unhandledRejectionBridge.test.ts
T
k88936 06a4f9346f unhandledrejection 测试桥只吞被 window 侧消费的拒绝
- 合成事件的 reason 改为访问器:有监听方读过就算有人接手;没人读则交回安装前的监听器(含 vitest 失败上报)
- 新增 unhandledRejectionBridge.test.ts 钉住两条路径:无人接手会交回、window 读过则不再交回
- 避免桥把无关的未处理拒绝静默吞掉
2026-10-01 21:15:03 +08:00

74 lines
2.5 KiB
TypeScript

// @vitest-environment jsdom
/**
* jsdom `unhandledrejection` 桥的「只吞被消费的拒绝」语义。
*
* 桥接管 Node 监听器是为了让组件能收到 window 事件;但没人消费的拒绝必须交回原监听器,
* 否则用例会静默吞掉真实的未处理拒绝。
*/
import { afterEach, expect, test } from 'vitest';
import { installUnhandledRejectionBridge } from './unhandledRejectionBridge';
const installed: Array<() => void> = [];
const processListeners: Array<(reason: unknown, promise: unknown) => void> = [];
const windowListeners: Array<(event: Event) => void> = [];
let parkedListeners: Array<(reason: unknown, promise: unknown) => void> = [];
afterEach(() => {
while (installed.length > 0) installed.pop()?.();
while (processListeners.length > 0) {
process.removeListener('unhandledRejection', processListeners.pop()!);
}
while (windowListeners.length > 0) {
window.removeEventListener('unhandledrejection', windowListeners.pop()!);
}
for (const listener of parkedListeners) {
process.on('unhandledRejection', listener);
}
parkedListeners = [];
});
/** 停放 vitest 自己的监听器,好观察「交回原监听器」而不触发用例失败上报。 */
function parkProcessListeners() {
parkedListeners = process.listeners('unhandledRejection');
process.removeAllListeners('unhandledRejection');
}
function trackProcessListener() {
const forwarded: unknown[] = [];
const listener = (reason: unknown) => {
forwarded.push(reason);
};
processListeners.push(listener);
process.on('unhandledRejection', listener);
return forwarded;
}
test('没人读 reason 的拒绝会交回原监听器', () => {
parkProcessListeners();
const forwarded = trackProcessListener();
installed.push(installUnhandledRejectionBridge());
const reason = new Error('意外的拒绝');
process.emit('unhandledRejection', reason, Promise.resolve());
expect(forwarded).toEqual([reason]);
});
test('window 侧读过 reason 的拒绝不再交回原监听器', () => {
const forwarded = trackProcessListener();
const consumed: unknown[] = [];
const listener = (event: Event) => {
consumed.push((event as Event & { reason?: unknown }).reason);
};
windowListeners.push(listener);
window.addEventListener('unhandledrejection', listener);
installed.push(installUnhandledRejectionBridge());
const reason = new Error('已接手的拒绝');
process.emit('unhandledRejection', reason, Promise.resolve());
expect(consumed).toEqual([reason]);
expect(forwarded).toEqual([]);
});