mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-07 04:12:04 +00:00
Give the mobile cycle smoke test a verdict to render
The spec hand-builds a calendar response, and the wheel now reads the resolved verdict from it. Without the field the ring paints empty, so the fixture derives the verdict from the same phase plan it derives the day grid from and the two cannot drift apart.
This commit is contained in:
1 parent
c65f122017
commit
043d2ba143
2 files changed
+50
-24
No files matched your search
@@ -37,20 +37,29 @@ function ymd(d: Date): string {
|
||||
return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, "0")}-${String(d.getDate()).padStart(2, "0")}`;
|
||||
}
|
||||
|
||||
/** The labelled run the fixture paints: 5 menstrual, 6 follicular, 1 ovulatory,
|
||||
* then luteal through today and one day past it. */
|
||||
const RUN_START_OFFSET = -12;
|
||||
const PHASE_PLAN: string[] = [
|
||||
...Array<string>(5).fill("MENSTRUAL"),
|
||||
...Array<string>(6).fill("FOLLICULAR"),
|
||||
"OVULATORY",
|
||||
"LUTEAL",
|
||||
"LUTEAL",
|
||||
];
|
||||
|
||||
function runStart(): Date {
|
||||
const start = new Date();
|
||||
start.setDate(start.getDate() + RUN_START_OFFSET);
|
||||
return start;
|
||||
}
|
||||
|
||||
/** A 90-day-back → 180-day-forward calendar with a recent labelled cycle run
|
||||
* so the wheel resolves a current phase + day and the calendar paints cells. */
|
||||
* so the wheel has a phase + day to show and the calendar paints cells. */
|
||||
function buildCalendarDays(): Array<Record<string, unknown>> {
|
||||
const days: Array<Record<string, unknown>> = [];
|
||||
const start = new Date();
|
||||
start.setDate(start.getDate() - 12);
|
||||
// 5 menstrual, 6 follicular, 1 ovulatory, then luteal through today.
|
||||
const plan: string[] = [
|
||||
...Array<string>(5).fill("MENSTRUAL"),
|
||||
...Array<string>(6).fill("FOLLICULAR"),
|
||||
"OVULATORY",
|
||||
"LUTEAL",
|
||||
"LUTEAL",
|
||||
];
|
||||
const start = runStart();
|
||||
const plan = PHASE_PLAN;
|
||||
for (let i = 0; i < plan.length; i++) {
|
||||
const d = new Date(start);
|
||||
d.setDate(start.getDate() + i);
|
||||
@@ -72,6 +81,34 @@ function buildCalendarDays(): Array<Record<string, unknown>> {
|
||||
return days;
|
||||
}
|
||||
|
||||
/**
|
||||
* The verdict the server resolves for that grid. The real route publishes this
|
||||
* and the wheel renders it, so a fixture that omitted it would paint an empty
|
||||
* ring — deriving it here from the SAME plan keeps the two from drifting.
|
||||
*/
|
||||
function buildVerdict(): Record<string, unknown> {
|
||||
const plan = PHASE_PLAN;
|
||||
const counts = plan.reduce<Record<string, number>>((acc, phase) => {
|
||||
acc[phase] = (acc[phase] ?? 0) + 1;
|
||||
return acc;
|
||||
}, {});
|
||||
const order = ["MENSTRUAL", "FOLLICULAR", "OVULATORY", "LUTEAL"];
|
||||
return {
|
||||
state: "IN_CYCLE",
|
||||
// The run starts 12 days back, so today is its 13th day.
|
||||
dayOfCycle: 1 - RUN_START_OFFSET,
|
||||
cycleLength: plan.length,
|
||||
phase: plan[-RUN_START_OFFSET],
|
||||
spans: order
|
||||
.filter((phase) => (counts[phase] ?? 0) > 0)
|
||||
.map((phase) => ({ phase, fraction: counts[phase] / plan.length })),
|
||||
cycleStartDate: ymd(runStart()),
|
||||
overdueDays: null,
|
||||
daysUntilNext: null,
|
||||
fertileWindow: { start: null, end: null, active: false },
|
||||
};
|
||||
}
|
||||
|
||||
const CALENDAR_BODY = {
|
||||
data: {
|
||||
profile: {
|
||||
@@ -81,6 +118,8 @@ const CALENDAR_BODY = {
|
||||
cyclesObserved: 1,
|
||||
},
|
||||
prediction: null,
|
||||
verdict: buildVerdict(),
|
||||
stillLearning: false,
|
||||
days: buildCalendarDays(),
|
||||
meta: { generatedAt: new Date().toISOString() },
|
||||
},
|
||||
|
||||
@@ -109,19 +109,6 @@ const LUTEAL_VERDICT: CycleVerdict = {
|
||||
fertileWindow: { start: null, end: null, active: false },
|
||||
};
|
||||
|
||||
/** The verdict for an account with nothing to say about today. */
|
||||
const NO_CYCLE_VERDICT: CycleVerdict = {
|
||||
state: "INSUFFICIENT_DATA",
|
||||
dayOfCycle: null,
|
||||
cycleLength: null,
|
||||
phase: null,
|
||||
spans: [],
|
||||
cycleStartDate: null,
|
||||
overdueDays: null,
|
||||
daysUntilNext: null,
|
||||
fertileWindow: { start: null, end: null, active: false },
|
||||
};
|
||||
|
||||
/** A calendar read whose SERVER-RESOLVED verdict puts today on LUTEAL, day 3.
|
||||
* The card renders the verdict; it no longer derives anything from `days`. */
|
||||
function lutealCalendar(today: string): CalendarResponse {
|
||||
|
||||
Reference in new issue
Block a user