| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990 |
- /* @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);
- });
- });
|