1import { describe, expect, it } from "vitest";
2import { atomHtmlToText, atomTextToHtml } from "./atom-html.js";
3
4describe("atom ↔ HTML bridge (T-148 web)", () => {
5 it("escapes untrusted text and renders atoms as spans", () => {
6 const html = atomTextToHtml('a <img src=x onerror=alert(1)> & @status(done) b');
7 expect(html).toContain("a <img src=x onerror=alert(1)> & ");
8
9 expect(html).not.toContain("<img");
10 expect(html).toContain('<span class="factory-atom" data-atom-kind="status" data-atom-value="done">done</span>');
11 });
12
13 it("escapes label values (XSS vector) in the span text", () => {
14
15 const html = atomTextToHtml("@label(<img src=x onerror=x>)")
16 expect(html).toContain(
17 '<span class="factory-atom" data-atom-kind="label" data-atom-value="<img src=x onerror=x>"'
18 );
19 expect(html).not.toContain("<img");
20 });
21
22 it("round-trips text → html → text (atoms become tokens)", () => {
23 const original = "Due @date(2026-10-11), @status(in-progress), @label(ops team)";
24 const html = atomTextToHtml(original);
25 expect(atomHtmlToText(html)).toBe(original);
26 });
27
28 it("returns null for atom-less HTML (caller keeps original content)", () => {
29 expect(atomHtmlToText("<p>plain <strong>bold</strong></p>")).toBeNull();
30 expect(atomHtmlToText("")).toBeNull();
31 });
32
33 it("strips formatting to plain text; atom-less HTML is left untouched", () => {
34 const html = '<p>one <span class="factory-atom" data-atom-kind="status" data-atom-value="done">done</span></p>';
35 expect(atomHtmlToText(html)).toBe("one @status(done)");
36
37 expect(atomHtmlToText("<p>two <strong>bold</strong></p>")).toBeNull();
38 });
39
40 it("keeps an unknown status value as plain text (no forged token)", () => {
41 const html =
42 '<span class="factory-atom" data-atom-kind="status" data-atom-value="maybe">maybe</span>';
43 expect(atomHtmlToText(html)).toBe("maybe");
44 });
45
46 it("unescapes entity-escaped values in the token", () => {
47 const html =
48 '<span class="factory-atom" data-atom-kind="label" data-atom-value="a"b">a"b</span>';
49 expect(atomHtmlToText(html)).toBe("@label(a\"b)");
50 });
51});
52