




























@@ -407,7 +407,92 @@ describe("web auto-reply connection", () => {
407407socket.ws.emit("frame");
408408await vi.advanceTimersByTimeAsync(20);
409409}
410+await vi.waitFor(
411+() => {
412+expect(scripted.getListenerCount()).toBeGreaterThanOrEqual(2);
413+},
414+{ timeout: 250, interval: 2 },
415+);
416+417+controller.abort();
418+scripted.resolveClose(scripted.getListenerCount() - 1, {
419+status: 499,
420+isLoggedOut: false,
421+error: "aborted",
422+});
423+await Promise.resolve();
424+await run;
425+} finally {
426+vi.useRealTimers();
427+}
428+});
429+430+it("publishes frame-driven transport activity for quiet sessions", async () => {
431+vi.useFakeTimers();
432+try {
433+const sleep = vi.fn(async () => {});
434+const statuses: Array<Record<string, unknown>> = [];
435+const scripted = createScriptedWebListenerFactory();
436+const { controller, run } = startWebAutoReplyMonitor({
437+monitorWebChannelFn: monitorWebChannel as never,
438+listenerFactory: scripted.listenerFactory,
439+ sleep,
440+heartbeatSeconds: 1,
441+transportTimeoutMs: 60_000,
442+messageTimeoutMs: 60_000,
443+watchdogCheckMs: 5,
444+statusSink: (next) => statuses.push({ ...next }),
445+});
446+447+await vi.waitFor(
448+() => {
449+expect(scripted.getListenerCount()).toBe(1);
450+},
451+{ timeout: 250, interval: 2 },
452+);
453+454+const initialTransportAt = Number(statuses.at(-1)?.lastTransportActivityAt ?? 0);
455+const socket = getLastWebAutoReplySessionSocket();
456+await vi.advanceTimersByTimeAsync(250);
457+socket.ws.emit("frame");
458+await vi.advanceTimersByTimeAsync(1_000);
459+460+const lastTransportAt = Number(statuses.at(-1)?.lastTransportActivityAt ?? 0);
461+expect(lastTransportAt).toBeGreaterThan(initialTransportAt);
462+463+controller.abort();
464+scripted.resolveClose(0, { status: 499, isLoggedOut: false, error: "aborted" });
465+await Promise.resolve();
466+await run;
467+} finally {
468+vi.useRealTimers();
469+}
470+});
410471472+it("reconnects on transport stall before the long app-silence window", async () => {
473+vi.useFakeTimers();
474+try {
475+const sleep = vi.fn(async () => {});
476+const scripted = createScriptedWebListenerFactory();
477+const { controller, run } = startWebAutoReplyMonitor({
478+monitorWebChannelFn: monitorWebChannel as never,
479+listenerFactory: scripted.listenerFactory,
480+ sleep,
481+heartbeatSeconds: 1,
482+transportTimeoutMs: 30,
483+messageTimeoutMs: 3_000,
484+watchdogCheckMs: 5,
485+});
486+487+await vi.waitFor(
488+() => {
489+expect(scripted.getListenerCount()).toBe(1);
490+},
491+{ timeout: 250, interval: 2 },
492+);
493+494+await vi.advanceTimersByTimeAsync(36);
495+await Promise.resolve();
411496await vi.waitFor(
412497() => {
413498expect(scripted.getListenerCount()).toBeGreaterThanOrEqual(2);
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。