import { describe, expect, it, vi } from "vitest"; import { withAbortableDeadline, type TimeoutScheduler, } from "../../src/adapters/web-push/runtime-support.ts"; import { webPushSuccess, } from "../../src/contracts/web-push.ts"; describe("Web Push runtime deadlines", () => { it("maps a scheduler setup failure without starting the task", async () => { const task = vi.fn(async () => webPushSuccess(undefined)); const scheduler: TimeoutScheduler = { setTimeout() { throw new Error("scheduler unavailable"); }, clearTimeout: vi.fn(), }; await expect( withAbortableDeadline(task, { deadlineMs: 10, operation: "PUSH_HANDLE", scheduler, }), ).resolves.toMatchObject({ ok: false, error: { code: "NATIVE_FAILURE", operation: "PUSH_HANDLE", }, }); expect(task).not.toHaveBeenCalled(); }); it("does not let timer cleanup replace a settled result", async () => { const scheduler: TimeoutScheduler = { setTimeout: () => Object.freeze({ handle: true }), clearTimeout() { throw new Error("cleanup unavailable"); }, }; await expect( withAbortableDeadline( async () => webPushSuccess("settled"), { deadlineMs: 10, operation: "PUSH_HANDLE", scheduler, }, ), ).resolves.toEqual(webPushSuccess("settled")); }); it("rechecks caller cancellation after listener registration", async () => { let abortReads = 0; const signal = { get aborted() { abortReads += 1; return abortReads >= 2; }, addEventListener: vi.fn(), removeEventListener: vi.fn(), } as unknown as AbortSignal; const task = vi.fn(async () => webPushSuccess(undefined)); const scheduler: TimeoutScheduler = { setTimeout: () => Object.freeze({ handle: true }), clearTimeout: vi.fn(), }; await expect( withAbortableDeadline(task, { deadlineMs: 10, operation: "PUSH_HANDLE", scheduler, signal, }), ).resolves.toMatchObject({ ok: false, error: { code: "ABORTED", operation: "PUSH_HANDLE" }, }); expect(task).not.toHaveBeenCalled(); }); });