const assert = require('node:assert/strict') const fs = require('node:fs') const path = require('node:path') const test = require('node:test') const ts = require('typescript') const source = fs.readFileSync(path.join(__dirname, '../src/utils/im-chat-archive-trigger.ts'), 'utf8') const compiled = ts.transpileModule(source, { compilerOptions: { module: ts.ModuleKind.CommonJS } }).outputText const mod = { exports: {} } new Function('module', 'exports', compiled)(mod, mod.exports) const { createImChatArchiveTrigger } = mod.exports const deferred = () => { let resolve, reject const promise = new Promise((a, b) => { resolve = a; reject = b }) return { promise, resolve, reject } } test('all pages use server-owned current-doctor scope and carry the continuation token', async () => { const calls = [] const sync = createImChatArchiveTrigger(async params => { calls.push(params) return { completed: calls.length === 3, sync_token: 'next-page' } }) await sync(12116) assert.deepEqual(calls, [ { diagnosis_id: 12116, scope: 'current', sync_token: undefined }, { diagnosis_id: 12116, scope: 'current', sync_token: 'next-page' }, { diagnosis_id: 12116, scope: 'current', sync_token: 'next-page' } ]) }) test('many events while syncing coalesce, then perform one catch-up scan for new messages', async () => { const page = deferred() let calls = 0 const sync = createImChatArchiveTrigger(() => { calls++ return calls === 1 ? page.promise : Promise.resolve({ completed: true }) }) const first = sync(10) assert.equal(sync(10), first) assert.equal(sync(10), first) assert.equal(calls, 1) page.resolve({ completed: true }) await first assert.equal(calls, 2) await sync(10) assert.equal(calls, 3) }) test('switching patients keeps in-flight requests bound to their original diagnosis', async () => { const old = deferred(), calls = [] const sync = createImChatArchiveTrigger(params => { calls.push(params) if (params.diagnosis_id === 10 && !params.sync_token) return old.promise return Promise.resolve({ completed: true }) }) const first = sync(10) await sync(20) old.resolve({ completed: false, sync_token: 'old-patient' }) await first assert.deepEqual(calls.map(p => [p.diagnosis_id, p.sync_token]), [[10, undefined], [20, undefined], [10, 'old-patient']]) }) test('partial failure and network failure are reported and do not poison later retries', async () => { const warnings = [] let count = 0 const sync = createImChatArchiveTrigger(async () => { count++ if (count === 1) return { completed: true, errors: ['cloud unavailable'] } if (count === 2) throw new Error('request timeout') return { completed: true } }, error => warnings.push(error.message)) await sync(10) await sync(10) await sync(10) assert.deepEqual(warnings, ['cloud unavailable', 'request timeout']) assert.equal(count, 3) }) test('invalid IDs never request and missing progress stops a malformed response loop', async () => { const warnings = [] let count = 0 const sync = createImChatArchiveTrigger(async () => { count++; return { completed: false } }, error => warnings.push(error.message)) for (const id of [0, -1, NaN, 1.5]) await sync(id) assert.equal(count, 0) await sync(10) assert.equal(count, 1) assert.match(warnings[0], /未返回进度/) })