From 52ad686ab5ec290f6fe252254f9b2cd04d140a9f Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Tue, 17 Mar 2026 06:42:28 +0000 Subject: [PATCH] refactor(runtime-tests): share typing lease assertions --- .../runtime/runtime-discord-typing.test.ts | 55 +++++++------------ .../runtime/runtime-telegram-typing.test.ts | 53 ++++++------------ .../runtime/typing-lease.test-support.ts | 47 ++++++++++++++++ 3 files changed, 84 insertions(+), 71 deletions(-) create mode 100644 src/plugins/runtime/typing-lease.test-support.ts diff --git a/src/plugins/runtime/runtime-discord-typing.test.ts b/src/plugins/runtime/runtime-discord-typing.test.ts index 1eb5b6fd315..6f6ec1a1dec 100644 --- a/src/plugins/runtime/runtime-discord-typing.test.ts +++ b/src/plugins/runtime/runtime-discord-typing.test.ts @@ -1,5 +1,9 @@ -import { afterEach, describe, expect, it, vi } from "vitest"; +import { afterEach, describe, it, vi } from "vitest"; import { createDiscordTypingLease } from "./runtime-discord-typing.js"; +import { + expectBackgroundTypingPulseFailuresAreSwallowed, + expectIndependentTypingLeases, +} from "./typing-lease.test-support.js"; describe("createDiscordTypingLease", () => { afterEach(() => { @@ -7,51 +11,30 @@ describe("createDiscordTypingLease", () => { }); it("pulses immediately and keeps leases independent", async () => { - vi.useFakeTimers(); - const pulse = vi.fn(async () => undefined); - - const leaseA = await createDiscordTypingLease({ - channelId: "123", - intervalMs: 2_000, - pulse, + await expectIndependentTypingLeases({ + createLease: createDiscordTypingLease, + buildParams: (pulse) => ({ + channelId: "123", + intervalMs: 2_000, + pulse, + }), }); - const leaseB = await createDiscordTypingLease({ - channelId: "123", - intervalMs: 2_000, - pulse, - }); - - expect(pulse).toHaveBeenCalledTimes(2); - - await vi.advanceTimersByTimeAsync(2_000); - expect(pulse).toHaveBeenCalledTimes(4); - - leaseA.stop(); - await vi.advanceTimersByTimeAsync(2_000); - expect(pulse).toHaveBeenCalledTimes(5); - - await leaseB.refresh(); - expect(pulse).toHaveBeenCalledTimes(6); - - leaseB.stop(); }); it("swallows background pulse failures", async () => { - vi.useFakeTimers(); const pulse = vi .fn<(params: { channelId: string; accountId?: string; cfg?: unknown }) => Promise>() .mockResolvedValueOnce(undefined) .mockRejectedValueOnce(new Error("boom")); - const lease = await createDiscordTypingLease({ - channelId: "123", - intervalMs: 2_000, + await expectBackgroundTypingPulseFailuresAreSwallowed({ + createLease: createDiscordTypingLease, pulse, + buildParams: (pulse) => ({ + channelId: "123", + intervalMs: 2_000, + pulse, + }), }); - - await expect(vi.advanceTimersByTimeAsync(2_000)).resolves.toBe(vi); - expect(pulse).toHaveBeenCalledTimes(2); - - lease.stop(); }); }); diff --git a/src/plugins/runtime/runtime-telegram-typing.test.ts b/src/plugins/runtime/runtime-telegram-typing.test.ts index 3394aa1cf50..0ec97971eb8 100644 --- a/src/plugins/runtime/runtime-telegram-typing.test.ts +++ b/src/plugins/runtime/runtime-telegram-typing.test.ts @@ -1,5 +1,9 @@ import { afterEach, describe, expect, it, vi } from "vitest"; import { createTelegramTypingLease } from "./runtime-telegram-typing.js"; +import { + expectBackgroundTypingPulseFailuresAreSwallowed, + expectIndependentTypingLeases, +} from "./typing-lease.test-support.js"; describe("createTelegramTypingLease", () => { afterEach(() => { @@ -7,37 +11,17 @@ describe("createTelegramTypingLease", () => { }); it("pulses immediately and keeps leases independent", async () => { - vi.useFakeTimers(); - const pulse = vi.fn(async () => undefined); - - const leaseA = await createTelegramTypingLease({ - to: "telegram:123", - intervalMs: 2_000, - pulse, + await expectIndependentTypingLeases({ + createLease: createTelegramTypingLease, + buildParams: (pulse) => ({ + to: "telegram:123", + intervalMs: 2_000, + pulse, + }), }); - const leaseB = await createTelegramTypingLease({ - to: "telegram:123", - intervalMs: 2_000, - pulse, - }); - - expect(pulse).toHaveBeenCalledTimes(2); - - await vi.advanceTimersByTimeAsync(2_000); - expect(pulse).toHaveBeenCalledTimes(4); - - leaseA.stop(); - await vi.advanceTimersByTimeAsync(2_000); - expect(pulse).toHaveBeenCalledTimes(5); - - await leaseB.refresh(); - expect(pulse).toHaveBeenCalledTimes(6); - - leaseB.stop(); }); it("swallows background pulse failures", async () => { - vi.useFakeTimers(); const pulse = vi .fn< (params: { @@ -50,16 +34,15 @@ describe("createTelegramTypingLease", () => { .mockResolvedValueOnce(undefined) .mockRejectedValueOnce(new Error("boom")); - const lease = await createTelegramTypingLease({ - to: "telegram:123", - intervalMs: 2_000, + await expectBackgroundTypingPulseFailuresAreSwallowed({ + createLease: createTelegramTypingLease, pulse, + buildParams: (pulse) => ({ + to: "telegram:123", + intervalMs: 2_000, + pulse, + }), }); - - await expect(vi.advanceTimersByTimeAsync(2_000)).resolves.toBe(vi); - expect(pulse).toHaveBeenCalledTimes(2); - - lease.stop(); }); it("falls back to the default interval for non-finite values", async () => { diff --git a/src/plugins/runtime/typing-lease.test-support.ts b/src/plugins/runtime/typing-lease.test-support.ts new file mode 100644 index 00000000000..f32511d760d --- /dev/null +++ b/src/plugins/runtime/typing-lease.test-support.ts @@ -0,0 +1,47 @@ +import { expect, vi } from "vitest"; + +export async function expectIndependentTypingLeases< + TParams extends { intervalMs?: number; pulse: (...args: never[]) => Promise }, + TLease extends { refresh: () => Promise; stop: () => void }, +>(params: { + createLease: (params: TParams) => Promise; + buildParams: (pulse: TParams["pulse"]) => TParams; +}) { + vi.useFakeTimers(); + const pulse = vi.fn(async () => undefined) as TParams["pulse"]; + + const leaseA = await params.createLease(params.buildParams(pulse)); + const leaseB = await params.createLease(params.buildParams(pulse)); + + expect(pulse).toHaveBeenCalledTimes(2); + + await vi.advanceTimersByTimeAsync(2_000); + expect(pulse).toHaveBeenCalledTimes(4); + + leaseA.stop(); + await vi.advanceTimersByTimeAsync(2_000); + expect(pulse).toHaveBeenCalledTimes(5); + + await leaseB.refresh(); + expect(pulse).toHaveBeenCalledTimes(6); + + leaseB.stop(); +} + +export async function expectBackgroundTypingPulseFailuresAreSwallowed< + TParams extends { intervalMs?: number; pulse: (...args: never[]) => Promise }, + TLease extends { stop: () => void }, +>(params: { + createLease: (params: TParams) => Promise; + buildParams: (pulse: TParams["pulse"]) => TParams; + pulse: TParams["pulse"]; +}) { + vi.useFakeTimers(); + + const lease = await params.createLease(params.buildParams(params.pulse)); + + await expect(vi.advanceTimersByTimeAsync(2_000)).resolves.toBe(vi); + expect(params.pulse).toHaveBeenCalledTimes(2); + + lease.stop(); +}