mirror of
https://github.com/snapotter-hq/SnapOtter.git
synced 2026-08-03 07:46:42 +02:00
feat(landing): add a live system status indicator to the footer (#641)
Adds /api/status to the landing Pages worker, HEAD-probing demo.snapotter.com and docs.snapotter.com with a 2 second per-attempt deadline and one retry. snapotter.com is not probed; the worker answering the request is the proof it is up. The footer badge ships grey in the static HTML and only upgrades once the route answers. A rejected fetch, a non-ok response, an unparseable body, and an unrecognized verdict all leave it grey, so it never claims green on its own. Color lives in the dot, never the label: `--color-success` scores 4.498:1 against the footer's `--color-background-alt`, just under AA. Four labels across 21 locales.
This commit is contained in:
@@ -0,0 +1,47 @@
|
||||
import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
import { SUPPORTED_LOCALES } from "@snapotter/shared";
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
/**
|
||||
* The footer status badge resolves all four labels server-side and hands them
|
||||
* to its inline script, so a catalog gap is invisible on the English page and
|
||||
* only shows on the localized one.
|
||||
*
|
||||
* `t()` falls back with `??`, which does not fall through on `""`. An empty
|
||||
* translation therefore resolves to an empty string rather than English, and
|
||||
* the badge would sit blank on that locale forever. Scoped to these four keys
|
||||
* on purpose: a whole-catalog parity guard is worth having but is a separate
|
||||
* change, and would trip on pre-existing debt.
|
||||
*/
|
||||
|
||||
const I18N_DIR = path.resolve(__dirname, "../../apps/landing/src/i18n");
|
||||
|
||||
const STATUS_KEYS = [
|
||||
"footer.status.checking",
|
||||
"footer.status.operational",
|
||||
"footer.status.partial",
|
||||
"footer.status.down",
|
||||
];
|
||||
|
||||
const locales = SUPPORTED_LOCALES.map((l) => l.code);
|
||||
|
||||
function catalog(locale: string): Record<string, string> {
|
||||
return JSON.parse(fs.readFileSync(path.join(I18N_DIR, `${locale}.json`), "utf-8"));
|
||||
}
|
||||
|
||||
describe("landing footer status labels", () => {
|
||||
it("covers every supported locale", () => {
|
||||
// Guards the loop below: if the locale list were ever empty or unresolvable
|
||||
// the per-locale assertions would vacuously pass.
|
||||
expect(locales.length).toBe(21);
|
||||
});
|
||||
|
||||
it.each(locales)("%s defines all four status labels as non-empty strings", (locale) => {
|
||||
const strings = catalog(locale);
|
||||
for (const key of STATUS_KEYS) {
|
||||
expect(typeof strings[key], `${locale}.json is missing ${key}`).toBe("string");
|
||||
expect(strings[key].trim(), `${locale}.json has an empty ${key}`).not.toBe("");
|
||||
}
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user