Files
codex-register/tests/test_batch_websocket_fallback.cjs
2026-03-24 12:15:21 +08:00

134 lines
3.2 KiB
JavaScript

const test = require('node:test');
const assert = require('node:assert/strict');
const fs = require('node:fs');
const vm = require('node:vm');
const APP_JS_PATH = '/Users/zhoukailian/.config/superpowers/worktrees/codex-manager/repro-batch-monitor/static/js/app.js';
function createElementStub() {
return {
style: {},
dataset: {},
value: '',
checked: false,
disabled: false,
innerHTML: '',
textContent: '',
className: '',
appendChild() {},
addEventListener() {},
removeEventListener() {},
querySelector() {
return createElementStub();
},
querySelectorAll() {
return [];
},
closest() {
return null;
},
};
}
function createSandbox() {
const sandbox = {
console,
setTimeout,
clearTimeout,
setInterval: () => 1,
clearInterval: () => {},
Event: class Event {
constructor(type) {
this.type = type;
}
},
document: {
getElementById() {
return createElementStub();
},
createElement() {
return createElementStub();
},
addEventListener() {},
querySelector() {
return createElementStub();
},
querySelectorAll() {
return [];
},
},
sessionStorage: {
getItem() {
return null;
},
setItem() {},
removeItem() {},
},
toast: {
info() {},
success() {},
warning() {},
error() {},
},
api: {
get() {
throw new Error('api.get should not be called in this test');
},
post() {
throw new Error('api.post should not be called in this test');
},
},
window: null,
WebSocket: null,
};
sandbox.window = sandbox;
sandbox.window.location = { protocol: 'http:', host: '127.0.0.1:8003' };
vm.createContext(sandbox);
vm.runInContext(fs.readFileSync(APP_JS_PATH, 'utf8'), sandbox, { filename: 'app.js' });
return sandbox;
}
async function runFallback(mode) {
const sandbox = createSandbox();
vm.runInContext(
`
var __calls = [];
currentBatch = { batch_id: 'test-batch' };
isOutlookBatchMode = ${mode === 'outlook' ? 'true' : 'false'};
batchCompleted = false;
batchFinalStatus = null;
startOutlookBatchPolling = function(batchId) { __calls.push(['outlook', batchId]); };
startBatchPolling = function(batchId) { __calls.push(['batch', batchId]); };
WebSocket = function(url) {
this.url = url;
this.readyState = 0;
setTimeout(() => {
if (this.onerror) {
this.onerror({ type: 'error' });
}
}, 0);
};
WebSocket.OPEN = 1;
connectBatchWebSocket('test-batch');
`,
sandbox,
);
await new Promise((resolve) => setTimeout(resolve, 20));
return JSON.parse(vm.runInContext('JSON.stringify(__calls)', sandbox));
}
test('normal batch websocket fallback uses standard batch polling', async () => {
const calls = await runFallback('batch');
assert.deepEqual(calls, [['batch', 'test-batch']]);
});
test('outlook batch websocket fallback uses outlook polling', async () => {
const calls = await runFallback('outlook');
assert.deepEqual(calls, [['outlook', 'test-batch']]);
});