Quill 2's semantic HTML saves a blank line as a truly empty <p></p> (no <br> placeholder) — verified in the DB (invoice_sections hold <p></p>, zero <p><br>) — which collapses to nothing outside the editor. cleanQuillHtml (PDF path) and the new restoreQuillBlankLines (order/ invoice read-only previews) restore the placeholder at render time, so existing stored content is covered retroactively. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
56 lines
2.1 KiB
TypeScript
56 lines
2.1 KiB
TypeScript
import { describe, it, expect } from "vitest";
|
|
import { cleanQuillHtml } from "../utils/pdf-shared";
|
|
|
|
describe("cleanQuillHtml — inline-style whitelist", () => {
|
|
it("keeps Quill text and background colors", () => {
|
|
const html =
|
|
'<p><span style="color: rgb(230, 0, 0);">červeně</span> ' +
|
|
'<span style="background-color: #ffff00;">zvýrazněně</span> ' +
|
|
'<span style="color: #06c;">modře</span></p>';
|
|
const out = cleanQuillHtml(html);
|
|
expect(out).toContain('style="color: rgb(230, 0, 0)"');
|
|
expect(out).toContain('style="background-color: #ffff00"');
|
|
expect(out).toContain('style="color: #06c"');
|
|
});
|
|
|
|
it("drops every non-color style declaration", () => {
|
|
const out = cleanQuillHtml(
|
|
'<span style="position: fixed; color: red; font-size: 99px;">x</span>',
|
|
);
|
|
expect(out).toBe('<span style="color: red">x</span>');
|
|
});
|
|
|
|
it("drops unsafe color values (url, expression, quotes)", () => {
|
|
expect(
|
|
cleanQuillHtml('<span style="color: url(javascript:alert(1))">x</span>'),
|
|
).toBe("<span>x</span>");
|
|
expect(
|
|
cleanQuillHtml('<span style="color: expression(alert(1))">x</span>'),
|
|
).toBe("<span>x</span>");
|
|
expect(cleanQuillHtml("<span style='color: \"red\"'>x</span>")).toBe(
|
|
"<span>x</span>",
|
|
);
|
|
});
|
|
|
|
it("restores Quill 2's empty <p></p> blank lines to <p><br></p>", () => {
|
|
// Quill 2's semantic HTML drops the <br> placeholder from blank lines.
|
|
expect(cleanQuillHtml("<p>A</p><p></p><p>B</p>")).toBe(
|
|
"<p>A</p><p><br></p><p>B</p>",
|
|
);
|
|
// Attribute-carrying and whitespace-only empties too.
|
|
expect(cleanQuillHtml('<p class="ql-align-center"> </p>')).toBe(
|
|
'<p class="ql-align-center"><br></p>',
|
|
);
|
|
});
|
|
|
|
it("keeps stripping scripts, event handlers and js: URLs", () => {
|
|
const out = cleanQuillHtml(
|
|
'<p onclick="alert(1)"><script>alert(1)</script>' +
|
|
'<a href="javascript:alert(1)">x</a></p>',
|
|
);
|
|
expect(out).not.toContain("script");
|
|
expect(out).not.toContain("onclick");
|
|
expect(out).not.toContain("javascript:");
|
|
});
|
|
});
|