1 Commits
Author SHA1 Message Date
sneak 4e93560eb1 Clock errors no longer stop probing; legend reads >=500ms (closes #149, closes #152)
check / check (push) Canceled after 0s
The header's clocks start last in init, after the rounds, and an error
formatting them, as in a browser that rejects the "shortGeneric" time
zone name, leaves both clocks blank instead of stopping the page before
its first round. updateClocks moved out of init so a unit test can call
it.

The footer legend's red entry reads >=500ms, as README.md and
CONFIG.latencyColors have it. buildUI is exported so a unit test can draw
the page and check the legend against every entry of
CONFIG.latencyColors.

Model: opus-5-5
2026-10-18 23:04:09 +00:00
2 changed files with 19 additions and 17 deletions
+6 -6
View File
@@ -24,14 +24,14 @@ Run `make frontend-viewport-test` in CI as its own step; it is not part of
- 2026-10-18: a browser that cannot format the header's clocks still probes
([#149](https://git.eeqj.de/sneak/netwatch/issues/149)). The clocks name the
local time zone through `Intl.DateTimeFormat`'s `shortGeneric` option, which
browsers from before 2022 reject with an error; it came before the first round
started, so such a browser never checked a target. The clocks now start last,
after the rounds, and an error formatting them leaves both blank. The footer's
color legend reads `>=500ms` for red, where it read `>500ms`, so 500 ms, which
is red, is in one of its colors
Chrome before 95, Firefox before 91 and Safari before 15.4 reject with an
error; it came before the first round started, so such a browser never checked
a target. The clocks now start last, after the rounds, and an error formatting
them leaves both blank. The footer's color legend reads `>=500ms` for red,
where it read `>500ms`, so 500 ms, which is red, is in one of its colors
([#152](https://git.eeqj.de/sneak/netwatch/issues/152)). Unit tests check the
clocks with a working `Intl.DateTimeFormat` and with one that rejects
`shortGeneric`, and draw the page and check the legend's limits against
`shortGeneric`, and draw the page and check the legend against every entry of
`CONFIG.latencyColors`
- 2026-10-18: from a trusted proxy, the backend takes the client address from
the right-most `X-Forwarded-For` entry that is not in `TRUSTED_PROXIES`
+13 -11
View File
@@ -588,9 +588,12 @@ test("a check that timed out or found its target unreachable has a grey figure a
// buildUI draws the page into #app, here a plain object. Each entry in the
// footer's color legend is a colored dot and the latencies it stands for,
// with < and > written as &lt; and &gt;. A latency takes the color of the
// first entry in CONFIG.latencyColors whose limit it is below, so red, the
// last, starts at orange's limit.
test("the footer's color legend gives the latency limits in CONFIG.latencyColors, each latency in one color", (t) => {
// first entry in CONFIG.latencyColors whose limit it is below, so the
// legend has, for each of those entries in order, a dot of its color (a
// bg- class where CONFIG.latencyColors has a text- one) and the latencies
// below its limit, or, for the last, which has no limit, the latencies
// from the limit before it up. A gray dot for offline comes after them.
test("the footer's color legend has each entry in CONFIG.latencyColors, with its color and limit, then offline", (t) => {
const app = {};
t.mock.method(globalThis.document, "getElementById", () => app);
buildUI(new AppState([]));
@@ -598,15 +601,14 @@ test("the footer's color legend gives the latency limits in CONFIG.latencyColors
const legend = [
...app.innerHTML.matchAll(/(bg-\w+-500) [^"]*"><\/span>(\S+)/g),
].map(([, dot, latencies]) => [dot, latencies]);
const limits = CONFIG.latencyColors.map((color) => color.below);
assert.deepEqual(legend, [
["bg-green-500", `&lt;${limits[0]}ms`],
["bg-lime-500", `&lt;${limits[1]}ms`],
["bg-yellow-500", `&lt;${limits[2]}ms`],
["bg-orange-500", `&lt;${limits[3]}ms`],
["bg-red-500", `&gt;=${limits[3]}ms`],
["bg-gray-500", "offline"],
const colors = CONFIG.latencyColors;
const expected = colors.map((color, i) => [
color.className.replace("text-", "bg-"),
color.below === Infinity
? `&gt;=${colors[i - 1].below}ms`
: `&lt;${color.below}ms`,
]);
assert.deepEqual(legend, [...expected, ["bg-gray-500", "offline"]]);
});
// A target whose checks, in turn, answered after each of latencies ms, or,