57 lines
2.4 KiB
TypeScript
57 lines
2.4 KiB
TypeScript
import assert from 'node:assert/strict'
|
|
import fs from 'node:fs'
|
|
import test from 'node:test'
|
|
|
|
import { shouldReplayRealtimeEvents } from './realtime-event-service.js'
|
|
|
|
/**
|
|
* 回归:整页刷新后大厅列表重复、可抢订单数越刷越多。
|
|
*
|
|
* 根因是新连接(lastEventId=0)也会补发最近 500 条历史事件。大厅 upsert 广播带的是
|
|
* 当时的工单快照,被重新打进刚加载的列表后,已抢走/已出队的订单会复活并被插到第 1 页,
|
|
* 前端还会按「插入行」把 pagination.total 加一。
|
|
*/
|
|
test('新连接(lastEventId=0)不补发历史事件,避免旧大厅快照复活订单', () => {
|
|
assert.equal(shouldReplayRealtimeEvents(0), false)
|
|
assert.equal(shouldReplayRealtimeEvents(Number.NaN), false)
|
|
assert.equal(shouldReplayRealtimeEvents(-1), false)
|
|
})
|
|
|
|
test('断线重连(带 Last-Event-ID)才补发事件', () => {
|
|
assert.equal(shouldReplayRealtimeEvents(1), true)
|
|
assert.equal(shouldReplayRealtimeEvents(3993659), true)
|
|
})
|
|
|
|
test('补发窗口取最新的一段,而不是最旧的一段', () => {
|
|
const source = fs.readFileSync(
|
|
new URL('../../repositories/realtime-event-repo.ts', import.meta.url),
|
|
'utf8',
|
|
)
|
|
const block = source.slice(
|
|
source.indexOf('export async function listRealtimeEventsAfter('),
|
|
source.indexOf('\n}', source.indexOf('export async function listRealtimeEventsAfter(')),
|
|
)
|
|
assert.ok(block.length > 0, 'listRealtimeEventsAfter 片段必须存在')
|
|
assert.ok(
|
|
/ORDER BY id DESC\s+LIMIT \$2\s+\)\s*replay_window\s+ORDER BY id ASC/s.test(block),
|
|
'补发必须「内层 id DESC 取最新 N 条、外层 id ASC 回放」;否则断线久了窗口会停在旧事件上',
|
|
)
|
|
})
|
|
|
|
test('补发窗口溢出时改为让客户端整体重拉', () => {
|
|
const source = fs.readFileSync(new URL('./realtime-event-service.ts', import.meta.url), 'utf8')
|
|
const replayBlock = source.slice(
|
|
source.indexOf('async function replayEvents('),
|
|
source.indexOf('function mapStoredEvent('),
|
|
)
|
|
assert.ok(replayBlock.length > 0, 'replayEvents 片段必须存在')
|
|
assert.ok(
|
|
replayBlock.includes('events.length >= REALTIME_REPLAY_EVENT_LIMIT'),
|
|
'补发窗口被拿满时必须判定为溢出,不能继续逐条套用旧快照',
|
|
)
|
|
assert.ok(
|
|
replayBlock.includes("'resync'"),
|
|
'溢出时要给客户端发 resync,让列表整体重拉(接口才是权威数据源)',
|
|
)
|
|
})
|