docfast/src/__tests__/demo-branch-coverage.test.ts
OpenClaw Subagent 1363c61e39
All checks were successful
Build & Deploy to Staging / Build & Deploy to Staging (push) Successful in 21m45s
test: improve billing.ts and demo.ts branch coverage
2026-03-14 17:13:36 +01:00

223 lines
8.2 KiB
TypeScript

import { describe, it, expect, vi, beforeEach } from "vitest";
import express from "express";
import request from "supertest";
vi.mock("../services/browser.js", () => ({
renderPdf: vi.fn(),
renderUrlPdf: vi.fn(),
}));
let app: express.Express;
beforeEach(async () => {
vi.clearAllMocks();
vi.resetModules();
const { renderPdf } = await import("../services/browser.js");
vi.mocked(renderPdf).mockResolvedValue({ pdf: Buffer.from("%PDF-1.4 mock"), durationMs: 10 });
const { demoRouter } = await import("../routes/demo.js");
app = express();
app.use(express.json({ limit: "500kb" }));
app.use("/v1/demo", demoRouter);
});
describe("Demo Branch Coverage", () => {
describe("injectWatermark fallback branch (line 19)", () => {
it("should append watermark when full HTML document doesn't contain </body> tag", async () => {
const { renderPdf } = await import("../services/browser.js");
// Send full HTML (with <html>) but without </body> to hit the fallback branch
const htmlWithoutClosingBody = `
<html>
<head><title>Test Page</title></head>
<body>
<h1>Hello</h1>
<p>Content here</p>
`;
const res = await request(app)
.post("/v1/demo/html")
.set("content-type", "application/json")
.send({ html: htmlWithoutClosingBody });
expect(res.status).toBe(200);
expect(res.headers["content-type"]).toMatch(/application\/pdf/);
// Verify watermark was appended (not replaced)
const calledHtml = vi.mocked(renderPdf).mock.calls[0][0];
// The fallback should append the watermark at the end
expect(calledHtml).toContain("Hello");
expect(calledHtml).toContain("Content here");
expect(calledHtml).toContain("DEMO");
expect(calledHtml).toContain("Generated by DocFast");
// Ensure the original HTML is preserved before the watermark
expect(calledHtml.indexOf("Hello")).toBeLessThan(calledHtml.indexOf("DEMO"));
// Ensure watermark is appended at the end (since there's no </body> to replace)
const lastBodyCloseIndex = calledHtml.lastIndexOf("</body>");
const watermarkIndex = calledHtml.indexOf("Generated by DocFast");
// If there's a </body> at the very end (from wrapping), the watermark should be before it
if (lastBodyCloseIndex > -1) {
expect(watermarkIndex).toBeLessThan(lastBodyCloseIndex);
}
});
it("should append watermark to plain HTML fragment without </body>", async () => {
const { renderPdf } = await import("../services/browser.js");
const res = await request(app)
.post("/v1/demo/html")
.set("content-type", "application/json")
.send({ html: "<div>Simple fragment</div>" });
expect(res.status).toBe(200);
const calledHtml = vi.mocked(renderPdf).mock.calls[0][0];
expect(calledHtml).toContain("<div>Simple fragment</div>");
expect(calledHtml).toContain("DEMO");
expect(calledHtml).toContain("position:fixed;bottom:0;left:0;right:0;");
});
it("should handle markdown that results in HTML without </body> and injects watermark", async () => {
const { renderPdf } = await import("../services/browser.js");
const res = await request(app)
.post("/v1/demo/markdown")
.set("content-type", "application/json")
.send({ markdown: "# Just a heading\n\nSome text" });
expect(res.status).toBe(200);
const calledHtml = vi.mocked(renderPdf).mock.calls[0][0];
// Should contain watermark
expect(calledHtml).toContain("DEMO");
expect(calledHtml).toContain("Generated by DocFast");
expect(calledHtml).toContain("Upgrade to Pro for clean PDFs");
});
it("should still work correctly when HTML contains </body> (replace branch)", async () => {
const { renderPdf } = await import("../services/browser.js");
const fullHtml = `
<html>
<head><title>Test</title></head>
<body>
<h1>Complete HTML</h1>
<p>With closing body tag</p>
</body>
</html>
`;
const res = await request(app)
.post("/v1/demo/html")
.set("content-type", "application/json")
.send({ html: fullHtml });
expect(res.status).toBe(200);
const calledHtml = vi.mocked(renderPdf).mock.calls[0][0];
// When </body> exists, watermark should be injected before it
expect(calledHtml).toContain("</body>");
expect(calledHtml).toContain("DEMO");
// The watermark should be between the content and closing </body>
const watermarkIndex = calledHtml.indexOf("Generated by DocFast");
const closingBodyIndex = calledHtml.indexOf("</body>");
expect(watermarkIndex).toBeGreaterThan(-1);
expect(closingBodyIndex).toBeGreaterThan(-1);
expect(watermarkIndex).toBeLessThan(closingBodyIndex);
});
it("should reject empty HTML input with 400 error", async () => {
const res = await request(app)
.post("/v1/demo/html")
.set("content-type", "application/json")
.send({ html: "" });
// Empty HTML is rejected by validation
expect(res.status).toBe(400);
expect(res.body.error).toContain("html");
});
it("should handle HTML with multiple </body> tags (uses first)</body>", async () => {
const { renderPdf } = await import("../services/browser.js");
const htmlWithMultipleBodies = `
<html>
<body>First body</body>
<body>Second body</body>
</html>
`;
const res = await request(app)
.post("/v1/demo/html")
.set("content-type", "application/json")
.send({ html: htmlWithMultipleBodies });
expect(res.status).toBe(200);
const calledHtml = vi.mocked(renderPdf).mock.calls[0][0];
// replace only replaces the first occurrence
expect(calledHtml).toContain("First body");
expect(calledHtml).toContain("DEMO");
expect(calledHtml).toContain("</body>");
});
});
describe("Watermark content verification", () => {
it("should include demo watermark with exact styling", async () => {
const { renderPdf } = await import("../services/browser.js");
const res = await request(app)
.post("/v1/demo/html")
.set("content-type", "application/json")
.send({ html: "<h1>Test</h1>" });
expect(res.status).toBe(200);
const calledHtml = vi.mocked(renderPdf).mock.calls[0][0];
// Verify watermark styling
expect(calledHtml).toContain("background:rgba(52,211,153,0.92);color:#0b0d11");
expect(calledHtml).toContain("z-index:999999");
expect(calledHtml).toContain("pointer-events:none");
});
it("should preserve user CSS when injecting watermark", async () => {
const { renderPdf } = await import("../services/browser.js");
const customCss = "body { background: blue; }";
const res = await request(app)
.post("/v1/demo/html")
.set("content-type", "application/json")
.send({ html: "<h1>Test</h1>", css: customCss });
expect(res.status).toBe(200);
const calledHtml = vi.mocked(renderPdf).mock.calls[0][0];
// Both watermark and user CSS should be present
expect(calledHtml).toContain("DEMO");
expect(calledHtml).toContain("background: blue");
});
});
describe("Branch coverage for attachment headers", () => {
it("should set Content-Disposition to attachment for HTML", async () => {
const res = await request(app)
.post("/v1/demo/html")
.set("content-type", "application/json")
.send({ html: "<h1>Hello</h1>" });
expect(res.status).toBe(200);
expect(res.headers["content-disposition"]).toMatch(/^attachment/);
expect(res.headers["content-disposition"]).toMatch(/filename="demo\.pdf"/);
});
it("should set Content-Disposition to attachment for markdown", async () => {
const res = await request(app)
.post("/v1/demo/markdown")
.set("content-type", "application/json")
.send({ markdown: "# Hello" });
expect(res.status).toBe(200);
expect(res.headers["content-disposition"]).toMatch(/^attachment/);
expect(res.headers["content-disposition"]).toMatch(/filename="demo\.pdf"/);
});
});
});