1import type { CDPSession } from "playwright-core";
2import { describe, expect, it, vi } from "vite-plus/test";
3
4import { installPdfDocumentNavigation } from "./PdfDocumentNavigation.ts";
5
6const source = "https://environment.test/api/assets/signed-token/files/Study%20guide.PDF";
7
8function fixture(nativePdfViewer = false) {
9 const completed = Promise.withResolvers<{ method: string; params: Record<string, unknown> }>();
10 let paused: (event: {
11 requestId: string;
12 frameId: string;
13 request: { url: string; method: string };
14 responseStatusCode: number;
15 responseHeaders: Array<{ name: string; value: string }>;
16 }) => void = () => {
17 throw new Error("Navigation handler was not installed");
18 };
19 const send = vi.fn(async (method: string, params: Record<string, unknown> = {}) => {
20 if (method === "Runtime.evaluate") return { result: { value: nativePdfViewer } };
21 if (method === "Page.getFrameTree") return { frameTree: { frame: { id: "main" } } };
22 if (
23 method === "Fetch.fulfillRequest" ||
24 method === "Fetch.continueRequest" ||
25 method === "Fetch.failRequest"
26 ) {
27 completed.resolve({ method, params });
28 }
29 return {};
30 });
31 const cdp = {
32 send,
33 on: (_name: string, listener: typeof paused) => {
34 paused = listener;
35 },
36 } as unknown as CDPSession;
37 return {
38 cdp,
39 send,
40 navigate: (
41 url = source,
42 frameId = "main",
43 method = "GET",
44 status = 200,
45 contentType = "application/pdf",
46 ) => {
47 paused({
48 requestId: "request-1",
49 frameId,
50 request: { url, method },
51 responseStatusCode: status,
52 responseHeaders: [{ name: "Content-Type", value: contentType }],
53 });
54 return completed.promise;
55 },
56 };
57}
58
59describe("PDF document navigation", () => {
60 it("escapes filenames in the browser document", async () => {
61 const test = fixture();
62 await installPdfDocumentNavigation(test.cdp);
63 const result = await test.navigate(
64 "https://environment.test/api/assets/token/%3Cscript%3E.pdf",
65 );
66 expect(Buffer.from(String(result.params.body), "base64").toString()).toContain(
67 "<title><script>.pdf</title>",
68 );
69 });
70
71 it("resumes navigation when committing the document fails", async () => {
72 const test = fixture();
73 await installPdfDocumentNavigation(test.cdp);
74 test.send.mockRejectedValueOnce(new Error("Tab closed"));
75 expect(await test.navigate()).toEqual({
76 method: "Fetch.continueRequest",
77 params: { requestId: "request-1" },
78 });
79 });
80});