1 Commits
Author SHA1 Message Date
sneak 58560a0f44 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's limits against CONFIG.latencyColors.

Model: opus-5-5
2026-10-18 22:34:25 +00:00
2 changed files with 17 additions and 19 deletions

No files matched your search

+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
Chrome before 95, Firefox before 91 and Safari before 15.4 reject with an browsers from before 2022 reject with an error; it came before the first round
error; it came before the first round started, so such a browser never checked started, so such a browser never checked a target. The clocks now start last,
a target. The clocks now start last, after the rounds, and an error formatting after the rounds, and an error formatting them leaves both blank. The footer's
them leaves both blank. The footer's color legend reads `>=500ms` for red, color legend reads `>=500ms` for red, where it read `>500ms`, so 500 ms, which
where it read `>500ms`, so 500 ms, which is red, is in one of its colors 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 against every entry of `shortGeneric`, and draw the page and check the legend's limits against
`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`
+11 -13
View File
@@ -588,12 +588,9 @@ 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 the // first entry in CONFIG.latencyColors whose limit it is below, so red, the
// legend has, for each of those entries in order, a dot of its color (a // last, starts at orange's limit.
// bg- class where CONFIG.latencyColors has a text- one) and the latencies test("the footer's color legend gives the latency limits in CONFIG.latencyColors, each latency in one color", (t) => {
// 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([]));
@@ -601,14 +598,15 @@ test("the footer's color legend has each entry in CONFIG.latencyColors, with its
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 colors = CONFIG.latencyColors; const limits = CONFIG.latencyColors.map((color) => color.below);
const expected = colors.map((color, i) => [ assert.deepEqual(legend, [
color.className.replace("text-", "bg-"), ["bg-green-500", `&lt;${limits[0]}ms`],
color.below === Infinity ["bg-lime-500", `&lt;${limits[1]}ms`],
? `&gt;=${colors[i - 1].below}ms` ["bg-yellow-500", `&lt;${limits[2]}ms`],
: `&lt;${color.below}ms`, ["bg-orange-500", `&lt;${limits[3]}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,