diff --git a/src/components/insights/__tests__/insight-advisor-card.test.tsx b/src/components/insights/__tests__/insight-advisor-card.test.tsx
new file mode 100644
index 000000000..6fb762f7f
--- /dev/null
+++ b/src/components/insights/__tests__/insight-advisor-card.test.tsx
@@ -0,0 +1,164 @@
+import { describe, it, expect, vi, beforeEach } from "vitest";
+import { renderToStaticMarkup } from "react-dom/server";
+
+// HealthChart pulls in TanStack Query + recharts. We don't care about its
+// internal rendering — we only need to know *that it was rendered* and
+// with which `types[]` (which is the chart's metric handle, since the
+// real component takes `types: string[]` not `metric: string`).
+vi.mock("@/components/charts/health-chart", () => ({
+ HealthChart: ({ types, title }: { types: string[]; title: string }) => (
+
+ chart:{title}
+
+ ),
+}));
+
+// Stub TanStack Query — InsightAdvisorCard itself doesn't query, but
+// nested clients (and the HealthChart mock above replaces the real one)
+// pull from this. Safe no-op.
+vi.mock("@tanstack/react-query", () => ({
+ useQuery: () => ({ data: null, isLoading: false }),
+ useQueryClient: () => ({ invalidateQueries: vi.fn() }),
+}));
+
+import { I18nProvider } from "@/lib/i18n/context";
+import { InsightAdvisorCard } from "../insight-advisor-card";
+import type { InsightResult } from "@/lib/ai/types";
+
+function buildInsight(overrides: Partial = {}): InsightResult {
+ return {
+ insightType: "general",
+ summary: "All good",
+ classification: "gut",
+ classificationLabel: "Good",
+ findings: [
+ {
+ label: "Heart rate stable",
+ value: "72 bpm",
+ assessment: "positive",
+ },
+ ],
+ correlations: [],
+ primaryRecommendation: "Keep going",
+ recommendations: [],
+ dataQuality: {
+ coverage: "good",
+ gaps: [],
+ confidence: "hoch",
+ },
+ disclaimer: "Not a substitute for medical advice.",
+ ...overrides,
+ };
+}
+
+function render(insight: InsightResult) {
+ return renderToStaticMarkup(
+
+
+ ,
+ );
+}
+
+beforeEach(() => {
+ vi.clearAllMocks();
+});
+
+describe(" — inline chart tokens", () => {
+ it("renders an inline HealthChart for an allowlisted token in summary", () => {
+ const html = render(
+ buildInsight({
+ summary: "BP looking great metric:BLOOD_PRESSURE_SYS today",
+ }),
+ );
+
+ // Chart is rendered with the token's metric as the type.
+ expect(html).toContain('data-testid="health-chart"');
+ expect(html).toContain('data-types="BLOOD_PRESSURE_SYS"');
+
+ // Token literal is stripped from the visible prose.
+ expect(html).not.toContain("metric:BLOOD_PRESSURE_SYS");
+
+ // Surrounding prose survives unchanged.
+ expect(html).toContain("BP looking great");
+ expect(html).toContain("today");
+ });
+
+ it("drops hallucinated tokens silently and still strips the literal", () => {
+ const html = render(
+ buildInsight({
+ summary: "metric:NUKE try this",
+ }),
+ );
+
+ // No chart rendered.
+ expect(html).not.toContain('data-testid="health-chart"');
+
+ // Token literal is gone from the DOM.
+ expect(html).not.toContain("metric:NUKE");
+
+ // Visible text is the surrounding prose only.
+ expect(html).toContain("try this");
+ });
+
+ it("treats injection attempts as plain text — no script, no markup", () => {
+ const html = render(
+ buildInsight({
+ summary: "metric:WEIGHT' onclick='alert(1)'",
+ }),
+ );
+
+ // The chart still renders for the safe metric prefix.
+ expect(html).toContain('data-testid="health-chart"');
+ expect(html).toContain('data-types="WEIGHT"');
+
+ // The trailing junk is preserved as escaped text — no script tag,
+ // no live `onclick` attribute survives the React text path.
+ expect(html).not.toContain("