diff --git a/src/components/cycle/__tests__/cycle-insight-summary-card.test.tsx b/src/components/cycle/__tests__/cycle-insight-summary-card.test.tsx index f7a72f259..385df6d05 100644 --- a/src/components/cycle/__tests__/cycle-insight-summary-card.test.tsx +++ b/src/components/cycle/__tests__/cycle-insight-summary-card.test.tsx @@ -1,6 +1,29 @@ import { describe, it, expect, vi, beforeEach } from "vitest"; import { renderToStaticMarkup } from "react-dom/server"; +// The embedded crosstab reads the unit preference through `useUnitDisplay`, +// which hangs off `useAuth` (a react-query hook). These are static SSR renders +// with no QueryClient, so mock the hook to a real metric-preference impl. +vi.mock("@/hooks/use-unit-display", async () => { + const dt = await import("@/lib/measurements/display-transform"); + const forType = (t: string) => dt.getDisplayTransform(t, "metric"); + return { + useUnitDisplay: () => ({ + preference: "metric" as const, + transformFor: forType, + toDisplay: (t: string, v: number) => + dt.applyDisplayTransform(v, forType(t)), + fromDisplay: (t: string, v: number) => + dt.invertDisplayTransform(v, forType(t)), + toDisplayDelta: (t: string, v: number) => + dt.applyDisplayTransformDelta(v, forType(t)), + unitFor: (t: string) => forType(t).displayUnit, + decimalsFor: (t: string) => forType(t).decimals, + isTransformed: (t: string) => dt.hasDisplayTransform(t), + }), + }; +}); + import { I18nProvider } from "@/lib/i18n/context"; import type { CalendarResponse } from "../types"; import type { CycleInsightsResponse } from "../use-cycle"; diff --git a/src/components/cycle/__tests__/cycle-phase-crosstab.test.tsx b/src/components/cycle/__tests__/cycle-phase-crosstab.test.tsx index 1691a7f67..82aec2b28 100644 --- a/src/components/cycle/__tests__/cycle-phase-crosstab.test.tsx +++ b/src/components/cycle/__tests__/cycle-phase-crosstab.test.tsx @@ -1,6 +1,31 @@ -import { describe, it, expect } from "vitest"; +import { describe, it, expect, vi } from "vitest"; import { renderToStaticMarkup } from "react-dom/server"; +// The crosstab reads the unit preference through `useUnitDisplay`, which hangs +// off `useAuth` (a react-query hook). These are static SSR renders with no +// QueryClient, so mock the hook to a real metric-preference implementation — +// metric is the identity on values and yields the canonical display symbols, +// so the assertions below (kg, °C, unchanged numbers) hold. +vi.mock("@/hooks/use-unit-display", async () => { + const dt = await import("@/lib/measurements/display-transform"); + const forType = (t: string) => dt.getDisplayTransform(t, "metric"); + return { + useUnitDisplay: () => ({ + preference: "metric" as const, + transformFor: forType, + toDisplay: (t: string, v: number) => + dt.applyDisplayTransform(v, forType(t)), + fromDisplay: (t: string, v: number) => + dt.invertDisplayTransform(v, forType(t)), + toDisplayDelta: (t: string, v: number) => + dt.applyDisplayTransformDelta(v, forType(t)), + unitFor: (t: string) => forType(t).displayUnit, + decimalsFor: (t: string) => forType(t).decimals, + isTransformed: (t: string) => dt.hasDisplayTransform(t), + }), + }; +}); + import { CyclePhaseCrosstab, CyclePhaseHeadline, diff --git a/src/components/insights/derived/__tests__/vitals-dashboard.test.tsx b/src/components/insights/derived/__tests__/vitals-dashboard.test.tsx index 479f26fb8..179104963 100644 --- a/src/components/insights/derived/__tests__/vitals-dashboard.test.tsx +++ b/src/components/insights/derived/__tests__/vitals-dashboard.test.tsx @@ -1,6 +1,31 @@ import { describe, it, expect, vi, beforeEach } from "vitest"; import { renderToStaticMarkup } from "react-dom/server"; +// The vitals tiles read the unit preference through `useUnitDisplay`, which +// hangs off `useAuth` (a react-query hook). These are static SSR renders with +// no QueryClient, so mock the hook to a real metric-preference implementation +// — metric is the identity on values and yields the canonical display symbols +// (e.g. °C), matching the pre-fix render the assertions expect. +vi.mock("@/hooks/use-unit-display", async () => { + const dt = await import("@/lib/measurements/display-transform"); + const forType = (t: string) => dt.getDisplayTransform(t, "metric"); + return { + useUnitDisplay: () => ({ + preference: "metric" as const, + transformFor: forType, + toDisplay: (t: string, v: number) => + dt.applyDisplayTransform(v, forType(t)), + fromDisplay: (t: string, v: number) => + dt.invertDisplayTransform(v, forType(t)), + toDisplayDelta: (t: string, v: number) => + dt.applyDisplayTransformDelta(v, forType(t)), + unitFor: (t: string) => forType(t).displayUnit, + decimalsFor: (t: string) => forType(t).decimals, + isTransformed: (t: string) => dt.hasDisplayTransform(t), + }), + }; +}); + import { I18nProvider } from "@/lib/i18n/context"; import type { DerivedMetricResponse, diff --git a/src/lib/mcp/__tests__/write-tools.test.ts b/src/lib/mcp/__tests__/write-tools.test.ts index d677f3ba6..d8eb0b8cd 100644 --- a/src/lib/mcp/__tests__/write-tools.test.ts +++ b/src/lib/mcp/__tests__/write-tools.test.ts @@ -5,12 +5,15 @@ const logMcpMood = vi.fn(); const logMcpBloodPressure = vi.fn(); const checkMcpMeasurement = vi.fn(); const checkMcpBloodPressure = vi.fn(); +const resolveMcpMeasurementUnit = vi.fn(); vi.mock("../writes", () => ({ logMcpMeasurement: (...a: unknown[]) => logMcpMeasurement(...a), logMcpMood: (...a: unknown[]) => logMcpMood(...a), logMcpBloodPressure: (...a: unknown[]) => logMcpBloodPressure(...a), checkMcpMeasurement: (...a: unknown[]) => checkMcpMeasurement(...a), checkMcpBloodPressure: (...a: unknown[]) => checkMcpBloodPressure(...a), + resolveMcpMeasurementUnit: (...a: unknown[]) => + resolveMcpMeasurementUnit(...a), })); const checkMcpWriteRateLimit = vi.fn(); @@ -49,6 +52,10 @@ beforeEach(() => { // would-be record. Individual tests override to assert wouldFail. checkMcpMeasurement.mockReturnValue({ ok: true }); checkMcpBloodPressure.mockReturnValue({ ok: true }); + // Default: the unit hint resolves to canonical, echoing the value through. + resolveMcpMeasurementUnit.mockImplementation( + (_type: string, value: number) => ({ ok: true, value, unit: "kg" }), + ); }); describe("write-tool surface", () => {