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 - 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 ([#149](https://git.eeqj.de/sneak/netwatch/issues/149)). The clocks name the
local time zone through `Intl.DateTimeFormat`'s `shortGeneric` option, which local time zone through `Intl.DateTimeFormat`'s `shortGeneric` option, which
browsers from before 2022 reject with an error; it came before the first round Chrome before 95, Firefox before 91 and Safari before 15.4 reject with an
started, so such a browser never checked a target. The clocks now start last, error; it came before the first round started, so such a browser never checked
after the rounds, and an error formatting them leaves both blank. The footer's a target. The clocks now start last, after the rounds, and an error formatting
color legend reads `>=500ms` for red, where it read `>500ms`, so 500 ms, which them leaves both blank. The footer's color legend reads `>=500ms` for red,
is red, is in one of its colors 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 ([#152](https://git.eeqj.de/sneak/netwatch/issues/152)). Unit tests check the
clocks with a working `Intl.DateTimeFormat` and with one that rejects 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` `CONFIG.latencyColors`
- 2026-10-18: from a trusted proxy, the backend takes the client address from - 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` 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 // 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, // 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 // 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 // first entry in CONFIG.latencyColors whose limit it is below, so the
// last, starts at orange's limit. // legend has, for each of those entries in order, a dot of its color (a
test("the footer's color legend gives the latency limits in CONFIG.latencyColors, each latency in one color", (t) => { // 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 = {}; const app = {};
t.mock.method(globalThis.document, "getElementById", () => app); t.mock.method(globalThis.document, "getElementById", () => app);
buildUI(new AppState([])); buildUI(new AppState([]));
@@ -598,15 +601,14 @@ test("the footer's color legend gives the latency limits in CONFIG.latencyColors
const legend = [ const legend = [
...app.innerHTML.matchAll(/(bg-\w+-500) [^"]*"><\/span>(\S+)/g), ...app.innerHTML.matchAll(/(bg-\w+-500) [^"]*"><\/span>(\S+)/g),
].map(([, dot, latencies]) => [dot, latencies]); ].map(([, dot, latencies]) => [dot, latencies]);
const limits = CONFIG.latencyColors.map((color) => color.below); const colors = CONFIG.latencyColors;
assert.deepEqual(legend, [ const expected = colors.map((color, i) => [
["bg-green-500", `&lt;${limits[0]}ms`], color.className.replace("text-", "bg-"),
["bg-lime-500", `&lt;${limits[1]}ms`], color.below === Infinity
["bg-yellow-500", `&lt;${limits[2]}ms`], ? `&gt;=${colors[i - 1].below}ms`
["bg-orange-500", `&lt;${limits[3]}ms`], : `&lt;${color.below}ms`,
["bg-red-500", `&gt;=${limits[3]}ms`],
["bg-gray-500", "offline"],
]); ]);
assert.deepEqual(legend, [...expected, ["bg-gray-500", "offline"]]);
}); });
// A target whose checks, in turn, answered after each of latencies ms, or, // A target whose checks, in turn, answered after each of latencies ms, or,