Files
glances/tests/js/refresh.test.mjs
T
Claude 1544a8096a WebUI v5: add version/links and a refresh stepper to the footer
The footer only carried the poll cadence as a read-only label. It now has
two ends:

- Left: "Glances v<release> · GitHub · API". The release comes from the
  /status health probe, which now serves it as `glances_version` next to
  the API version (v4 already serves the release from its own /status).
  The /docs link appears only when `[outputs] api_doc` is on -- the same
  key webserver_v5.build_app() reads to decide whether FastAPI mounts
  Swagger UI at all, so the link can never point at a 404.

- Right: "Refresh: - Ns +". The two steppers walk a fixed ladder
  (1, 2, 3, 5, 10, 15, 30, 60 s) so the whole range is seven clicks wide
  instead of fifty-eight, clamping at both ends rather than wrapping. The
  chosen cadence is remembered in localStorage and re-armed on the poll
  timer immediately; `[global] refresh` stays the value a first visit
  starts at.

Both ends are deliberately quiet: one size below the body text, muted,
dotted underlines instead of browser-blue links, and steppers with no
border or background. The cadence sits in a fixed-width box so stepping
2s -> 10s does not slide the "+" out from under the pointer.

The render probe's fake elements gained a `disabled` property on
<button>: Vue's shouldSetAsProp() tests `key in el`, and without it
`:disabled` fell back to setAttribute("disabled", "false") -- an
attribute whose mere presence disables a button in a real browser.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VeEhhw7pcPvZRguFPALgwh
2026-09-20 15:54:40 +00:00

79 lines
2.4 KiB
JavaScript

import { test, beforeEach } from "node:test";
import assert from "node:assert/strict";
import {
REFRESH_STEPS,
stepRefresh,
loadRefresh,
saveRefresh,
} from "../../glances/outputs/static/js/v5/refresh.js";
function stubStorage(initial) {
const store = { ...initial };
globalThis.localStorage = {
getItem: (key) => (key in store ? store[key] : null),
setItem: (key, value) => {
store[key] = value;
},
};
return store;
}
beforeEach(() => {
delete globalThis.localStorage;
});
test("the ladder spans the whole 1..60 s range the footer advertises", () => {
assert.equal(REFRESH_STEPS[0], 1);
assert.equal(REFRESH_STEPS[REFRESH_STEPS.length - 1], 60);
const sorted = [...REFRESH_STEPS].sort((a, b) => a - b);
assert.deepEqual(REFRESH_STEPS, sorted, "stepRefresh scans the ladder in order");
});
test("stepping moves one rung in the asked direction", () => {
assert.equal(stepRefresh(2, 1), 3);
assert.equal(stepRefresh(2, -1), 1);
assert.equal(stepRefresh(15, 1), 30);
assert.equal(stepRefresh(15, -1), 10);
});
test("stepping clamps at both ends instead of wrapping", () => {
// A "+" that jumped back to 1 s would silently make the page poll 60x
// faster -- the opposite of what the click asked for.
assert.equal(stepRefresh(60, 1), 60);
assert.equal(stepRefresh(1, -1), 1);
});
test("stepping from an off-ladder cadence lands on the nearest rung", () => {
// `[global] refresh=4` is legal and is not a rung.
assert.equal(stepRefresh(4, 1), 5);
assert.equal(stepRefresh(4, -1), 3);
// A config value past the top of the ladder is pulled back onto it.
assert.equal(stepRefresh(120, -1), 60);
assert.equal(stepRefresh(120, 1), 60);
});
test("loadRefresh returns null when nothing was ever saved", () => {
stubStorage({});
assert.equal(loadRefresh(), null);
});
test("loadRefresh returns null rather than repairing an unusable value", () => {
stubStorage({ "glances.refresh": "not a number" });
assert.equal(loadRefresh(), null);
stubStorage({ "glances.refresh": "0" });
assert.equal(loadRefresh(), null);
});
test("a saved cadence survives the reload", () => {
stubStorage({});
saveRefresh(15);
assert.equal(loadRefresh(), 15);
});
test("no localStorage at all degrades to 'not remembered', never to a throw", () => {
// Private browsing, blocked site data, and the render probe's DOM stub all
// look like this.
assert.equal(loadRefresh(), null);
assert.doesNotThrow(() => saveRefresh(5));
});