Files
HealthLog/src/lib/validations/__tests__/measurement.test.ts
T
Marc-André Bombeck ef3e37b7da test(security): add SSRF guard tests + measurement validation tests
- New unit tests for isPublicUrl covering loopback, link-local, RFC1918,
  CGNAT, IPv6 ranges, and the leading-zero IPv4 octal-bypass regression
  (URL parser silently turns '010.0.0.1' into '8.0.0.1' — caught now).
- Strengthened isPublicUrl: pre-URL leading-zero check on the raw input,
  bracket-aware IPv6, deny on malformed IPv4 quads instead of falling
  through to 'public' (better safe than sorry on user-supplied URLs).
- New unit tests for measurement validation covering the new
  TOTAL_BODY_WATER and BONE_MASS types: ranges, glucoseContext rejection
  on non-glucose types, and unrecognised type rejection.
2026-04-27 00:28:28 +02:00

125 lines
4.0 KiB
TypeScript

import { describe, expect, it } from "vitest";
import {
createMeasurementSchema,
getUnitForType,
validateMeasurementRange,
} from "../measurement";
describe("measurement validation", () => {
describe("getUnitForType", () => {
it("returns canonical unit for each measurement type", () => {
expect(getUnitForType("WEIGHT")).toBe("kg");
expect(getUnitForType("BLOOD_PRESSURE_SYS")).toBe("mmHg");
expect(getUnitForType("BLOOD_PRESSURE_DIA")).toBe("mmHg");
expect(getUnitForType("PULSE")).toBe("bpm");
expect(getUnitForType("BODY_FAT")).toBe("%");
expect(getUnitForType("SLEEP_DURATION")).toBe("hours");
expect(getUnitForType("ACTIVITY_STEPS")).toBe("steps");
expect(getUnitForType("BLOOD_GLUCOSE")).toBe("mg/dL");
expect(getUnitForType("TOTAL_BODY_WATER")).toBe("kg");
expect(getUnitForType("BONE_MASS")).toBe("kg");
});
it("returns 'unknown' for unrecognised types", () => {
expect(getUnitForType("MADE_UP_TYPE")).toBe("unknown");
});
});
describe("validateMeasurementRange", () => {
it("rejects values below the plausible minimum", () => {
expect(validateMeasurementRange("WEIGHT", 0.5)).toMatch(/zwischen/);
expect(validateMeasurementRange("BONE_MASS", 0.1)).toMatch(/zwischen/);
expect(validateMeasurementRange("TOTAL_BODY_WATER", 1)).toMatch(
/zwischen/,
);
});
it("rejects values above the plausible maximum", () => {
expect(validateMeasurementRange("WEIGHT", 600)).toMatch(/zwischen/);
expect(validateMeasurementRange("BONE_MASS", 12)).toMatch(/zwischen/);
expect(validateMeasurementRange("TOTAL_BODY_WATER", 200)).toMatch(
/zwischen/,
);
});
it("accepts values inside the plausible range", () => {
expect(validateMeasurementRange("WEIGHT", 75)).toBeNull();
expect(validateMeasurementRange("BONE_MASS", 3.0)).toBeNull();
expect(validateMeasurementRange("TOTAL_BODY_WATER", 42)).toBeNull();
});
it("returns null for unknown types (no range = no opinion)", () => {
expect(validateMeasurementRange("MADE_UP_TYPE", 9999)).toBeNull();
});
});
describe("createMeasurementSchema", () => {
const validBase = {
value: 75,
measuredAt: "2026-04-27T08:00:00.000Z",
};
it("accepts a TOTAL_BODY_WATER measurement without glucoseContext", () => {
const parsed = createMeasurementSchema.safeParse({
...validBase,
type: "TOTAL_BODY_WATER",
value: 42,
});
expect(parsed.success).toBe(true);
});
it("accepts a BONE_MASS measurement without glucoseContext", () => {
const parsed = createMeasurementSchema.safeParse({
...validBase,
type: "BONE_MASS",
value: 3.2,
});
expect(parsed.success).toBe(true);
});
it("rejects out-of-range values for body composition types", () => {
const tooMuchWater = createMeasurementSchema.safeParse({
...validBase,
type: "TOTAL_BODY_WATER",
value: 500,
});
expect(tooMuchWater.success).toBe(false);
const tooLittleBone = createMeasurementSchema.safeParse({
...validBase,
type: "BONE_MASS",
value: 0.1,
});
expect(tooLittleBone.success).toBe(false);
});
it("rejects glucoseContext on non-glucose measurements", () => {
const parsed = createMeasurementSchema.safeParse({
...validBase,
type: "TOTAL_BODY_WATER",
value: 42,
glucoseContext: "FASTING",
});
expect(parsed.success).toBe(false);
});
it("requires glucoseContext on BLOOD_GLUCOSE measurements", () => {
const parsed = createMeasurementSchema.safeParse({
...validBase,
type: "BLOOD_GLUCOSE",
value: 95,
});
expect(parsed.success).toBe(false);
});
it("rejects unrecognised measurement types", () => {
const parsed = createMeasurementSchema.safeParse({
...validBase,
type: "TBD_NEW_TYPE",
value: 1,
});
expect(parsed.success).toBe(false);
});
});
});