import { readFileSync } from "node:fs"; import { describe, expect, it, vi } from "vitest"; import type { ReadingManifestDto } from "../api/types"; import { createEpubApiLoader } from "./EpubReader"; const manifest: ReadingManifestDto = { bookId: 4, format: "epub", revision: "rev-1", containerPath: "META-INF/container.xml", opfPath: "OPS/package.opf", basePath: "OPS/", resources: [ { resourceId: "container", href: "META-INF/container.xml", url: "/books/4/reading-resources/container", mediaType: "application/xml", size: 12, kind: "document", state: "ready" }, { resourceId: "chapter", href: "OPS/text/chapter.xhtml", url: "/books/4/reading-resources/chapter", mediaType: "application/xhtml+xml", size: 18, kind: "chapter", state: "ready" } ], spine: [{ index: 0, href: "OPS/text/chapter.xhtml", resourceId: "chapter", url: "/books/4/reading-resources/chapter", mediaType: "application/xhtml+xml", size: 18 }], capabilities: { byteRanges: false, derivedImages: true, lightweightPages: false } }; describe("EPUB adaptive loader", () => { it("loads manifest resources with credentials and reuses a fetched entry", async () => { const fetcher = vi.fn().mockResolvedValue(new Response("chapter", { status: 200 })); const loader = createEpubApiLoader(manifest, fetcher); await expect(loader.loadText("OPS/text/chapter.xhtml#part")).resolves.toBe("chapter"); await loader.loadBlob("OPS/text/chapter.xhtml"); expect(fetcher).toHaveBeenCalledTimes(1); expect(fetcher).toHaveBeenCalledWith("/books/4/reading-resources/chapter", { credentials: "include", cache: "default" }); expect(loader.getSize("OPS/text/chapter.xhtml")).toBe(18); }); it("does not contain the complete-book fetch path", () => { const source = readFileSync(new URL("./EpubReader.tsx", import.meta.url), "utf8"); expect(source).not.toContain("bookFileUrl"); expect(source).not.toContain("fetch(url"); expect(source).not.toContain("new File("); expect(source).toContain("new EPUB(createEpubApiLoader(manifest)).init()"); }); });