fix(web): cover deep document headings

This commit is contained in:
2026-09-30 09:09:24 +09:00
parent 22c2e25c8f
commit 065812bc39
4 changed files with 38 additions and 7 deletions
@@ -25,7 +25,7 @@ const paragraphs = Array.from(
const bodyMd =
`# Workspace Memory\n\nThis document is read-only.\n\n| Very wide heading | Another heading | Decision |\n| --- | --- | --- |\n| ${
"wide-value-".repeat(16)
} | stable | keep scrolling local |\n\n\`\`\`rust\nfn example() { println!("${
} | stable | keep scrolling local |\n\n##### Deep document heading\n\n###### Deepest document heading\n\n\`\`\`rust\nfn example() { println!("${
"wide-code-".repeat(18)
}"); }\n\`\`\`\n\n[Safe link](https://example.com) [Unsafe link](javascript:alert(1))\n\n<img src=x onerror=alert(1)>\n\n${paragraphs}\n\n## T-661 UNIQUE END MARKER`;
@@ -165,6 +165,21 @@ Deno.test("production Memory shell renders safe Markdown and scrolls to its end
);
assertEquals(await page.locator("blockquote").count() > 0, true);
assertEquals(await page.locator("ul li").count() > 0, true);
for (
const heading of [
{ selector: "h5", text: "Deep document heading" },
{ selector: "h6", text: "Deepest document heading" },
]
) {
const element = page.locator(heading.selector, { hasText: heading.text });
assertEquals(await element.count(), 1);
assert(
await element.evaluate((node) =>
Number.parseFloat((globalThis as any).getComputedStyle(node).fontSize) >= 12
),
`${heading.selector} fell below the design language minimum text size`,
);
}
assertEquals(await page.locator('a[href="https://example.com"]').count(), 1);
assertEquals(await page.locator('a[href^="javascript:"]').count(), 0);
assertEquals(await page.locator("article img, article script").count(), 0);
@@ -10,6 +10,10 @@ test("renders document Markdown semantics through the shared safe policy", async
const source = [
"# Memory heading",
"",
"##### Deep heading",
"",
"###### Deepest heading",
"",
"A paragraph with **strong context** and `inline-code`.",
"",
"- first item",
@@ -36,10 +40,15 @@ test("renders document Markdown semantics through the shared safe policy", async
expect(container.querySelector("table")).not.toBeNull();
});
expect(container.querySelector("h5")?.textContent).toBe("Deep heading");
expect(container.querySelector("h6")?.textContent).toBe("Deepest heading");
expect(container.querySelector("strong")?.textContent).toBe("strong context");
expect(container.querySelectorAll("li")).toHaveLength(2);
expect(container.querySelector("blockquote")?.textContent).toContain("durable quote");
expect(container.querySelector('a[href="https://example.com"]')).not.toBeNull();
expect(container.querySelector("blockquote")?.textContent).toContain(
"durable quote",
);
expect(container.querySelector('a[href="https://example.com"]')).not
.toBeNull();
expect(container.querySelectorAll("a")).toHaveLength(1);
expect(container.querySelector("img")).toBeNull();
expect(container.querySelector("script")).toBeNull();
@@ -52,13 +61,16 @@ test("renders document Markdown semantics through the shared safe policy", async
);
expect(tableRegion?.tabIndex).toBe(0);
expect(codeRegion?.tabIndex).toBe(0);
expect(codeRegion?.querySelector("pre > code")?.textContent).toContain("println!");
expect(codeRegion?.querySelector("pre > code")?.textContent).toContain(
"println!",
);
});
test("wraps long prose and identifiers without turning them into document-level controls", async () => {
const longIdentifier = "memory-identifier-".repeat(40);
const { container } = render(DocumentMarkdown, {
text: `Long value: ${longIdentifier}\n\n<details open><summary>unsafe HTML</summary></details>`,
text:
`Long value: ${longIdentifier}\n\n<details open><summary>unsafe HTML</summary></details>`,
});
await waitFor(() => expect(container.textContent).toContain(longIdentifier));
@@ -41,7 +41,9 @@
:global(.document-markdown h2),
:global(.document-markdown h3),
:global(.document-markdown h4) {
:global(.document-markdown h4),
:global(.document-markdown h5),
:global(.document-markdown h6) {
margin: var(--space-6) 0 var(--space-2);
color: var(--text-strong);
font-size: var(--font-size-body);
@@ -53,7 +55,9 @@
}
:global(.document-markdown h3),
:global(.document-markdown h4) {
:global(.document-markdown h4),
:global(.document-markdown h5),
:global(.document-markdown h6) {
font-weight: 600;
}