test: improve billing.ts and demo.ts branch coverage
All checks were successful
Build & Deploy to Staging / Build & Deploy to Staging (push) Successful in 21m45s
All checks were successful
Build & Deploy to Staging / Build & Deploy to Staging (push) Successful in 21m45s
This commit is contained in:
parent
3aae96fd8a
commit
1363c61e39
2 changed files with 553 additions and 0 deletions
223
src/__tests__/demo-branch-coverage.test.ts
Normal file
223
src/__tests__/demo-branch-coverage.test.ts
Normal file
|
|
@ -0,0 +1,223 @@
|
|||
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"/);
|
||||
});
|
||||
});
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue