test(#248 F2): exercise <,> escape branches in raw-HTML export round-trip
The escaping round-trip test's data (A & "B") only contained & and ", so the <,> branches of escapeHtmlAttr (&,",<,>) and escapeHtmlText (&,<,>) were never exercised; a regression dropping <,> escaping would still pass. Extend the data to A & <B> "C" in both the data-label attribute and the visible text so both functions' <,> branches are genuinely covered. Assert the well-formed escaped tag (attr: A & <B> "C", text: A & <B> "C"), explicitly reject the raw tag-corrupting forms, and confirm markdownToHtml restores the originals. Comment updated to match. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -111,22 +111,28 @@ describe("htmlToMarkdown — custom nodes are preserved losslessly (#206 mdrt-2)
|
|||||||
// HTML special chars in an attribute value or in a node's text must be
|
// HTML special chars in an attribute value or in a node's text must be
|
||||||
// ESCAPED when re-emitted as raw HTML, otherwise the exported tag is
|
// ESCAPED when re-emitted as raw HTML, otherwise the exported tag is
|
||||||
// malformed and `markdownToHtml`'s parser cannot restore the original value
|
// malformed and `markdownToHtml`'s parser cannot restore the original value
|
||||||
// (the same silent data loss this PR fixes). This exercises the escape
|
// (the same silent data loss this PR fixes). Dropping `<`/`>` escaping is the
|
||||||
// branches of escapeHtmlAttr (&, ", <, >) and escapeHtmlText (&, <, >) that
|
// dangerous regression: a stray `<` or `>` corrupts the tag (or injects new
|
||||||
// the alphanumeric-only cases above never hit. The mention's data-label and
|
// markup), so the test data carries ALL of `&`, `"`, `<`, `>` in BOTH the
|
||||||
// visible text both carry `&` and `"`.
|
// data-label attribute and the visible text. That fully exercises
|
||||||
it("escapes HTML special chars in attrs + text and round-trips them", async () => {
|
// escapeHtmlAttr's `&,",<,>` branches and escapeHtmlText's `&,<,>` branches
|
||||||
|
// (escapeHtmlText leaves `"` literal); the alphanumeric-only cases above hit
|
||||||
|
// none of them.
|
||||||
|
it("escapes HTML special chars (& \" < >) in attrs + text and round-trips them", async () => {
|
||||||
const md = htmlToMarkdown(
|
const md = htmlToMarkdown(
|
||||||
`<p>hi <span data-type="mention" data-id="u1" data-label='A & "B"'>@A & "B"</span> there</p>`,
|
`<p>hi <span data-type="mention" data-id="u1" data-label="A & <B> "C"">@A & <B> "C"</span> there</p>`,
|
||||||
);
|
);
|
||||||
|
|
||||||
// (a) The exported Markdown carries a WELL-FORMED, correctly-escaped tag:
|
// (a) The exported Markdown carries a WELL-FORMED, correctly-escaped tag:
|
||||||
// the attribute escapes both `&` and `"`; the text escapes `&` (a `"`
|
// the attribute escapes `&`, `<`, `>` AND `"`; the text escapes `&`, `<`,
|
||||||
// inside text content is legal, so it stays literal).
|
// `>` (a `"` inside text content is legal, so it stays literal).
|
||||||
expect(md).toContain('data-label="A & "B""');
|
expect(md).toContain('data-label="A & <B> "C""');
|
||||||
expect(md).toContain('>@A & "B"</span>');
|
expect(md).toContain('>@A & <B> "C"</span>');
|
||||||
// And NOT the raw, malformed form that would break the attribute.
|
// And explicitly NOT the raw, tag-corrupting forms: a literal `<B>` (would
|
||||||
expect(md).not.toContain('data-label="A & "B""');
|
// mean `<`/`>` escaping was dropped in either the attr or the text)...
|
||||||
|
expect(md).not.toContain("<B>");
|
||||||
|
// ...nor the malformed attribute that an unescaped `"` would produce.
|
||||||
|
expect(md).not.toContain('data-label="A & <B> "C""');
|
||||||
|
|
||||||
// (b) Import restores the ORIGINAL (unescaped) values, attribute and text.
|
// (b) Import restores the ORIGINAL (unescaped) values, attribute and text.
|
||||||
const html = await markdownToHtml(md);
|
const html = await markdownToHtml(md);
|
||||||
@@ -134,8 +140,8 @@ describe("htmlToMarkdown — custom nodes are preserved losslessly (#206 mdrt-2)
|
|||||||
const span = dom.querySelector('span[data-type="mention"]');
|
const span = dom.querySelector('span[data-type="mention"]');
|
||||||
expect(span).not.toBeNull();
|
expect(span).not.toBeNull();
|
||||||
expect(span!.getAttribute("data-id")).toBe("u1");
|
expect(span!.getAttribute("data-id")).toBe("u1");
|
||||||
expect(span!.getAttribute("data-label")).toBe('A & "B"');
|
expect(span!.getAttribute("data-label")).toBe('A & <B> "C"');
|
||||||
expect(span!.textContent).toBe('@A & "B"');
|
expect(span!.textContent).toBe('@A & <B> "C"');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user