mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-14 22:50:51 +00:00
Marc reported v1.4.15 A4 didn't fully land: - DE label still read "7-Tage-Schnitt" / "7T-Schnitt" in places - mood tile showed no numeric trend delta even though other tiles did i18n rename: - de.json + en.json: trend7dShort, movingAverage7d, moodMA all read "7-Tage-Trend" / "7-day trend". The legacy "7T:" / "7d:" header on the avg7 line is preserved for tiles that haven't been migrated to the trend7Delta API. trend-delta fallback: - summaryToTrend7Delta() now falls back to slope30 (projected onto 7 days) when slope7 is null. Mood entries are typically logged less than daily, so slope7 needs ≥ 2 points within the trailing 7-day window — for sparser users that came back null and the tile silently dropped the delta indicator. slope30 still answers "is this metric drifting?" so we project that onto the 7-day window for label parity. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
66 lines
2.1 KiB
TypeScript
66 lines
2.1 KiB
TypeScript
import { describe, it, expect } from "vitest";
|
|
import { summaryToTrend7Delta } from "../trend-delta";
|
|
|
|
const STABLE = { slope: 0, direction: "stable" as const, confidence: 0.1 };
|
|
const RISING_HALF_PER_DAY = {
|
|
slope: 0.5,
|
|
direction: "up" as const,
|
|
confidence: 0.8,
|
|
};
|
|
const FALLING_TENTH_PER_DAY = {
|
|
slope: -0.1,
|
|
direction: "down" as const,
|
|
confidence: 0.7,
|
|
};
|
|
|
|
describe("summaryToTrend7Delta()", () => {
|
|
it("returns null when the summary is missing", () => {
|
|
expect(summaryToTrend7Delta(null)).toBeNull();
|
|
expect(summaryToTrend7Delta(undefined)).toBeNull();
|
|
});
|
|
|
|
it("returns null when neither slope7 nor slope30 is computable", () => {
|
|
expect(summaryToTrend7Delta({ slope7: null })).toBeNull();
|
|
expect(summaryToTrend7Delta({ slope7: null, slope30: null })).toBeNull();
|
|
});
|
|
|
|
it("projects slope (units per day) over a 7-day window", () => {
|
|
expect(summaryToTrend7Delta({ slope7: RISING_HALF_PER_DAY })).toBe(3.5);
|
|
// Negative slope produces a negative delta — the tile shows it
|
|
// with the unicode minus sign in the formatter.
|
|
expect(summaryToTrend7Delta({ slope7: FALLING_TENTH_PER_DAY })).toBeCloseTo(
|
|
-0.7,
|
|
3,
|
|
);
|
|
});
|
|
|
|
it("returns 0 for a stable slope (the tile then paints ±0)", () => {
|
|
expect(summaryToTrend7Delta({ slope7: STABLE })).toBe(0);
|
|
});
|
|
|
|
it("falls back to slope30 when slope7 is null (sparse metrics like mood)", () => {
|
|
// v1.4.16 fix A4: mood-tile showed no trend number for users who
|
|
// log mood < daily because slope7 needs ≥2 points within the
|
|
// trailing 7-day window. slope30 still answers "is this metric
|
|
// drifting?" so we project that onto 7 days for label parity.
|
|
expect(
|
|
summaryToTrend7Delta({ slope7: null, slope30: RISING_HALF_PER_DAY }),
|
|
).toBe(3.5);
|
|
expect(
|
|
summaryToTrend7Delta({
|
|
slope7: null,
|
|
slope30: FALLING_TENTH_PER_DAY,
|
|
}),
|
|
).toBeCloseTo(-0.7, 3);
|
|
});
|
|
|
|
it("prefers slope7 over slope30 when both are present", () => {
|
|
expect(
|
|
summaryToTrend7Delta({
|
|
slope7: RISING_HALF_PER_DAY,
|
|
slope30: FALLING_TENTH_PER_DAY,
|
|
}),
|
|
).toBe(3.5);
|
|
});
|
|
});
|