/** * @file htmlInline.test.ts * @description An HTML preview's relative CSS, scripts and images are inlined * from the place's own files, never from above its root or off a URL. * @author Nguyễn Ngọc Trí Vĩ */ import { describe, expect, it, vi } from "vitest"; import { inlineHtml, resolveRef } from "../htmlInline"; const files: Record = { "site/css/app.css": "body{background:url(../img/bg.png)}", "site/js/app.js": "window.ok=1", "site/img/logo.png": "PNG", "site/img/bg.png": "BG", }; const fetchFile = vi.fn(async (p: string) => { if (!(p in files)) throw new Error("404"); return new Blob([files[p]!]); }); describe("resolveRef", () => { it("resolves against the page's folder, from the root on a leading slash", () => { expect(resolveRef("site", "css/a.css?v=2#x")).toBe("site/css/a.css"); expect(resolveRef("site/sub", "../img/a%20b.png")).toBe("site/img/a b.png"); expect(resolveRef("site", "/top.css")).toBe("top.css"); }); it("skips URLs, anchors and anything above the root", () => { for (const r of ["https://x/a.js", "//cdn/a.js", "data:x", "#top", "", "../../etc/passwd"]) expect(resolveRef("site", r)).toBeNull(); }); }); describe("inlineHtml", () => { it("inlines stylesheets (with their url()s), scripts and images", async () => { const html = ` `; const out = await inlineHtml(html, "site/index.html", fetchFile); expect(out.startsWith("")).toBe(true); expect(out).toContain(``); expect(out).toContain(`src="data:text/javascript;base64,${btoa("window.ok=1")}"`); expect(out).toContain(`src="data:image/png;base64,${btoa("PNG")}"`); expect(out).not.toContain("srcset"); expect(out).toContain('src="https://cdn.example/x.js"'); expect(out).toContain('src="missing.png"'); expect(fetchFile).not.toHaveBeenCalledWith(expect.stringContaining("cdn")); }); it("returns the page untouched when nothing is local", async () => { const html = "

hi x

"; expect(await inlineHtml(html, "a.html", fetchFile)).toBe(html); }); });