55 lines
2.4 KiB
JavaScript
55 lines
2.4 KiB
JavaScript
// Exercise the actual browser request function with a deterministic fake clock.
|
|
'use strict';
|
|
const assert = require('node:assert/strict');
|
|
const fs = require('node:fs');
|
|
const path = require('node:path');
|
|
const vm = require('node:vm');
|
|
const source = fs.readFileSync(path.join(__dirname, '../js/app.js'), 'utf8');
|
|
const start = source.indexOf(' var ANALYZE_TIMEOUT_MS =');
|
|
const end = source.indexOf(' /* ─── SkinScore viewModel', start);
|
|
assert(start >= 0 && end > start);
|
|
function setup() {
|
|
let timer, complete, signal, result;
|
|
const ctx = { IS_MOCK: false, camSeq: 1, AbortController, CaptureQuality: require('../js/capture-quality'), captureDiagnostics: [],
|
|
setTimeout(fn, delay) { timer = { fn, delay }; return 1; },
|
|
clearTimeout() { timer = null; },
|
|
fetch(url, options) {
|
|
assert.equal(url, 'api/skin-analyze');
|
|
signal = options.signal;
|
|
return new Promise((resolve, reject) => {
|
|
complete = () => resolve({ json: async () => ({ ok: true, report_saved: true }) });
|
|
signal.addEventListener('abort', () => { const e = new Error('aborted'); e.name = 'AbortError'; reject(e); });
|
|
});
|
|
}
|
|
};
|
|
vm.createContext(ctx);
|
|
vm.runInContext(source.slice(start, end), ctx);
|
|
ctx.requestAnalyze(['front', 'left', 'right'], 1, {}, (...args) => { result = args; });
|
|
return { ctx, get timer() { return timer; }, get signal() { return signal; },
|
|
get result() { return result; }, finish() { complete(); } };
|
|
}
|
|
const flush = () => new Promise(resolve => setImmediate(resolve));
|
|
(async () => {
|
|
const delayed = setup();
|
|
assert.equal(delayed.timer.delay, 150000);
|
|
assert(delayed.timer.delay > 60000 * 2 + 4000, 'Allow both backend attempts plus retry wait');
|
|
delayed.finish();
|
|
await flush();
|
|
assert.equal(delayed.result[0], null);
|
|
assert.equal(delayed.result[1].report_saved, true);
|
|
assert.equal(delayed.timer, null);
|
|
assert.equal(delayed.signal.aborted, false);
|
|
const expired = setup();
|
|
expired.timer.fn();
|
|
await flush();
|
|
assert(expired.signal.aborted);
|
|
assert.match(expired.result[0], /检测服务开小差/);
|
|
const canceled = setup();
|
|
canceled.ctx.camSeq++;
|
|
canceled.finish();
|
|
await flush();
|
|
assert.equal(canceled.result, undefined);
|
|
assert.equal(canceled.timer, null);
|
|
console.log('PASS: frontend timeout covers backend retry budget; success, timeout, stale response, timer cleanup');
|
|
})().catch(e => { console.error(e); process.exitCode = 1; });
|