Files
HealthLog/src/lib/logging/__tests__/transports-buffer.test.ts
T
Marc-André BombeckandClaude Opus 4.7 a66c128dd9 feat(insights): citation footnote on recommendations with medical reference
When a recommendation carries a `referenceId` pointing into the
curated medical-reference bundle, render a small footnote underneath
linking to the guideline. Format: "Source: ESH 2023 — ESH 2023
Guidelines for the Management of Arterial Hypertension" (locale-
routed title), with a tiny external-link icon, opens in a new tab via
target="_blank" rel="noreferrer". Per the v1.4.16 research doc §7
the URL never opens in an in-app webview.

`InsightResult.recommendations` widens to accept either the legacy
plain-string shape OR a structured `{ text, referenceId? }` object so
existing rendering paths keep working while the new citation surface
plugs in through the same component. `getMedicalReferenceById()`
returns undefined for unknown ids — the UI silently drops the
footnote in that case rather than rendering a broken link (defence
in depth on top of the schema validation).

i18n keys `insights.recommendation.source` and
`insights.recommendation.viewSource` land in both EN and DE.

6 component tests pin the no-footnote / EN-locale / DE-locale /
unknown-id-defence / multi-rec paths.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-10 00:04:24 +02:00

58 lines
1.7 KiB
TypeScript

import { describe, expect, it, beforeEach, vi, afterEach } from "vitest";
import {
clearLogBuffer,
readLogBuffer,
getLogBufferSize,
} from "../in-memory-buffer";
import { emitEvent } from "../transports";
import { resetLoggingConfig } from "../config";
import type { WideEvent } from "../types";
function makeEvent(overrides: Partial<WideEvent> = {}): WideEvent {
return {
timestamp: new Date().toISOString(),
duration_ms: 42,
request_id: "req-buf-test",
trace_id: "trace-buf-test",
level: "info",
kind: "http",
service: "healthlog",
environment: "test",
...overrides,
};
}
describe("emitEvent → in-memory buffer wiring", () => {
let stdoutSpy: ReturnType<typeof vi.spyOn>;
beforeEach(() => {
clearLogBuffer();
resetLoggingConfig();
// Suppress the JSON line so the test runner stays readable.
stdoutSpy = vi.spyOn(process.stdout, "write").mockReturnValue(true);
});
afterEach(() => {
stdoutSpy.mockRestore();
});
it("pushes the emitted event into the in-memory buffer", () => {
expect(getLogBufferSize()).toBe(0);
emitEvent(makeEvent({ trace_id: "trace-A" }));
emitEvent(makeEvent({ trace_id: "trace-B" }));
expect(getLogBufferSize()).toBe(2);
const events = readLogBuffer({});
// Newest-first: trace-B was pushed second.
expect(events[0].trace_id).toBe("trace-B");
expect(events[1].trace_id).toBe("trace-A");
});
it("still writes to stdout (transport contract preserved)", () => {
emitEvent(makeEvent());
expect(stdoutSpy).toHaveBeenCalledTimes(1);
const arg = stdoutSpy.mock.calls[0][0];
expect(typeof arg).toBe("string");
expect(arg as string).toContain("trace-buf-test");
});
});