Target names, URLs and log lines reach the page as text (closes #29)
check / check (push) Successful in 3m29s

A host row escapes the name and URL it writes into its markup with a new
escapeHTML function, and the debug log builds each line as an element
whose text is set, so neither is read as HTML once targets can be
configured. A unit test builds the row of a target named <b>x</b>;
hostRowHTML is exported for it.

README.md stops calling CONFIG frozen: the interval menu changes
updateInterval. AppState declares _recoveryProbeId and
_recoveryProbeChecks, the sparkline axis functions drop the parameters
they never used, and HostState's history comment names both entry
shapes.

Model: opus-5-5
This commit is contained in:
2026-10-04 02:01:52 +00:00
parent 9b548da90d
commit 87a2305048
4 changed files with 61 additions and 16 deletions
+14
View File
@@ -8,6 +8,7 @@ import {
AppState,
CONFIG,
greyOutUI,
hostRowHTML,
HostState,
humanDuration,
latencyClass,
@@ -230,6 +231,19 @@ test("at a 30000ms interval, after the user pauses and resumes during a round, n
}
});
// The page shows &lt; in a row's markup as < and &gt; as >.
test("a target named <b>x</b> shows those characters in its row, as does its URL", () => {
const host = new HostState({
name: "<b>x</b>",
url: "https://x.test/<b>x</b>",
});
const row = hostRowHTML(host, 0);
assert.doesNotMatch(row, /<b>/);
assert.ok(row.includes(">&lt;b&gt;x&lt;/b&gt;</span>"));
assert.ok(row.includes('href="https://x.test/&lt;b&gt;x&lt;/b&gt;"'));
assert.ok(row.includes(">https://x.test/&lt;b&gt;x&lt;/b&gt;</a>"));
});
for (const [seconds, text] of [
[0, "0s"],
[1, "1s"],