Files
HealthLog/src/components/settings/integrations/__tests__/pill-mapper.test.tsx
T

142 lines
4.4 KiB
TypeScript

/**
* One verdict, one pill mapping.
*
* There used to be three `pillStateFor` implementations — one per card family —
* and they disagreed with each other. The same ledger state painted red on the
* Withings card and orange on the Polar card, on the same page. The server now
* resolves the verdict once; this pins that the client projects it once, and
* that a fourth dialect cannot be minted without someone editing this file.
*/
import { describe, expect, it } from "vitest";
import { readFileSync } from "node:fs";
import { join, sep } from "node:path";
import { globSync } from "node:fs";
import type { SyncVerdict } from "@/lib/integrations/sync-verdict";
import {
pickStatus,
pillFailurePropsFor,
pillStateForVerdict,
} from "../shared";
describe("pillStateForVerdict — the verdict→pill table", () => {
const table: Array<[SyncVerdict | undefined, string]> = [
["fresh", "connected"],
["stale", "stale"],
["stalled", "stalled"],
["failing", "warning"],
["reauth_required", "error"],
["parked", "parked"],
["pending_first_sync", "pending-setup"],
["disconnected", "disconnected"],
// Still loading: the card renders its neutral default rather than
// guessing at a status it has not been told.
[undefined, "disconnected"],
];
it.each(table)("maps %s to the %s pill", (verdict, expected) => {
expect(pillStateForVerdict(verdict)).toBe(expected);
});
/**
* The decision this release makes and must not silently lose: **red means
* "your action fixes this"**. Reconnecting cannot repair an upstream 503 or
* a cron that stopped running, so neither of those may reach the destructive
* pill.
*/
it("reserves the error pill for the states a reconnect actually fixes", () => {
const red = table
.filter(([, state]) => state === "error")
.map(([verdict]) => verdict);
expect(red).toEqual(["reauth_required"]);
expect(pillStateForVerdict("failing")).not.toBe("error");
expect(pillStateForVerdict("stalled")).not.toBe("error");
});
});
describe("pillFailurePropsFor", () => {
it("projects the active bucket and envelope threshold onto the pill", () => {
const status = pickStatus(
{
threshold: 3,
integrations: [
{
integration: "withings",
state: "error_transient",
lastSuccessAt: null,
lastAttemptAt: "2026-07-28T12:00:00.000Z",
lastError: "upstream unavailable",
consecutiveFailuresByKind: {
transient: 2,
reauth_required: 0,
persistent: 1,
},
},
],
},
"withings",
);
expect(pillFailurePropsFor(status)).toEqual({
failureCount: 2,
failureThreshold: 3,
});
});
it("returns no ratio for a healthy zero-count status", () => {
const status = pickStatus(
{
threshold: 3,
integrations: [
{
integration: "withings",
state: "connected",
lastSuccessAt: "2026-07-28T12:00:00.000Z",
lastAttemptAt: "2026-07-28T12:00:00.000Z",
lastError: null,
consecutiveFailuresByKind: {
transient: 0,
reauth_required: 0,
persistent: 0,
},
},
],
},
"withings",
);
expect(pillFailurePropsFor(status)).toEqual({});
});
});
describe("structural guard — no second pill dialect", () => {
const SRC = join(process.cwd(), "src");
function sourceFiles(): string[] {
return globSync("**/*.{ts,tsx}", { cwd: SRC })
.filter(
(p) => !p.startsWith(`generated${sep}`) && !p.startsWith("generated/"),
)
.filter((p) => !p.includes("__tests__"))
.filter((p) => !p.endsWith(".test.ts") && !p.endsWith(".test.tsx"))
.map((p) => p.split(sep).join("/"))
.sort();
}
/**
* The one module allowed to define a status→pill mapping. A tripwire, not a
* proof: it cannot show the mapping is right, only that nobody added a
* second one without editing this file.
*/
const MAPPER_HOME = "components/settings/integrations/shared.tsx";
it("defines the mapping in exactly one module", () => {
const definers = sourceFiles().filter((rel) =>
/function\s+pillStateFor\w*\s*\(/.test(
readFileSync(join(SRC, rel), "utf8"),
),
);
expect(definers).toEqual([MAPPER_HOME]);
});
});