/ tests / elements / pdf.test.ts
pdf.test.ts
  1  import { StandardFonts } from "@cantoo/pdf-lib";
  2  import { describe, expect, mock, test } from "bun:test";
  3  import { div } from "~/elements/div";
  4  import { page } from "~/elements/page";
  5  import { PDF, pdf } from "~/elements/pdf";
  6  import { text } from "~/elements/text";
  7  import { font } from "~/utils/fonts";
  8  
  9  // Mock PDFDocument
 10  const mockPDFDocument = {
 11    addJavaScript: mock(() => {}),
 12    addPage: mock(() => ({
 13      drawRectangle: mock(() => {}),
 14      drawText: mock(() => {}),
 15      getFont: mock(() => [{}]),
 16      getHeight: mock(() => 841.8898),
 17      getWidth: mock(() => 595.276),
 18      setSize: mock(() => {})
 19    })),
 20    embedFont: mock(async () => ({})),
 21    save: mock(async () => new Uint8Array([1, 2, 3, 4])),
 22    setAuthor: mock(() => {})
 23  };
 24  
 25  // Mock PDFDocument.create for each test
 26  const mockPDFDocumentCreate = mock(async () => mockPDFDocument);
 27  
 28  describe("PDF", () => {
 29    describe("constructor and helper function", () => {
 30      test("should create PDF instance", () => {
 31        const pdfElement = new PDF();
 32        expect(pdfElement).toBeInstanceOf(PDF);
 33      });
 34  
 35      test("should create PDF instance with helper function", () => {
 36        const pdfElement = pdf();
 37        expect(pdfElement).toBeInstanceOf(PDF);
 38      });
 39    });
 40  
 41    describe("author method", () => {
 42      test("should set author and return instance for chaining", () => {
 43        const pdfElement = pdf();
 44        const result = pdfElement.author("John Doe");
 45  
 46        expect(result).toBe(pdfElement);
 47      });
 48  
 49      test("should chain multiple author calls", () => {
 50        const pdfElement = pdf()
 51          .author("John Doe")
 52          .author("Jane Smith");
 53  
 54        expect(pdfElement).toBeInstanceOf(PDF);
 55      });
 56    });
 57  
 58    describe("child management", () => {
 59      test("should add page child and return instance for chaining", () => {
 60        const pdfElement = pdf();
 61        const pageElement = page();
 62  
 63        const result = pdfElement.child(pageElement);
 64  
 65        expect(result).toBe(pdfElement);
 66      });
 67  
 68      test("should add multiple page children", () => {
 69        const pdfElement = pdf();
 70        const page1 = page();
 71        const page2 = page();
 72  
 73        pdfElement.child(page1).child(page2);
 74  
 75        expect(pdfElement).toBeInstanceOf(PDF);
 76      });
 77    });
 78  
 79    describe("font management", () => {
 80      test("should add font and return instance for chaining", () => {
 81        const pdfElement = pdf();
 82        const memoryFont = font(StandardFonts.Helvetica);
 83  
 84        const result = pdfElement.font(memoryFont);
 85  
 86        expect(result).toBe(pdfElement);
 87      });
 88  
 89      test("should add multiple fonts", () => {
 90        const pdfElement = pdf();
 91        const font1 = font(StandardFonts.Helvetica);
 92        const font2 = font(StandardFonts.TimesRoman);
 93  
 94        pdfElement.font(font1).font(font2);
 95  
 96        expect(pdfElement).toBeInstanceOf(PDF);
 97      });
 98    });
 99  
100    describe("script management", () => {
101      test("should add JavaScript and return instance for chaining", () => {
102        const pdfElement = pdf();
103        const result = pdfElement.script("myScript", "console.log('Hello');");
104  
105        expect(result).toBe(pdfElement);
106      });
107  
108      test("should add multiple scripts", () => {
109        const pdfElement = pdf();
110  
111        pdfElement
112          .script("script1", "console.log('Script 1');")
113          .script("script2", "console.log('Script 2');");
114  
115        expect(pdfElement).toBeInstanceOf(PDF);
116      });
117    });
118  
119    describe("renderToBytes", () => {
120      test("should be an async method that returns Promise<Uint8Array>", () => {
121        const pdfElement = pdf();
122  
123        const result = pdfElement.renderToBytes();
124  
125        expect(result).toBeInstanceOf(Promise);
126      });
127  
128      test("should handle empty PDF without throwing", async () => {
129        const pdfElement = pdf();
130  
131        // Test that the method doesn't throw - we can't easily test the actual PDF creation
132        // without complex mocking of the pdf-lib import
133        expect(() => pdfElement.renderToBytes()).not.toThrow();
134      });
135    });
136  
137    describe("method chaining", () => {
138      test("should support complete method chaining", () => {
139        const memoryFont = font(StandardFonts.Helvetica);
140        const pageElement = page()
141          .child(div().w(200).h(100).bg(0xFF0000))
142          .child(text("Hello World"));
143  
144        const pdfElement = pdf()
145          .author("Test Author")
146          .font(memoryFont)
147          .script("init", "console.log('PDF loaded');")
148          .child(pageElement)
149          .author("Updated Author"); // Should override
150  
151        expect(pdfElement).toBeInstanceOf(PDF);
152      });
153    });
154  
155    describe("integration scenarios", () => {
156      test("should handle complex PDF structure", () => {
157        const font1 = font(StandardFonts.Helvetica);
158        const font2 = font(StandardFonts.TimesRoman);
159  
160        const page1 = page()
161          .size([600, 800])
162          .child(text("Page 1 Header").font(font1))
163          .child(div().w(500).h(200).bg(0x333333));
164  
165        const page2 = page()
166          .size([600, 800])
167          .child(text("Page 2 Content").font(font2))
168          .child(div().w(500).h(300).bg(0x666666));
169  
170        const pdfElement = pdf()
171          .author("Complex PDF Author")
172          .font(font1)
173          .font(font2)
174          .script("analytics", "trackPDFView();")
175          .child(page1)
176          .child(page2);
177  
178        expect(pdfElement).toBeInstanceOf(PDF);
179      });
180    });
181  });