mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-11 05:42:19 +00:00
style(labs): format the filter rail files
This commit is contained in:
1 parent
c59f4d7e65
commit
ba3ee968c7
11 files changed
+74
-45
No files matched your search
@@ -72,9 +72,9 @@ describe("<LabFilterRail> layout", () => {
|
||||
.closest('[data-slot="filter-bar"]')
|
||||
?.querySelector("svg.lucide-list-filter, svg.lucide-funnel");
|
||||
expect(icon).toBeTruthy();
|
||||
expect(Math.abs(centerY(icon!) - centerY(dateRange.element()))).toBeLessThan(
|
||||
2,
|
||||
);
|
||||
expect(
|
||||
Math.abs(centerY(icon!) - centerY(dateRange.element())),
|
||||
).toBeLessThan(2);
|
||||
expect(document.documentElement.scrollWidth).toBeLessThanOrEqual(390);
|
||||
});
|
||||
|
||||
@@ -199,7 +199,9 @@ describe("<LabFilterRail> keyboard", () => {
|
||||
const search = screen.getByRole("searchbox", { name: "Search biomarkers" });
|
||||
|
||||
(
|
||||
screen.getByRole("button", { name: "Open dialog" }).element() as HTMLElement
|
||||
screen
|
||||
.getByRole("button", { name: "Open dialog" })
|
||||
.element() as HTMLElement
|
||||
).focus();
|
||||
await userEvent.keyboard("/");
|
||||
await expect.element(search).toHaveFocus();
|
||||
|
||||
@@ -83,14 +83,12 @@ describe("<LabFilterRail>", () => {
|
||||
);
|
||||
|
||||
expect(html).toContain('aria-label="Clear search"');
|
||||
expect(html).not.toContain('<kbd');
|
||||
expect(html).not.toContain("<kbd");
|
||||
});
|
||||
|
||||
it("pluralizes marker count with tCount across locales", () => {
|
||||
const extractCountText = (html: string) => {
|
||||
const match = html.match(
|
||||
/<span[^>]*tabular-nums[^>]*>([^<]+)<\/span>/,
|
||||
);
|
||||
const match = html.match(/<span[^>]*tabular-nums[^>]*>([^<]+)<\/span>/);
|
||||
return match ? match[1].trim() : null;
|
||||
};
|
||||
|
||||
@@ -106,7 +104,7 @@ describe("<LabFilterRail>", () => {
|
||||
onCategoryChange={vi.fn()}
|
||||
onFromDayChange={vi.fn()}
|
||||
onToDayChange={vi.fn()}
|
||||
onResetFilters={vi.fn()}
|
||||
onResetFilters={vi.fn()}
|
||||
isFiltered={false}
|
||||
total={total}
|
||||
/>
|
||||
|
||||
@@ -178,9 +178,7 @@ describe("filterMarkerRows", () => {
|
||||
accented,
|
||||
]);
|
||||
expect(filterMarkerRows([accented], { q: "hämo" })).toEqual([accented]);
|
||||
expect(filterMarkerRows([accented], { q: "blutbild" })).toEqual([
|
||||
accented,
|
||||
]);
|
||||
expect(filterMarkerRows([accented], { q: "blutbild" })).toEqual([accented]);
|
||||
expect(filterMarkerRows([accented], { q: "ferritin" })).toEqual([]);
|
||||
});
|
||||
|
||||
@@ -269,12 +267,7 @@ describe("filterMarkerRows", () => {
|
||||
),
|
||||
).toEqual([]);
|
||||
expect(
|
||||
filterMarkerRows(
|
||||
[lateRow],
|
||||
{ toDay: "2026-08-31" },
|
||||
undefined,
|
||||
dayKeyNy,
|
||||
),
|
||||
filterMarkerRows([lateRow], { toDay: "2026-08-31" }, undefined, dayKeyNy),
|
||||
).toEqual([lateRow]);
|
||||
});
|
||||
});
|
||||
@@ -319,8 +312,12 @@ describe("labReadingDayKey", () => {
|
||||
it("keeps noon UTC anchors on their stated date across all timezones", () => {
|
||||
const noonInstant = "2026-09-01T12:00:00.000Z";
|
||||
expect(labReadingDayKey(noonInstant, "UTC")).toBe("2026-09-01");
|
||||
expect(labReadingDayKey(noonInstant, "America/New_York")).toBe("2026-09-01");
|
||||
expect(labReadingDayKey(noonInstant, "Pacific/Kiritimati")).toBe("2026-09-01");
|
||||
expect(labReadingDayKey(noonInstant, "America/New_York")).toBe(
|
||||
"2026-09-01",
|
||||
);
|
||||
expect(labReadingDayKey(noonInstant, "Pacific/Kiritimati")).toBe(
|
||||
"2026-09-01",
|
||||
);
|
||||
});
|
||||
|
||||
it("documents exact-noon date-anchor ambiguity vs true instant timestamps", () => {
|
||||
@@ -329,12 +326,16 @@ describe("labReadingDayKey", () => {
|
||||
// `useLabDate` / `date-only.ts`. In Pacific/Kiritimati (UTC+14), 12:00 UTC would be
|
||||
// 02:00 on the NEXT calendar day if treated as an instant; but as an anchor it stays 2026-09-01.
|
||||
const noonAnchor = "2026-09-01T12:00:00.000Z";
|
||||
expect(labReadingDayKey(noonAnchor, "Pacific/Kiritimati")).toBe("2026-09-01");
|
||||
expect(labReadingDayKey(noonAnchor, "Pacific/Kiritimati")).toBe(
|
||||
"2026-09-01",
|
||||
);
|
||||
|
||||
// Any non-noon instant (even 1 second off noon) is recognized as a true instant with time
|
||||
// and correctly shifts to the local date in the user's timezone:
|
||||
const nonNoonInstant = "2026-09-01T12:00:01.000Z";
|
||||
expect(labReadingDayKey(nonNoonInstant, "Pacific/Kiritimati")).toBe("2026-09-02");
|
||||
expect(labReadingDayKey(nonNoonInstant, "Pacific/Kiritimati")).toBe(
|
||||
"2026-09-02",
|
||||
);
|
||||
expect(labReadingDayKey(nonNoonInstant, "UTC")).toBe("2026-09-01");
|
||||
});
|
||||
|
||||
|
||||
@@ -3,7 +3,10 @@ import type { QueryClient } from "@tanstack/react-query";
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
import { queryKeys } from "@/lib/query-keys";
|
||||
import { renderWithApp, testQueryClient } from "../../../../tests/browser/render";
|
||||
import {
|
||||
renderWithApp,
|
||||
testQueryClient,
|
||||
} from "../../../../tests/browser/render";
|
||||
import {
|
||||
currentSearch,
|
||||
recordHistory,
|
||||
@@ -210,7 +213,9 @@ describe("LabList stale category and group header handling", () => {
|
||||
// Group header button shows the filtered count ("1 of 1 outside range") and chip "1"
|
||||
const groupButton = screen.getByRole("button", { name: /Iron Panel/i });
|
||||
await expect.element(groupButton).toBeVisible();
|
||||
await expect.element(groupButton.getByText("1 of 1 outside range")).toBeVisible();
|
||||
await expect
|
||||
.element(groupButton.getByText("1 of 1 outside range"))
|
||||
.toBeVisible();
|
||||
await expect.element(groupButton.getByText("1")).toBeVisible();
|
||||
});
|
||||
|
||||
|
||||
@@ -52,7 +52,8 @@ const mockModulePrefs: ModuleListPrefs = {
|
||||
};
|
||||
|
||||
vi.mock("@/lib/module-list-prefs", async (importOriginal) => {
|
||||
const actual = await importOriginal<typeof import("@/lib/module-list-prefs")>();
|
||||
const actual =
|
||||
await importOriginal<typeof import("@/lib/module-list-prefs")>();
|
||||
return {
|
||||
...actual,
|
||||
useModuleListPrefs: () => ({
|
||||
|
||||
@@ -35,7 +35,8 @@ vi.mock("@/lib/i18n/context", async (importOriginal) => {
|
||||
});
|
||||
|
||||
vi.mock("@/lib/module-list-prefs", async (importOriginal) => {
|
||||
const actual = await importOriginal<typeof import("@/lib/module-list-prefs")>();
|
||||
const actual =
|
||||
await importOriginal<typeof import("@/lib/module-list-prefs")>();
|
||||
return {
|
||||
...actual,
|
||||
useModuleListPrefs: () => ({
|
||||
|
||||
@@ -106,7 +106,7 @@ export function LabFilterRail({
|
||||
searchInputRef.current?.focus();
|
||||
}}
|
||||
aria-label={t("labs.filter.clearSearch")}
|
||||
className="text-muted-foreground hover:text-foreground focus-visible:ring-ring/50 absolute top-1/2 right-0 inline-flex size-11 -translate-y-1/2 sm:size-10 items-center justify-center rounded-full outline-none focus-visible:ring-[3px]"
|
||||
className="text-muted-foreground hover:text-foreground focus-visible:ring-ring/50 absolute top-1/2 right-0 inline-flex size-11 -translate-y-1/2 items-center justify-center rounded-full outline-none focus-visible:ring-[3px] sm:size-10"
|
||||
>
|
||||
<X className="size-4" aria-hidden="true" />
|
||||
</button>
|
||||
|
||||
@@ -174,7 +174,9 @@ export interface LabGroupSummary {
|
||||
}
|
||||
|
||||
/** Summarise counts and overall status for a list of rows. */
|
||||
export function summariseGroupRows(rows: readonly MarkerRow[]): LabGroupSummary {
|
||||
export function summariseGroupRows(
|
||||
rows: readonly MarkerRow[],
|
||||
): LabGroupSummary {
|
||||
const counts = { inRange: 0, below: 0, above: 0, unknown: 0 };
|
||||
for (const row of rows) {
|
||||
const s = row.latest.rangeStatus;
|
||||
@@ -278,9 +280,7 @@ export function LabGroupHeader({
|
||||
<span className="text-muted-foreground min-w-0 truncate text-xs font-medium tracking-wide uppercase">
|
||||
{category.label}
|
||||
</span>
|
||||
<TagChip className="shrink-0 tabular-nums">
|
||||
{rows.length}
|
||||
</TagChip>
|
||||
<TagChip className="shrink-0 tabular-nums">{rows.length}</TagChip>
|
||||
<span className="ml-auto shrink-0">
|
||||
<GroupStatus counts={counts} status={status} />
|
||||
</span>
|
||||
|
||||
@@ -42,10 +42,7 @@ import {
|
||||
toMarkerRows,
|
||||
type MarkerRow,
|
||||
} from "./lab-list-rows";
|
||||
import type {
|
||||
LabOverviewCategoryDto,
|
||||
LabOverviewResponse,
|
||||
} from "./types";
|
||||
import type { LabOverviewCategoryDto, LabOverviewResponse } from "./types";
|
||||
|
||||
type GroupsOpen = ReturnType<typeof useGroupsOpen>;
|
||||
|
||||
|
||||
@@ -112,10 +112,7 @@ function FilterRail({ syncToUrl = true }: { syncToUrl?: boolean }) {
|
||||
<button
|
||||
type="button"
|
||||
onClick={() =>
|
||||
patchFilters(
|
||||
{ type: "PULSE" },
|
||||
{ mode: "replace", afterPaint: true },
|
||||
)
|
||||
patchFilters({ type: "PULSE" }, { mode: "replace", afterPaint: true })
|
||||
}
|
||||
>
|
||||
Defer replace type
|
||||
@@ -208,7 +205,9 @@ describe("useUrlFilterSync with FilterBar", () => {
|
||||
const { screen, history } = await mount("?type=WEIGHT");
|
||||
const entries = window.history.length;
|
||||
(
|
||||
screen.getByRole("button", { name: "Defer replace type" }).element() as HTMLButtonElement
|
||||
screen
|
||||
.getByRole("button", { name: "Defer replace type" })
|
||||
.element() as HTMLButtonElement
|
||||
).click();
|
||||
|
||||
// Immediately after trigger, the write is deferred until after paint:
|
||||
|
||||
@@ -68,19 +68,44 @@ describe("formatReferenceRange", () => {
|
||||
describe("priorityReferenceRangeStatus", () => {
|
||||
it("implements canonical priority: above > below > in-range > unknown with counts", () => {
|
||||
expect(
|
||||
priorityReferenceRangeStatus({ above: 1, below: 1, inRange: 1, unknown: 1 }),
|
||||
priorityReferenceRangeStatus({
|
||||
above: 1,
|
||||
below: 1,
|
||||
inRange: 1,
|
||||
unknown: 1,
|
||||
}),
|
||||
).toBe("above");
|
||||
expect(
|
||||
priorityReferenceRangeStatus({ above: 0, below: 2, inRange: 5, unknown: 1 }),
|
||||
priorityReferenceRangeStatus({
|
||||
above: 0,
|
||||
below: 2,
|
||||
inRange: 5,
|
||||
unknown: 1,
|
||||
}),
|
||||
).toBe("below");
|
||||
expect(
|
||||
priorityReferenceRangeStatus({ above: 0, below: 0, inRange: 3, unknown: 2 }),
|
||||
priorityReferenceRangeStatus({
|
||||
above: 0,
|
||||
below: 0,
|
||||
inRange: 3,
|
||||
unknown: 2,
|
||||
}),
|
||||
).toBe("in-range");
|
||||
expect(
|
||||
priorityReferenceRangeStatus({ above: 0, below: 0, inRange: 0, unknown: 4 }),
|
||||
priorityReferenceRangeStatus({
|
||||
above: 0,
|
||||
below: 0,
|
||||
inRange: 0,
|
||||
unknown: 4,
|
||||
}),
|
||||
).toBe("unknown");
|
||||
expect(
|
||||
priorityReferenceRangeStatus({ above: 0, below: 0, inRange: 0, unknown: 0 }),
|
||||
priorityReferenceRangeStatus({
|
||||
above: 0,
|
||||
below: 0,
|
||||
inRange: 0,
|
||||
unknown: 0,
|
||||
}),
|
||||
).toBe("unknown");
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user