import { describe, expect, test } from "bun:test"; import { docxToHtml } from "../src/optional/docx.ts"; import { readWorkbook } from "../src/optional/sheet.ts"; import { listZip } from "../src/optional/zip.ts"; import { zipSync, strToU8 } from "fflate"; /** * These exercise the parsers themselves. The browser wiring — one runtime asset * per installed package, fetched on first use — is covered in component.test.ts. */ describe("zip listing", () => { const archive = zipSync({ "docs/readme.md": strToU8("hello world\n".repeat(20)), "src/index.ts": strToU8("export const value = 1;\n"), }); test("entries are listed with their uncompressed sizes", async () => { const entries = await listZip(archive); expect(entries.map((entry) => entry.name).sort()).toEqual(["docs/readme.md", "src/index.ts"]); expect(entries.find((entry) => entry.name === "docs/readme.md")!.size).toBe(240); }); test("a corrupt archive rejects rather than resolving empty", async () => { await expect(listZip(new Uint8Array([0x50, 0x4b, 3, 4, 9, 9, 9]))).rejects.toThrow(); }); }); describe("workbook reading", () => { // Built with the same shape as examples/basic-app/public/viewer/sample.xlsx. const NS = "http://schemas.openxmlformats.org/spreadsheetml/2006/main"; const R = "http://schemas.openxmlformats.org/officeDocument/2006/relationships"; const sheet = (rows: (string | number)[][]) => `${rows .map( (row, rowIndex) => `${row .map((value, index) => { const ref = `${String.fromCharCode(65 + index)}${rowIndex + 1}`; return typeof value === "number" ? `${value}` : `${value}`; }) .join("")}`, ) .join("")}`; const workbook = zipSync({ "[Content_Types].xml": strToU8( '' + '' + '' + '' + '' + '' + "", ), "_rels/.rels": strToU8( ``, ), "xl/workbook.xml": strToU8( `` + '' + '' + "", ), "xl/_rels/workbook.xml.rels": strToU8( `` + `` + `` + "", ), "xl/worksheets/sheet1.xml": strToU8( sheet([ ["Region", "Q1"], ["North", 15400], ["South", 11200], ]), ), "xl/worksheets/sheet2.xml": strToU8( sheet([ ["Team", "People"], ["Engineering", 42], ]), ), }); test("every sheet comes back named, with a header and string cells", () => { const sheets = readWorkbook(workbook); expect(sheets.map((item) => item.name)).toEqual(["Revenue", "Headcount"]); expect(sheets[0]!.header).toEqual(["Region", "Q1"]); expect(sheets[0]!.rows).toEqual([ ["North", "15400"], ["South", "11200"], ]); expect(sheets[1]!.rows).toEqual([["Engineering", "42"]]); }); }); describe("document conversion", () => { const W = "http://schemas.openxmlformats.org/wordprocessingml/2006/main"; const R = "http://schemas.openxmlformats.org/officeDocument/2006/relationships"; const paragraph = (text: string, style?: string) => `${style ? `` : ""}` + `${text}`; const document = zipSync({ "[Content_Types].xml": strToU8( '' + '' + '' + '' + "", ), "_rels/.rels": strToU8( ``, ), "word/document.xml": strToU8( `` + paragraph("Quarterly summary", "Heading1") + paragraph("Bodies of text survive; page layout does not.") + "", ), }); test("a docx becomes semantic HTML", async () => { const html = await docxToHtml(document); expect(html).toContain("

Quarterly summary

"); expect(html).toContain("Bodies of text survive"); // Semantic output only: no document chrome, and nothing executable. expect(html).not.toContain(" { await expect(docxToHtml(strToU8("not a document"))).rejects.toThrow(); }); });