Files
zyt/admin/tests/im-chat-archive-trigger.test.cjs
T
2026-09-09 15:47:48 +08:00

90 lines
3.4 KiB
JavaScript

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], /未返回进度/)
})