mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-11 05:42:19 +00:00
A converted reading's bounds move with its value, but the printed range text stays in the unit the report used, and every reader preferred that text: the list showed "Report range 3.9 to 5.5" beside 100.9 mg/dL, and the doctor report and the FHIR referenceRange.text did the same. The text is still stored verbatim. The range resolver now takes the reading's sourceUnit (as a required field, so no reader can forget to select it) and, for a converted reading, leaves the window's text empty so every surface states the converted bounds in the marker's unit, and hands the printed text over separately with its unit. The lab DTO carries it as printedReferenceText, and the note beside a reading shows it as "as printed in mmol/L: ...".
180 lines
5.8 KiB
TypeScript
180 lines
5.8 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
||
|
||
import {
|
||
classifyAgainstEffectiveRange,
|
||
resolveEffectiveReferenceRange,
|
||
} from "@/lib/labs/reference-range";
|
||
|
||
const NO_SOURCE = {
|
||
sourceReferenceLow: null,
|
||
sourceReferenceHigh: null,
|
||
sourceReferenceText: null,
|
||
sourceUnit: null,
|
||
};
|
||
|
||
describe("resolveEffectiveReferenceRange", () => {
|
||
it("falls back to the catalog band when the reading carries no source window", () => {
|
||
const eff = resolveEffectiveReferenceRange(3.5, 5, NO_SOURCE);
|
||
expect(eff).toMatchObject({
|
||
low: 3.5,
|
||
high: 5,
|
||
origin: "catalog",
|
||
catalogLow: 3.5,
|
||
catalogHigh: 5,
|
||
sourceText: null,
|
||
divergesFromCatalog: false,
|
||
});
|
||
});
|
||
|
||
it("reports no window when neither side states one", () => {
|
||
expect(resolveEffectiveReferenceRange(null, null, NO_SOURCE)).toMatchObject(
|
||
{ low: null, high: null, origin: "none", divergesFromCatalog: false },
|
||
);
|
||
});
|
||
|
||
it("lets the source window win over the catalog band for that reading", () => {
|
||
const eff = resolveEffectiveReferenceRange(3.5, 5, {
|
||
sourceReferenceLow: 3.9,
|
||
sourceReferenceHigh: 5.4,
|
||
sourceReferenceText: "3,9 - 5,4",
|
||
sourceUnit: null,
|
||
});
|
||
expect(eff).toMatchObject({
|
||
low: 3.9,
|
||
high: 5.4,
|
||
origin: "source",
|
||
catalogLow: 3.5,
|
||
catalogHigh: 5,
|
||
sourceText: "3,9 - 5,4",
|
||
divergesFromCatalog: true,
|
||
});
|
||
});
|
||
|
||
it("does not call an identical window a divergence", () => {
|
||
const eff = resolveEffectiveReferenceRange(3.5, 5, {
|
||
sourceReferenceLow: 3.5,
|
||
sourceReferenceHigh: 5,
|
||
sourceReferenceText: "3,5 - 5,0",
|
||
sourceUnit: null,
|
||
});
|
||
expect(eff.origin).toBe("source");
|
||
expect(eff.divergesFromCatalog).toBe(false);
|
||
});
|
||
|
||
it("takes a one-sided source window whole, not merged with the catalog", () => {
|
||
// A report that prints "< 5" states a ceiling and NO floor. Borrowing the
|
||
// catalog's floor would invent a window the report never stated.
|
||
const eff = resolveEffectiveReferenceRange(3.5, 5, {
|
||
sourceReferenceLow: null,
|
||
sourceReferenceHigh: 4.2,
|
||
sourceReferenceText: "< 4,2",
|
||
sourceUnit: null,
|
||
});
|
||
expect(eff).toMatchObject({
|
||
low: null,
|
||
high: 4.2,
|
||
origin: "source",
|
||
divergesFromCatalog: true,
|
||
});
|
||
});
|
||
|
||
it("does not displace the catalog for a printed window with no derivable bound", () => {
|
||
// "negativ" is carried through verbatim, but it is not an argument for
|
||
// discarding the catalog band.
|
||
const eff = resolveEffectiveReferenceRange(3.5, 5, {
|
||
sourceReferenceLow: null,
|
||
sourceReferenceHigh: null,
|
||
sourceReferenceText: "negativ",
|
||
sourceUnit: null,
|
||
});
|
||
expect(eff).toMatchObject({
|
||
low: 3.5,
|
||
high: 5,
|
||
origin: "catalog",
|
||
sourceText: "negativ",
|
||
divergesFromCatalog: false,
|
||
});
|
||
});
|
||
|
||
it("reports a source window as no divergence when the catalog has none", () => {
|
||
const eff = resolveEffectiveReferenceRange(null, null, {
|
||
sourceReferenceLow: 3.9,
|
||
sourceReferenceHigh: 5.4,
|
||
sourceReferenceText: "3,9 - 5,4",
|
||
sourceUnit: null,
|
||
});
|
||
expect(eff.origin).toBe("source");
|
||
expect(eff.divergesFromCatalog).toBe(false);
|
||
});
|
||
});
|
||
|
||
describe("a converted reading's printed text", () => {
|
||
// 5.6 mmol/L stored as mg/dL, with the printed 3.9 to 5.5 mmol/L window
|
||
// converted alongside; the text stays as the report printed it.
|
||
const CONVERTED = {
|
||
sourceReferenceLow: 3.9 * 18.0182,
|
||
sourceReferenceHigh: 5.5 * 18.0182,
|
||
sourceReferenceText: "3,9 - 5,5",
|
||
sourceUnit: "mmol/L",
|
||
};
|
||
|
||
it("is never the window's text, so no statement mixes two units", () => {
|
||
const eff = resolveEffectiveReferenceRange(70, 100, CONVERTED);
|
||
expect(eff.origin).toBe("source");
|
||
expect(eff.low).toBeCloseTo(70.27, 2);
|
||
expect(eff.sourceText).toBeNull();
|
||
});
|
||
|
||
it("is kept as evidence with the unit it is written in", () => {
|
||
const eff = resolveEffectiveReferenceRange(70, 100, CONVERTED);
|
||
expect(eff.printed).toEqual({ text: "3,9 - 5,5", unit: "mmol/L" });
|
||
});
|
||
|
||
it("stays the window's text for a reading stored as stated", () => {
|
||
const eff = resolveEffectiveReferenceRange(70, 100, {
|
||
...CONVERTED,
|
||
sourceUnit: null,
|
||
});
|
||
expect(eff.sourceText).toBe("3,9 - 5,5");
|
||
expect(eff.printed).toBeNull();
|
||
});
|
||
|
||
it("moves an unreadable printed text the same way", () => {
|
||
const eff = resolveEffectiveReferenceRange(70, 100, {
|
||
sourceReferenceLow: null,
|
||
sourceReferenceHigh: null,
|
||
sourceReferenceText: "siehe Befund",
|
||
sourceUnit: "mmol/L",
|
||
});
|
||
expect(eff.origin).toBe("catalog");
|
||
expect(eff.sourceText).toBeNull();
|
||
expect(eff.printed).toEqual({ text: "siehe Befund", unit: "mmol/L" });
|
||
});
|
||
});
|
||
|
||
describe("classifyAgainstEffectiveRange", () => {
|
||
it("judges a reading by the source window, not the catalog band", () => {
|
||
// 5.2 sits inside the catalog band (3.5–5.0 would call it high) but the
|
||
// report that produced this value states 3.9–5.4, so it is in range.
|
||
const eff = resolveEffectiveReferenceRange(3.5, 5, {
|
||
sourceReferenceLow: 3.9,
|
||
sourceReferenceHigh: 5.4,
|
||
sourceReferenceText: "3,9 - 5,4",
|
||
sourceUnit: null,
|
||
});
|
||
expect(classifyAgainstEffectiveRange(5.2, eff)).toBe("in-range");
|
||
expect(classifyAgainstEffectiveRange(3.7, eff)).toBe("below");
|
||
expect(classifyAgainstEffectiveRange(5.5, eff)).toBe("above");
|
||
});
|
||
|
||
it("keeps the catalog verdict for a reading with no source window", () => {
|
||
const eff = resolveEffectiveReferenceRange(3.5, 5, NO_SOURCE);
|
||
expect(classifyAgainstEffectiveRange(5.2, eff)).toBe("above");
|
||
});
|
||
|
||
it("never classifies a qualitative reading", () => {
|
||
const eff = resolveEffectiveReferenceRange(3.5, 5, NO_SOURCE);
|
||
expect(classifyAgainstEffectiveRange(null, eff)).toBe("unknown");
|
||
});
|
||
});
|