@@ -18,6 +18,7 @@ async function withFakeTimers(run: () => Promise<void>) {
|
18 | 18 | } finally { |
19 | 19 | vi.clearAllTimers(); |
20 | 20 | vi.useRealTimers(); |
| 21 | +vi.restoreAllMocks(); |
21 | 22 | } |
22 | 23 | } |
23 | 24 | |
@@ -62,8 +63,11 @@ describe("createTypingCallbacks", () => {
|
62 | 63 | }); |
63 | 64 | |
64 | 65 | afterEach(() => { |
65 | | -vi.clearAllTimers(); |
| 66 | +if (vi.isFakeTimers()) { |
| 67 | +vi.clearAllTimers(); |
| 68 | +} |
66 | 69 | vi.useRealTimers(); |
| 70 | +vi.restoreAllMocks(); |
67 | 71 | }); |
68 | 72 | |
69 | 73 | it("invokes start on reply start", async () => { |
@@ -211,15 +215,19 @@ describe("createTypingCallbacks", () => {
|
211 | 215 | |
212 | 216 | it("clamps oversized keepalive intervals before arming timers", async () => { |
213 | 217 | await withFakeTimers(async () => { |
214 | | -const setIntervalSpy = vi.spyOn(globalThis, "setInterval"); |
215 | | -const { callbacks } = createTypingHarness({ |
| 218 | +const { start, callbacks } = createTypingHarness({ |
216 | 219 | keepaliveIntervalMs: Number.MAX_SAFE_INTEGER, |
| 220 | +maxDurationMs: 0, |
217 | 221 | }); |
218 | 222 | |
219 | 223 | await callbacks.onReplyStart(); |
220 | 224 | await flushMicrotasks(); |
221 | 225 | |
222 | | -expect(setIntervalSpy).toHaveBeenCalledWith(expect.any(Function), MAX_TIMER_TIMEOUT_MS); |
| 226 | +expect(vi.getTimerCount()).toBe(1); |
| 227 | +await vi.advanceTimersByTimeAsync(MAX_TIMER_TIMEOUT_MS - 1); |
| 228 | +expect(start).toHaveBeenCalledTimes(1); |
| 229 | +await vi.advanceTimersByTimeAsync(1); |
| 230 | +expect(start).toHaveBeenCalledTimes(2); |
223 | 231 | callbacks.onCleanup?.(); |
224 | 232 | }); |
225 | 233 | }); |
@@ -387,15 +395,23 @@ describe("createTypingCallbacks", () => {
|
387 | 395 | |
388 | 396 | it("clamps oversized TTLs before arming timers", async () => { |
389 | 397 | await withFakeTimers(async () => { |
390 | | -const setTimeoutSpy = vi.spyOn(globalThis, "setTimeout"); |
391 | | -const { callbacks } = createTypingHarness({ |
| 398 | +const consoleWarn = vi.spyOn(console, "warn").mockImplementation(() => {}); |
| 399 | +const { stop, callbacks } = createTypingHarness({ |
| 400 | +keepaliveIntervalMs: 0, |
392 | 401 | maxDurationMs: Number.MAX_SAFE_INTEGER, |
393 | 402 | }); |
394 | 403 | |
395 | 404 | await callbacks.onReplyStart(); |
396 | 405 | await flushMicrotasks(); |
397 | 406 | |
398 | | -expect(setTimeoutSpy).toHaveBeenCalledWith(expect.any(Function), MAX_TIMER_TIMEOUT_MS); |
| 407 | +expect(vi.getTimerCount()).toBe(1); |
| 408 | +await vi.advanceTimersByTimeAsync(MAX_TIMER_TIMEOUT_MS - 1); |
| 409 | +expect(stop).not.toHaveBeenCalled(); |
| 410 | +await vi.advanceTimersByTimeAsync(1); |
| 411 | +expect(stop).toHaveBeenCalledTimes(1); |
| 412 | +expect(consoleWarn).toHaveBeenCalledWith( |
| 413 | +`[typing] TTL exceeded (${MAX_TIMER_TIMEOUT_MS}ms), auto-stopping typing indicator`, |
| 414 | +); |
399 | 415 | callbacks.onCleanup?.(); |
400 | 416 | }); |
401 | 417 | }); |
|