1import test from "node:test";2import assert from "node:assert/strict";3import { FakeNode, setup } from "./rooms.test.mjs";45test("chat tables render semantic headers, alignment and uneven rows", () => {6 const s = setup();7 const body = s.rooms.chatMarkdown(new FakeNode("div"), "| Name | Notes | Score |\n| :--- | :---: | ---: |\n| Ada | **ready** | 10 |\n| Grace | `a|b` |\n| Alan | left");8 const region = body.children[0], table = region.querySelector("table");9 assert.equal(region.getAttribute("data-markdown-table"), "");10 assert.equal(region.getAttribute("role"), "region");11 assert.equal(region.getAttribute("aria-label"), "Table");12 assert.equal(region.getAttribute("tabindex"), "0");13 assert.deepEqual(table.querySelectorAll("th").map(cell => [cell.getAttribute("scope"), cell.getAttribute("data-align")]), [["col", "left"], ["col", "center"], ["col", "right"]]);14 assert.equal(table.querySelectorAll("tbody tr").length, 3);15 assert.equal(table.querySelectorAll("tbody tr")[1].children.length, 3);16 assert.equal(table.querySelectorAll("tbody tr")[1].children[1].querySelector("code").textContent, "a|b");17 assert.equal(table.querySelectorAll("tbody tr")[2].children[2].textContent, "");18 assert.equal(table.querySelector("strong").textContent, "ready");19});2021test("chat tables accept escaped pipes and keep inline content safe", () => {22 const s = setup();23 const body = s.rooms.chatMarkdown(new FakeNode("div"), "Label | Link\n--- | ---\nA \\| B | [go](javascript:alert(1)) <img>");24 const table = body.querySelector("table");25 assert.equal(table.querySelector("tbody td").textContent, "A | B");26 assert.equal(table.querySelectorAll("a").length, 0);27 assert.equal(table.textContent.includes("<img>"), true);28});2930test("chat tables preserve single columns and distinguish escaped trailing pipes", () => {31 const s = setup();32 const body = s.rooms.chatMarkdown(new FakeNode("div"), "| Value |\n| --- |\n| `a\\|b` |");33 assert.equal(body.querySelectorAll("table").length, 1);34 assert.equal(body.querySelector("th").textContent, "Value");35 assert.equal(body.querySelector("tbody code").textContent, "a|b");36 const prose = s.rooms.chatMarkdown(new FakeNode("div"), "A \\\\| B\n| --- |");37 assert.equal(prose.querySelectorAll("table").length, 0);38});3940test("malformed tables and tables in fenced code remain prose or code", () => {41 const s = setup();42 const body = s.rooms.chatMarkdown(new FakeNode("div"), "| Header | Other\n| -- | ---\n\n```\n| A | B |\n| --- | --- |\n```");43 assert.equal(body.querySelectorAll("[data-markdown-table]").length, 0);44 assert.equal(body.querySelectorAll("pre").length, 1);45 assert.equal(body.querySelector("p").textContent, "| Header | Other| -- | ---");46 assert.equal(body.querySelector("pre").textContent.includes("| A | B |"), true);47});4849test("rerendering edited chat content creates a fresh table node", () => {50 const s = setup();51 const body = new FakeNode("div");52 s.rooms.chatMarkdown(body, "| Before | State |\n| --- | --- |\n| old | draft |");53 assert.equal(body.querySelector("tbody td").textContent, "old");54 body.replaceChildren();55 s.rooms.chatMarkdown(body, "| After | State |\n| --- | --- |\n| new | sent |");56 assert.equal(body.querySelector("th").textContent, "After");57 assert.equal(body.querySelector("tbody td").textContent, "new");58});5960test("tables stop before headings and preserve backtick and tilde fences", () => {61 const s = setup();62 for (const marker of ["```", " ~~~~"]) {63 const body = s.rooms.chatMarkdown(new FakeNode("div"), "| Name | Value |\n| --- | --- |\n| one | two |\n" + marker + "text | example\n| A | B |\n|---|---|\n" + marker + "\n# Heading | text");64 assert.equal(body.querySelectorAll("table").length, 1);65 assert.equal(body.querySelector("th").getAttribute("data-align"), null);66 assert.equal(body.querySelectorAll("tbody tr").length, 1);67 assert.equal(body.querySelector("pre").textContent, "| A | B |\n|---|---|");68 assert.equal(body.children.find(node => node.localName === "h1").textContent, "Heading | text");69 }70});