/* @vitest-environment node */ import { describe, it, expect } from "vitest"; import { ApiError } from "@/lib/api/errors"; import { encodeCursor, decodeCursor } from "./cursor.js"; describe("lib/search/cursor", () => { it("decodeCursor(null) returns the default cursor", () => { expect(decodeCursor(null)).toEqual({ v: 1, mode: "sync", offset: 0, contextId: null, }); }); it('decodeCursor("") treats empty string like missing cursor (default)', () => { expect(decodeCursor("")).toEqual({ v: 1, mode: "sync", offset: 0, contextId: null, }); }); it("encodeCursor + decodeCursor roundtrip works", () => { const encoded = encodeCursor({ v: 1, mode: "sync", offset: 10 }); expect(typeof encoded).toBe("string"); expect(encoded.length).toBeGreaterThan(5); const decoded = decodeCursor(encoded); expect(decoded).toEqual({ v: 1, mode: "sync", offset: 10, contextId: null, }); }); it("keeps contextId when provided", () => { const encoded = encodeCursor({ v: 1, mode: "sync", offset: 5, contextId: "ctx-123", }); expect(decodeCursor(encoded)).toEqual({ v: 1, mode: "sync", offset: 5, contextId: "ctx-123", }); }); it("encodeCursor rejects invalid payloads", () => { expect(() => encodeCursor(null)).toThrow(ApiError); expect(() => encodeCursor({})).toThrow(ApiError); expect(() => encodeCursor({ offset: -1 })).toThrow(ApiError); }); it("decodeCursor rejects whitespace-only cursor", () => { expect(() => decodeCursor(" ")).toThrow(ApiError); }); it("decodeCursor rejects non-JSON payloads (deterministic)", () => { // Using a valid base64url string that decodes to non-JSON ensures deterministic failure: // JSON.parse("not-json") must throw => decodeCursor must throw ApiError. const bad = Buffer.from("not-json", "utf8").toString("base64url"); expect(() => decodeCursor(bad)).toThrow(ApiError); }); it("decodeCursor rejects wrong version", () => { const bad = Buffer.from( JSON.stringify({ v: 2, mode: "sync", offset: 0 }), "utf8" ).toString("base64url"); expect(() => decodeCursor(bad)).toThrow(ApiError); }); it("decodeCursor rejects negative offsets", () => { const bad = Buffer.from( JSON.stringify({ v: 1, mode: "sync", offset: -1 }), "utf8" ).toString("base64url"); expect(() => decodeCursor(bad)).toThrow(ApiError); }); });