Files
HealthLog/src/components/settings/__tests__/layout-groups.test.ts
T
Marc-André Bombeck 71dbef1742 feat(settings): nine groups, module pages and one switch per state
Settings now reads as nine groups: Account, Tracking, Arrangement,
Notifications, Health profile, AI, Connections, Data and System. On a
phone one button names the current section and opens the grouped list,
replacing the strip of every section.

What moved, every old address still working:
- Sessions, trusted devices and security activity sit under Security;
  the privacy page anchors forward there.
- Notifications holds every reminder kind: the Coach nudges and the
  checkup reminder switches joined, and a card names the reminders set
  where their subject lives (dose times, cycle reminders).
- Arrangement holds order and view only. Mood tags, the labs biomarker
  catalog and on-device text recognition, and the injection sites live on
  module pages under /settings/modules/<id>, linked from each Modules row
  and from the module's own wrench. /settings/layout/mood redirects.
- The timezone saves on change in the Display card, with a one-tap offer
  of the device zone.
- Screening hints sit beside the life circumstances they come from.
- System gains Preview features with the Topics switch.

Duplicates: the Coach and MCP pages show their state and link to the one
switch in Modules (turning MCP off keeps tokens), the Coach overlay shows
the provider and model with a link to Settings > AI instead of a second
set of selects, and the privacy page drops its copy of the export links.

A guard walks every historical /settings address through the redirects
and every forwarded anchor to a page that renders.
2026-10-21 19:43:02 +02:00

88 lines
3.4 KiB
TypeScript

/**
* v1.25.11 (#148) — the shared Appearance group registry.
*
* `layout-groups` is the single source of truth consumed by BOTH the client
* hub (`layout-section.tsx`) and the server subpage route
* (`app/settings/layout/[module]/page.tsx`, via `LAYOUT_GROUP_IDS` in
* `generateStaticParams()`). These tests pin the param → section mapping: the
* id list (the statically-generated subpage params), the guard, the per-module
* gate expectations, and that each group resolves a distinct section body.
*/
import { describe, expect, it, vi } from "vitest";
// Stub the section components at the import boundary — each has its own test;
// here we only assert the registry's metadata + identity mapping, and we keep
// the heavy section trees out of the unit import graph.
vi.mock("../dashboard-section", () => ({ DashboardSection: () => null }));
vi.mock("../insights-section", () => ({ InsightsSection: () => null }));
vi.mock("../medications-section", () => ({ MedicationsSection: () => null }));
vi.mock("../labs-section", () => ({ LabsSection: () => null }));
vi.mock("../illness-section", () => ({ IllnessSection: () => null }));
vi.mock("../vorsorge-section", () => ({ VorsorgeSection: () => null }));
import {
LAYOUT_GROUPS,
LAYOUT_GROUP_IDS,
isLayoutGroupId,
layoutGroupModule,
} from "../layout-groups";
describe("layout-groups registry", () => {
it("exposes the seven Arrangement modules as statically-generated subpage params", () => {
// v1.44 — mood left: its page was tag management, which lives under
// Settings > Modules > Mood now (`/settings/layout/mood` redirects).
expect(LAYOUT_GROUP_IDS).toEqual([
"dashboard",
"insights",
"medications",
"labs",
"illness",
"documents",
"vorsorge",
]);
// generateStaticParams() shape.
expect(LAYOUT_GROUP_IDS.map((module) => ({ module }))).toEqual([
{ module: "dashboard" },
{ module: "insights" },
{ module: "medications" },
{ module: "labs" },
{ module: "illness" },
{ module: "documents" },
{ module: "vorsorge" },
]);
});
it("guards unknown segments", () => {
expect(isLayoutGroupId("medications")).toBe(true);
expect(isLayoutGroupId("vorsorge")).toBe(true);
expect(isLayoutGroupId("nope")).toBe(false);
expect(isLayoutGroupId("")).toBe(false);
});
it("gates the toggleable tracking modules and leaves the rest always-on", () => {
const gate = (id: string) =>
LAYOUT_GROUPS.some((group) => group.id === id)
? layoutGroupModule(id)
: "not-a-group";
expect(gate("medications")).toBe("medications");
expect(gate("mood")).toBe("not-a-group");
expect(gate("labs")).toBe("labs");
expect(gate("illness")).toBe("illness");
// dashboard / insights / vorsorge are never gated.
expect(gate("dashboard")).toBeUndefined();
expect(gate("insights")).toBeUndefined();
expect(gate("vorsorge")).toBeUndefined();
});
it("maps every id to a distinct section body and the canonical i18n keys", () => {
const bodies = new Set(LAYOUT_GROUPS.map((group) => group.Body));
expect(bodies.size).toBe(LAYOUT_GROUPS.length);
for (const group of LAYOUT_GROUPS) {
expect(group.titleKey).toBe(`settings.sections.layout.${group.id}.title`);
expect(group.descriptionKey).toBe(
`settings.sections.layout.${group.id}.description`,
);
}
});
});