import { describe, expect, it, vi } from "vitest"; import { createCursorPaginationRuntime } from "../../src/adapters/query-cache/cursor-pagination-runtime.ts"; const profile = { profileId: "bounded-cursor-v1", maxPages: 3, maxTotalItems: 4, maxEstimatedBytes: 1_024, maxCursorBytes: 64, allowSparsePage: false, } as const; describe("bounded cursor pagination runtime", () => { it("loads a stable finite chain without exposing cursors in its value", async () => { const loadPage = vi .fn() .mockResolvedValueOnce({ ok: true, value: { items: ["one"], nextCursor: "cursor-2", hasMore: true, snapshotToken: "snapshot-a", }, }) .mockResolvedValueOnce({ ok: true, value: { items: ["two"], nextCursor: null, hasMore: false, snapshotToken: "snapshot-a", }, }); const runtime = createCursorPaginationRuntime({ definitionId: "LIST_ALL", profile, loadPage, }); await expect(runtime.loadAll({})).resolves.toEqual({ ok: true, value: ["one", "two"], }); expect(loadPage.mock.calls.map(([cursor]) => cursor)).toEqual([ null, "cursor-2", ]); }); it.each([ { page: { items: [], nextCursor: "next", hasMore: true, snapshotToken: null, }, code: "PAGINATION_PAGE_INVALID", }, { page: { items: ["one"], nextCursor: null, hasMore: true, snapshotToken: null, }, code: "PAGINATION_PAGE_INVALID", }, ])("rejects invalid page invariants", async ({ page, code }) => { const runtime = createCursorPaginationRuntime({ definitionId: "LIST_ALL", profile, loadPage: async () => ({ ok: true, value: page }), }); await expect(runtime.loadAll({})).resolves.toMatchObject({ ok: false, error: { kind: "PAGINATION_CONTRACT_VIOLATION", code }, }); }); it("rejects cursor loops and snapshot drift", async () => { const loop = createCursorPaginationRuntime({ definitionId: "LIST_ALL", profile, loadPage: async () => ({ ok: true, value: { items: ["one"], nextCursor: "same", hasMore: true, snapshotToken: null, }, }), }); await expect(loop.loadAll({})).resolves.toMatchObject({ ok: false, error: { code: "PAGINATION_CURSOR_LOOP" }, }); let page = 0; const drift = createCursorPaginationRuntime({ definitionId: "LIST_ALL", profile, loadPage: async () => ({ ok: true, value: { items: [String(page)], nextCursor: page++ === 0 ? "next" : null, hasMore: page === 1, snapshotToken: page === 1 ? "snapshot-a" : "snapshot-b", }, }), }); await expect(drift.loadAll({})).resolves.toMatchObject({ ok: false, error: { code: "PAGINATION_SNAPSHOT_CHANGED" }, }); }); });