From 1b32217844a9be3a587bac1e1ce7c41906ef21ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Bombeck?= Date: Fri, 23 Oct 2026 15:20:27 +0200 Subject: [PATCH] test(dashboard): pin the summary before moving its builder --- .../dashboard-summary.01-cold.json.snap | 383 ++++++++++++++++++ .../dashboard-summary.02-warm.json.snap | 374 +++++++++++++++++ ...dashboard-summary.03-modules-off.json.snap | 279 +++++++++++++ .../dashboard-summary.04-de-cached.json.snap | 374 +++++++++++++++++ .../dashboard-summary.05-manager.json.snap | 374 +++++++++++++++++ .../dashboard-summary.06-reader.json.snap | 26 ++ .../dashboard-summary.07-anonymous.json.snap | 24 ++ ...shboard-summary.08-empty-account.json.snap | 100 +++++ .../parity/dashboard-summary.parity.test.ts | 201 +++++++++ 9 files changed, 2135 insertions(+) create mode 100644 tests/integration/routes/parity/__snapshots__/dashboard-summary.01-cold.json.snap create mode 100644 tests/integration/routes/parity/__snapshots__/dashboard-summary.02-warm.json.snap create mode 100644 tests/integration/routes/parity/__snapshots__/dashboard-summary.03-modules-off.json.snap create mode 100644 tests/integration/routes/parity/__snapshots__/dashboard-summary.04-de-cached.json.snap create mode 100644 tests/integration/routes/parity/__snapshots__/dashboard-summary.05-manager.json.snap create mode 100644 tests/integration/routes/parity/__snapshots__/dashboard-summary.06-reader.json.snap create mode 100644 tests/integration/routes/parity/__snapshots__/dashboard-summary.07-anonymous.json.snap create mode 100644 tests/integration/routes/parity/__snapshots__/dashboard-summary.08-empty-account.json.snap create mode 100644 tests/integration/routes/parity/dashboard-summary.parity.test.ts diff --git a/tests/integration/routes/parity/__snapshots__/dashboard-summary.01-cold.json.snap b/tests/integration/routes/parity/__snapshots__/dashboard-summary.01-cold.json.snap new file mode 100644 index 000000000..8cc97d561 --- /dev/null +++ b/tests/integration/routes/parity/__snapshots__/dashboard-summary.01-cold.json.snap @@ -0,0 +1,383 @@ +{ + "status": 200, + "body": { + "data": { + "greeting": { + "salutation": "Hi, Sam", + "date": "anchor+0d+12:00:00" + }, + "streak": { + "currentDays": 120, + "longest": 120, + "label": "days in a row" + }, + "compliance": { + "scheduledToday": 2, + "takenToday": 0 + }, + "highlightInsight": null, + "metrics": [ + { + "id": "weight", + "kind": "weight", + "titleKey": "dashboard.metric.title.weight", + "latestValue": 82, + "secondaryValue": null, + "unitKey": "dashboard.metric.unit.weight", + "unit": null, + "sleepStages": null, + "sleepSourceDiscrepancy": null, + "trend": "flat", + "sparkline": [ + 82.2, + 82.2, + 82.2, + 82.1, + 82.1, + 82, + 82 + ], + "updatedAt": "", + "allTimeCount": 60, + "lastSeenAt": "anchor+0d+06:30:00", + "direction": { + "direction": "up-bad", + "targetPosition": null, + "basis": "metric_default" + }, + "trendSentiment": "neutral" + }, + { + "id": "bp", + "kind": "bloodPressure", + "titleKey": "dashboard.metric.title.bloodPressure", + "latestValue": 123, + "secondaryValue": 78, + "unitKey": "dashboard.metric.unit.bloodPressure", + "unit": null, + "sleepStages": null, + "sleepSourceDiscrepancy": null, + "trend": "down", + "sparkline": [ + 135, + 128, + 136, + 129, + 137, + 130, + 123 + ], + "updatedAt": "", + "allTimeCount": 182, + "lastSeenAt": "anchor+0d+07:00:00", + "direction": { + "direction": "up-bad", + "targetPosition": "above", + "basis": "profile_default" + }, + "trendSentiment": "positive" + }, + { + "id": "pulse", + "kind": "pulse", + "titleKey": "dashboard.metric.title.pulse", + "latestValue": 64, + "secondaryValue": null, + "unitKey": "dashboard.metric.unit.pulse", + "unit": null, + "sleepStages": null, + "sleepSourceDiscrepancy": null, + "trend": "flat", + "sparkline": [ + 64, + 69, + 68, + 67, + 66, + 65, + 64 + ], + "updatedAt": "", + "allTimeCount": 60, + "lastSeenAt": "anchor+0d+07:01:00", + "direction": { + "direction": "hold", + "targetPosition": "inside", + "basis": "profile_default" + }, + "trendSentiment": "positive" + }, + { + "id": "bodyFat", + "kind": "bodyFat", + "titleKey": "dashboard.metric.title.bodyFat", + "latestValue": 24, + "secondaryValue": null, + "unitKey": "dashboard.metric.unit.bodyFat", + "unit": null, + "sleepStages": null, + "sleepSourceDiscrepancy": null, + "trend": "flat", + "sparkline": [ + 24.8, + 24.7, + 24.6, + 24.4, + 24.3, + 24.1, + 24 + ], + "updatedAt": "", + "allTimeCount": 9, + "lastSeenAt": "anchor+0d+06:31:00", + "direction": { + "direction": "up-bad", + "targetPosition": null, + "basis": "metric_default" + }, + "trendSentiment": "neutral" + }, + { + "id": "glucose", + "kind": "glucose", + "titleKey": "dashboard.metric.title.glucose", + "latestValue": 128, + "secondaryValue": null, + "unitKey": "dashboard.metric.unit.glucose", + "unit": null, + "sleepStages": null, + "sleepSourceDiscrepancy": null, + "trend": "down", + "sparkline": [ + 117, + 115.33333333333333, + 113.66666666666667, + 113.33333333333333, + 111.66666666666667, + 110, + 108.33333333333333 + ], + "updatedAt": "", + "allTimeCount": 60, + "lastSeenAt": "anchor+0d+11:00:00", + "direction": { + "direction": "up-bad", + "targetPosition": null, + "basis": "metric_default" + }, + "trendSentiment": "positive" + }, + { + "id": "sleep", + "kind": "sleep", + "titleKey": "dashboard.metric.title.sleep", + "latestValue": 5.92, + "secondaryValue": null, + "unitKey": "dashboard.metric.unit.sleep", + "unit": "h", + "sleepStages": { + "CORE": 3.33, + "DEEP": 1.17, + "REM": 1.42, + "AWAKE": 0.2 + }, + "sleepSourceDiscrepancy": null, + "trend": "flat", + "sparkline": [ + 6.25, + 6.17, + 6.67, + 6.67, + 7.17, + 6.25, + 5.92 + ], + "updatedAt": "", + "allTimeCount": 85, + "lastSeenAt": "anchor+0d+04:15:00", + "direction": { + "direction": "up-good", + "targetPosition": null, + "basis": "metric_default" + }, + "trendSentiment": "neutral" + }, + { + "id": "steps", + "kind": "steps", + "titleKey": "dashboard.metric.title.steps", + "latestValue": 6000, + "secondaryValue": null, + "unitKey": "dashboard.metric.unit.steps", + "unit": null, + "sleepStages": null, + "sleepSourceDiscrepancy": null, + "trend": "down", + "sparkline": [ + 8238, + 7865, + 7492, + 7119, + 6746, + 6373, + 6000 + ], + "updatedAt": "", + "allTimeCount": 30, + "lastSeenAt": "anchor+0d+09:00:00", + "direction": { + "direction": "up-good", + "targetPosition": null, + "basis": "metric_default" + }, + "trendSentiment": "negative" + }, + { + "id": "oxygenSaturation", + "kind": "oxygenSaturation", + "titleKey": "dashboard.metric.title.oxygenSaturation", + "latestValue": 96, + "secondaryValue": null, + "unitKey": "dashboard.metric.unit.oxygenSaturation", + "unit": null, + "sleepStages": null, + "sleepSourceDiscrepancy": null, + "trend": "flat", + "sparkline": [ + 96, + 98, + 97, + 96, + 98, + 97, + 96 + ], + "updatedAt": "", + "allTimeCount": 10, + "lastSeenAt": "anchor+0d+04:40:00", + "direction": { + "direction": "up-good", + "targetPosition": null, + "basis": "metric_default" + }, + "trendSentiment": "neutral" + }, + { + "id": "mood", + "kind": "mood", + "titleKey": "dashboard.metric.title.mood", + "latestValue": 1, + "secondaryValue": null, + "unitKey": "dashboard.metric.unit.mood", + "unit": null, + "sleepStages": null, + "sleepSourceDiscrepancy": null, + "trend": "down", + "sparkline": [ + 4, + 1, + 3, + 5, + 2, + 4, + 1 + ], + "updatedAt": "", + "allTimeCount": 45, + "lastSeenAt": "anchor+0d+00:00:00", + "direction": { + "direction": "up-good", + "targetPosition": null, + "basis": "metric_default" + }, + "trendSentiment": "negative" + }, + { + "id": "bmi", + "kind": "bmi", + "titleKey": "dashboard.metric.title.bmi", + "latestValue": 25.9, + "secondaryValue": null, + "unitKey": "dashboard.metric.unit.bmi", + "unit": null, + "sleepStages": null, + "sleepSourceDiscrepancy": null, + "trend": "flat", + "sparkline": [ + 25.9, + 25.9, + 25.9, + 25.9, + 25.9, + 25.9, + 25.9 + ], + "updatedAt": "", + "allTimeCount": 60, + "lastSeenAt": "anchor+0d+06:30:00", + "direction": { + "direction": "up-bad", + "targetPosition": null, + "basis": "metric_default" + }, + "trendSentiment": "neutral" + } + ], + "sleepRhythm": { + "sleepDebt": { + "state": "ready", + "debtMinutes": 145, + "needMinutes": 420, + "nightsCounted": 5, + "windowNights": 5, + "nightsUntilReady": 0, + "source": "COMPUTED" + }, + "chronotype": { + "state": "ready", + "msfMinutes": 63.33521977432794, + "msfScMinutes": 63.335219774327925, + "band": "extreme_early", + "socialJetlagMinutes": 2.402527629787599, + "freeNightsCounted": 6, + "workNightsCounted": 15, + "freeNightsUntilReady": 0 + }, + "averagePerNight": { + "state": "ready", + "averageMinutes": 388, + "nightsCounted": 21, + "nightsUntilReady": 0 + } + }, + "lastUpdated": "anchor+0d+12:00:00" + }, + "error": null + }, + "events": [ + { + "status": 200, + "action": { + "name": "dashboard.summary" + }, + "meta": { + "cache.analytics.key_hash": 3272136333, + "cache.analytics.outcome": "miss", + "dashboard.sub_allTime_ms": 0, + "dashboard.sub_bmi_ms": 0, + "dashboard.sub_latestEver_ms": 0, + "dashboard.sub_medsToday_ms": 0, + "dashboard.sub_moodSeries_ms": 0, + "dashboard.sub_sleepNights_ms": 0, + "dashboard.sub_sparkline_ms": 0, + "dashboard.sub_streakDays_ms": 0, + "dashboard.sub_streakIntakes_ms": 0, + "metrics_emitted": 10, + "metrics_gated": 0 + }, + "warnings": null, + "error": null + } + ], + "effects": [] +} diff --git a/tests/integration/routes/parity/__snapshots__/dashboard-summary.02-warm.json.snap b/tests/integration/routes/parity/__snapshots__/dashboard-summary.02-warm.json.snap new file mode 100644 index 000000000..24b0d1fb1 --- /dev/null +++ b/tests/integration/routes/parity/__snapshots__/dashboard-summary.02-warm.json.snap @@ -0,0 +1,374 @@ +{ + "status": 200, + "body": { + "data": { + "greeting": { + "salutation": "Hi, Sam", + "date": "anchor+0d+12:00:00" + }, + "streak": { + "currentDays": 120, + "longest": 120, + "label": "days in a row" + }, + "compliance": { + "scheduledToday": 2, + "takenToday": 0 + }, + "highlightInsight": null, + "metrics": [ + { + "id": "weight", + "kind": "weight", + "titleKey": "dashboard.metric.title.weight", + "latestValue": 82, + "secondaryValue": null, + "unitKey": "dashboard.metric.unit.weight", + "unit": null, + "sleepStages": null, + "sleepSourceDiscrepancy": null, + "trend": "flat", + "sparkline": [ + 82.2, + 82.2, + 82.2, + 82.1, + 82.1, + 82, + 82 + ], + "updatedAt": "", + "allTimeCount": 60, + "lastSeenAt": "anchor+0d+06:30:00", + "direction": { + "direction": "up-bad", + "targetPosition": null, + "basis": "metric_default" + }, + "trendSentiment": "neutral" + }, + { + "id": "bp", + "kind": "bloodPressure", + "titleKey": "dashboard.metric.title.bloodPressure", + "latestValue": 123, + "secondaryValue": 78, + "unitKey": "dashboard.metric.unit.bloodPressure", + "unit": null, + "sleepStages": null, + "sleepSourceDiscrepancy": null, + "trend": "down", + "sparkline": [ + 135, + 128, + 136, + 129, + 137, + 130, + 123 + ], + "updatedAt": "", + "allTimeCount": 182, + "lastSeenAt": "anchor+0d+07:00:00", + "direction": { + "direction": "up-bad", + "targetPosition": "above", + "basis": "profile_default" + }, + "trendSentiment": "positive" + }, + { + "id": "pulse", + "kind": "pulse", + "titleKey": "dashboard.metric.title.pulse", + "latestValue": 64, + "secondaryValue": null, + "unitKey": "dashboard.metric.unit.pulse", + "unit": null, + "sleepStages": null, + "sleepSourceDiscrepancy": null, + "trend": "flat", + "sparkline": [ + 64, + 69, + 68, + 67, + 66, + 65, + 64 + ], + "updatedAt": "", + "allTimeCount": 60, + "lastSeenAt": "anchor+0d+07:01:00", + "direction": { + "direction": "hold", + "targetPosition": "inside", + "basis": "profile_default" + }, + "trendSentiment": "positive" + }, + { + "id": "bodyFat", + "kind": "bodyFat", + "titleKey": "dashboard.metric.title.bodyFat", + "latestValue": 24, + "secondaryValue": null, + "unitKey": "dashboard.metric.unit.bodyFat", + "unit": null, + "sleepStages": null, + "sleepSourceDiscrepancy": null, + "trend": "flat", + "sparkline": [ + 24.8, + 24.7, + 24.6, + 24.4, + 24.3, + 24.1, + 24 + ], + "updatedAt": "", + "allTimeCount": 9, + "lastSeenAt": "anchor+0d+06:31:00", + "direction": { + "direction": "up-bad", + "targetPosition": null, + "basis": "metric_default" + }, + "trendSentiment": "neutral" + }, + { + "id": "glucose", + "kind": "glucose", + "titleKey": "dashboard.metric.title.glucose", + "latestValue": 128, + "secondaryValue": null, + "unitKey": "dashboard.metric.unit.glucose", + "unit": null, + "sleepStages": null, + "sleepSourceDiscrepancy": null, + "trend": "down", + "sparkline": [ + 117, + 115.33333333333333, + 113.66666666666667, + 113.33333333333333, + 111.66666666666667, + 110, + 108.33333333333333 + ], + "updatedAt": "", + "allTimeCount": 60, + "lastSeenAt": "anchor+0d+11:00:00", + "direction": { + "direction": "up-bad", + "targetPosition": null, + "basis": "metric_default" + }, + "trendSentiment": "positive" + }, + { + "id": "sleep", + "kind": "sleep", + "titleKey": "dashboard.metric.title.sleep", + "latestValue": 5.92, + "secondaryValue": null, + "unitKey": "dashboard.metric.unit.sleep", + "unit": "h", + "sleepStages": { + "CORE": 3.33, + "DEEP": 1.17, + "REM": 1.42, + "AWAKE": 0.2 + }, + "sleepSourceDiscrepancy": null, + "trend": "flat", + "sparkline": [ + 6.25, + 6.17, + 6.67, + 6.67, + 7.17, + 6.25, + 5.92 + ], + "updatedAt": "", + "allTimeCount": 85, + "lastSeenAt": "anchor+0d+04:15:00", + "direction": { + "direction": "up-good", + "targetPosition": null, + "basis": "metric_default" + }, + "trendSentiment": "neutral" + }, + { + "id": "steps", + "kind": "steps", + "titleKey": "dashboard.metric.title.steps", + "latestValue": 6000, + "secondaryValue": null, + "unitKey": "dashboard.metric.unit.steps", + "unit": null, + "sleepStages": null, + "sleepSourceDiscrepancy": null, + "trend": "down", + "sparkline": [ + 8238, + 7865, + 7492, + 7119, + 6746, + 6373, + 6000 + ], + "updatedAt": "", + "allTimeCount": 30, + "lastSeenAt": "anchor+0d+09:00:00", + "direction": { + "direction": "up-good", + "targetPosition": null, + "basis": "metric_default" + }, + "trendSentiment": "negative" + }, + { + "id": "oxygenSaturation", + "kind": "oxygenSaturation", + "titleKey": "dashboard.metric.title.oxygenSaturation", + "latestValue": 96, + "secondaryValue": null, + "unitKey": "dashboard.metric.unit.oxygenSaturation", + "unit": null, + "sleepStages": null, + "sleepSourceDiscrepancy": null, + "trend": "flat", + "sparkline": [ + 96, + 98, + 97, + 96, + 98, + 97, + 96 + ], + "updatedAt": "", + "allTimeCount": 10, + "lastSeenAt": "anchor+0d+04:40:00", + "direction": { + "direction": "up-good", + "targetPosition": null, + "basis": "metric_default" + }, + "trendSentiment": "neutral" + }, + { + "id": "mood", + "kind": "mood", + "titleKey": "dashboard.metric.title.mood", + "latestValue": 1, + "secondaryValue": null, + "unitKey": "dashboard.metric.unit.mood", + "unit": null, + "sleepStages": null, + "sleepSourceDiscrepancy": null, + "trend": "down", + "sparkline": [ + 4, + 1, + 3, + 5, + 2, + 4, + 1 + ], + "updatedAt": "", + "allTimeCount": 45, + "lastSeenAt": "anchor+0d+00:00:00", + "direction": { + "direction": "up-good", + "targetPosition": null, + "basis": "metric_default" + }, + "trendSentiment": "negative" + }, + { + "id": "bmi", + "kind": "bmi", + "titleKey": "dashboard.metric.title.bmi", + "latestValue": 25.9, + "secondaryValue": null, + "unitKey": "dashboard.metric.unit.bmi", + "unit": null, + "sleepStages": null, + "sleepSourceDiscrepancy": null, + "trend": "flat", + "sparkline": [ + 25.9, + 25.9, + 25.9, + 25.9, + 25.9, + 25.9, + 25.9 + ], + "updatedAt": "", + "allTimeCount": 60, + "lastSeenAt": "anchor+0d+06:30:00", + "direction": { + "direction": "up-bad", + "targetPosition": null, + "basis": "metric_default" + }, + "trendSentiment": "neutral" + } + ], + "sleepRhythm": { + "sleepDebt": { + "state": "ready", + "debtMinutes": 145, + "needMinutes": 420, + "nightsCounted": 5, + "windowNights": 5, + "nightsUntilReady": 0, + "source": "COMPUTED" + }, + "chronotype": { + "state": "ready", + "msfMinutes": 63.33521977432794, + "msfScMinutes": 63.335219774327925, + "band": "extreme_early", + "socialJetlagMinutes": 2.402527629787599, + "freeNightsCounted": 6, + "workNightsCounted": 15, + "freeNightsUntilReady": 0 + }, + "averagePerNight": { + "state": "ready", + "averageMinutes": 388, + "nightsCounted": 21, + "nightsUntilReady": 0 + } + }, + "lastUpdated": "anchor+0d+12:00:00" + }, + "error": null + }, + "events": [ + { + "status": 200, + "action": { + "name": "dashboard.summary" + }, + "meta": { + "cache.analytics.key_hash": 3272136333, + "cache.analytics.outcome": "hit", + "metrics_emitted": 10, + "metrics_gated": 0 + }, + "warnings": null, + "error": null + } + ], + "effects": [] +} diff --git a/tests/integration/routes/parity/__snapshots__/dashboard-summary.03-modules-off.json.snap b/tests/integration/routes/parity/__snapshots__/dashboard-summary.03-modules-off.json.snap new file mode 100644 index 000000000..59a30ed08 --- /dev/null +++ b/tests/integration/routes/parity/__snapshots__/dashboard-summary.03-modules-off.json.snap @@ -0,0 +1,279 @@ +{ + "status": 200, + "body": { + "data": { + "greeting": { + "salutation": "Hi, Sam", + "date": "anchor+0d+12:00:00" + }, + "streak": { + "currentDays": 120, + "longest": 120, + "label": "days in a row" + }, + "compliance": { + "scheduledToday": 2, + "takenToday": 0 + }, + "highlightInsight": null, + "metrics": [ + { + "id": "weight", + "kind": "weight", + "titleKey": "dashboard.metric.title.weight", + "latestValue": 82, + "secondaryValue": null, + "unitKey": "dashboard.metric.unit.weight", + "unit": null, + "sleepStages": null, + "sleepSourceDiscrepancy": null, + "trend": "flat", + "sparkline": [ + 82.2, + 82.2, + 82.2, + 82.1, + 82.1, + 82, + 82 + ], + "updatedAt": "", + "allTimeCount": 60, + "lastSeenAt": "anchor+0d+06:30:00", + "direction": { + "direction": "up-bad", + "targetPosition": null, + "basis": "metric_default" + }, + "trendSentiment": "neutral" + }, + { + "id": "bp", + "kind": "bloodPressure", + "titleKey": "dashboard.metric.title.bloodPressure", + "latestValue": 123, + "secondaryValue": 78, + "unitKey": "dashboard.metric.unit.bloodPressure", + "unit": null, + "sleepStages": null, + "sleepSourceDiscrepancy": null, + "trend": "down", + "sparkline": [ + 135, + 128, + 136, + 129, + 137, + 130, + 123 + ], + "updatedAt": "", + "allTimeCount": 182, + "lastSeenAt": "anchor+0d+07:00:00", + "direction": { + "direction": "up-bad", + "targetPosition": "above", + "basis": "profile_default" + }, + "trendSentiment": "positive" + }, + { + "id": "pulse", + "kind": "pulse", + "titleKey": "dashboard.metric.title.pulse", + "latestValue": 64, + "secondaryValue": null, + "unitKey": "dashboard.metric.unit.pulse", + "unit": null, + "sleepStages": null, + "sleepSourceDiscrepancy": null, + "trend": "flat", + "sparkline": [ + 64, + 69, + 68, + 67, + 66, + 65, + 64 + ], + "updatedAt": "", + "allTimeCount": 60, + "lastSeenAt": "anchor+0d+07:01:00", + "direction": { + "direction": "hold", + "targetPosition": "inside", + "basis": "profile_default" + }, + "trendSentiment": "positive" + }, + { + "id": "bodyFat", + "kind": "bodyFat", + "titleKey": "dashboard.metric.title.bodyFat", + "latestValue": 24, + "secondaryValue": null, + "unitKey": "dashboard.metric.unit.bodyFat", + "unit": null, + "sleepStages": null, + "sleepSourceDiscrepancy": null, + "trend": "flat", + "sparkline": [ + 24.8, + 24.7, + 24.6, + 24.4, + 24.3, + 24.1, + 24 + ], + "updatedAt": "", + "allTimeCount": 9, + "lastSeenAt": "anchor+0d+06:31:00", + "direction": { + "direction": "up-bad", + "targetPosition": null, + "basis": "metric_default" + }, + "trendSentiment": "neutral" + }, + { + "id": "steps", + "kind": "steps", + "titleKey": "dashboard.metric.title.steps", + "latestValue": 6000, + "secondaryValue": null, + "unitKey": "dashboard.metric.unit.steps", + "unit": null, + "sleepStages": null, + "sleepSourceDiscrepancy": null, + "trend": "down", + "sparkline": [ + 8238, + 7865, + 7492, + 7119, + 6746, + 6373, + 6000 + ], + "updatedAt": "", + "allTimeCount": 30, + "lastSeenAt": "anchor+0d+09:00:00", + "direction": { + "direction": "up-good", + "targetPosition": null, + "basis": "metric_default" + }, + "trendSentiment": "negative" + }, + { + "id": "oxygenSaturation", + "kind": "oxygenSaturation", + "titleKey": "dashboard.metric.title.oxygenSaturation", + "latestValue": 96, + "secondaryValue": null, + "unitKey": "dashboard.metric.unit.oxygenSaturation", + "unit": null, + "sleepStages": null, + "sleepSourceDiscrepancy": null, + "trend": "flat", + "sparkline": [ + 96, + 98, + 97, + 96, + 98, + 97, + 96 + ], + "updatedAt": "", + "allTimeCount": 10, + "lastSeenAt": "anchor+0d+04:40:00", + "direction": { + "direction": "up-good", + "targetPosition": null, + "basis": "metric_default" + }, + "trendSentiment": "neutral" + }, + { + "id": "bmi", + "kind": "bmi", + "titleKey": "dashboard.metric.title.bmi", + "latestValue": 25.9, + "secondaryValue": null, + "unitKey": "dashboard.metric.unit.bmi", + "unit": null, + "sleepStages": null, + "sleepSourceDiscrepancy": null, + "trend": "flat", + "sparkline": [ + 25.9, + 25.9, + 25.9, + 25.9, + 25.9, + 25.9, + 25.9 + ], + "updatedAt": "", + "allTimeCount": 60, + "lastSeenAt": "anchor+0d+06:30:00", + "direction": { + "direction": "up-bad", + "targetPosition": null, + "basis": "metric_default" + }, + "trendSentiment": "neutral" + } + ], + "sleepRhythm": { + "sleepDebt": { + "state": "ready", + "debtMinutes": 145, + "needMinutes": 420, + "nightsCounted": 5, + "windowNights": 5, + "nightsUntilReady": 0, + "source": "COMPUTED" + }, + "chronotype": { + "state": "ready", + "msfMinutes": 63.33521977432794, + "msfScMinutes": 63.335219774327925, + "band": "extreme_early", + "socialJetlagMinutes": 2.402527629787599, + "freeNightsCounted": 6, + "workNightsCounted": 15, + "freeNightsUntilReady": 0 + }, + "averagePerNight": { + "state": "ready", + "averageMinutes": 388, + "nightsCounted": 21, + "nightsUntilReady": 0 + } + }, + "lastUpdated": "anchor+0d+12:00:00" + }, + "error": null + }, + "events": [ + { + "status": 200, + "action": { + "name": "dashboard.summary" + }, + "meta": { + "cache.analytics.key_hash": 3272136333, + "cache.analytics.outcome": "hit", + "metrics_emitted": 7, + "metrics_gated": 3 + }, + "warnings": null, + "error": null + } + ], + "effects": [] +} diff --git a/tests/integration/routes/parity/__snapshots__/dashboard-summary.04-de-cached.json.snap b/tests/integration/routes/parity/__snapshots__/dashboard-summary.04-de-cached.json.snap new file mode 100644 index 000000000..24b0d1fb1 --- /dev/null +++ b/tests/integration/routes/parity/__snapshots__/dashboard-summary.04-de-cached.json.snap @@ -0,0 +1,374 @@ +{ + "status": 200, + "body": { + "data": { + "greeting": { + "salutation": "Hi, Sam", + "date": "anchor+0d+12:00:00" + }, + "streak": { + "currentDays": 120, + "longest": 120, + "label": "days in a row" + }, + "compliance": { + "scheduledToday": 2, + "takenToday": 0 + }, + "highlightInsight": null, + "metrics": [ + { + "id": "weight", + "kind": "weight", + "titleKey": "dashboard.metric.title.weight", + "latestValue": 82, + "secondaryValue": null, + "unitKey": "dashboard.metric.unit.weight", + "unit": null, + "sleepStages": null, + "sleepSourceDiscrepancy": null, + "trend": "flat", + "sparkline": [ + 82.2, + 82.2, + 82.2, + 82.1, + 82.1, + 82, + 82 + ], + "updatedAt": "", + "allTimeCount": 60, + "lastSeenAt": "anchor+0d+06:30:00", + "direction": { + "direction": "up-bad", + "targetPosition": null, + "basis": "metric_default" + }, + "trendSentiment": "neutral" + }, + { + "id": "bp", + "kind": "bloodPressure", + "titleKey": "dashboard.metric.title.bloodPressure", + "latestValue": 123, + "secondaryValue": 78, + "unitKey": "dashboard.metric.unit.bloodPressure", + "unit": null, + "sleepStages": null, + "sleepSourceDiscrepancy": null, + "trend": "down", + "sparkline": [ + 135, + 128, + 136, + 129, + 137, + 130, + 123 + ], + "updatedAt": "", + "allTimeCount": 182, + "lastSeenAt": "anchor+0d+07:00:00", + "direction": { + "direction": "up-bad", + "targetPosition": "above", + "basis": "profile_default" + }, + "trendSentiment": "positive" + }, + { + "id": "pulse", + "kind": "pulse", + "titleKey": "dashboard.metric.title.pulse", + "latestValue": 64, + "secondaryValue": null, + "unitKey": "dashboard.metric.unit.pulse", + "unit": null, + "sleepStages": null, + "sleepSourceDiscrepancy": null, + "trend": "flat", + "sparkline": [ + 64, + 69, + 68, + 67, + 66, + 65, + 64 + ], + "updatedAt": "", + "allTimeCount": 60, + "lastSeenAt": "anchor+0d+07:01:00", + "direction": { + "direction": "hold", + "targetPosition": "inside", + "basis": "profile_default" + }, + "trendSentiment": "positive" + }, + { + "id": "bodyFat", + "kind": "bodyFat", + "titleKey": "dashboard.metric.title.bodyFat", + "latestValue": 24, + "secondaryValue": null, + "unitKey": "dashboard.metric.unit.bodyFat", + "unit": null, + "sleepStages": null, + "sleepSourceDiscrepancy": null, + "trend": "flat", + "sparkline": [ + 24.8, + 24.7, + 24.6, + 24.4, + 24.3, + 24.1, + 24 + ], + "updatedAt": "", + "allTimeCount": 9, + "lastSeenAt": "anchor+0d+06:31:00", + "direction": { + "direction": "up-bad", + "targetPosition": null, + "basis": "metric_default" + }, + "trendSentiment": "neutral" + }, + { + "id": "glucose", + "kind": "glucose", + "titleKey": "dashboard.metric.title.glucose", + "latestValue": 128, + "secondaryValue": null, + "unitKey": "dashboard.metric.unit.glucose", + "unit": null, + "sleepStages": null, + "sleepSourceDiscrepancy": null, + "trend": "down", + "sparkline": [ + 117, + 115.33333333333333, + 113.66666666666667, + 113.33333333333333, + 111.66666666666667, + 110, + 108.33333333333333 + ], + "updatedAt": "", + "allTimeCount": 60, + "lastSeenAt": "anchor+0d+11:00:00", + "direction": { + "direction": "up-bad", + "targetPosition": null, + "basis": "metric_default" + }, + "trendSentiment": "positive" + }, + { + "id": "sleep", + "kind": "sleep", + "titleKey": "dashboard.metric.title.sleep", + "latestValue": 5.92, + "secondaryValue": null, + "unitKey": "dashboard.metric.unit.sleep", + "unit": "h", + "sleepStages": { + "CORE": 3.33, + "DEEP": 1.17, + "REM": 1.42, + "AWAKE": 0.2 + }, + "sleepSourceDiscrepancy": null, + "trend": "flat", + "sparkline": [ + 6.25, + 6.17, + 6.67, + 6.67, + 7.17, + 6.25, + 5.92 + ], + "updatedAt": "", + "allTimeCount": 85, + "lastSeenAt": "anchor+0d+04:15:00", + "direction": { + "direction": "up-good", + "targetPosition": null, + "basis": "metric_default" + }, + "trendSentiment": "neutral" + }, + { + "id": "steps", + "kind": "steps", + "titleKey": "dashboard.metric.title.steps", + "latestValue": 6000, + "secondaryValue": null, + "unitKey": "dashboard.metric.unit.steps", + "unit": null, + "sleepStages": null, + "sleepSourceDiscrepancy": null, + "trend": "down", + "sparkline": [ + 8238, + 7865, + 7492, + 7119, + 6746, + 6373, + 6000 + ], + "updatedAt": "", + "allTimeCount": 30, + "lastSeenAt": "anchor+0d+09:00:00", + "direction": { + "direction": "up-good", + "targetPosition": null, + "basis": "metric_default" + }, + "trendSentiment": "negative" + }, + { + "id": "oxygenSaturation", + "kind": "oxygenSaturation", + "titleKey": "dashboard.metric.title.oxygenSaturation", + "latestValue": 96, + "secondaryValue": null, + "unitKey": "dashboard.metric.unit.oxygenSaturation", + "unit": null, + "sleepStages": null, + "sleepSourceDiscrepancy": null, + "trend": "flat", + "sparkline": [ + 96, + 98, + 97, + 96, + 98, + 97, + 96 + ], + "updatedAt": "", + "allTimeCount": 10, + "lastSeenAt": "anchor+0d+04:40:00", + "direction": { + "direction": "up-good", + "targetPosition": null, + "basis": "metric_default" + }, + "trendSentiment": "neutral" + }, + { + "id": "mood", + "kind": "mood", + "titleKey": "dashboard.metric.title.mood", + "latestValue": 1, + "secondaryValue": null, + "unitKey": "dashboard.metric.unit.mood", + "unit": null, + "sleepStages": null, + "sleepSourceDiscrepancy": null, + "trend": "down", + "sparkline": [ + 4, + 1, + 3, + 5, + 2, + 4, + 1 + ], + "updatedAt": "", + "allTimeCount": 45, + "lastSeenAt": "anchor+0d+00:00:00", + "direction": { + "direction": "up-good", + "targetPosition": null, + "basis": "metric_default" + }, + "trendSentiment": "negative" + }, + { + "id": "bmi", + "kind": "bmi", + "titleKey": "dashboard.metric.title.bmi", + "latestValue": 25.9, + "secondaryValue": null, + "unitKey": "dashboard.metric.unit.bmi", + "unit": null, + "sleepStages": null, + "sleepSourceDiscrepancy": null, + "trend": "flat", + "sparkline": [ + 25.9, + 25.9, + 25.9, + 25.9, + 25.9, + 25.9, + 25.9 + ], + "updatedAt": "", + "allTimeCount": 60, + "lastSeenAt": "anchor+0d+06:30:00", + "direction": { + "direction": "up-bad", + "targetPosition": null, + "basis": "metric_default" + }, + "trendSentiment": "neutral" + } + ], + "sleepRhythm": { + "sleepDebt": { + "state": "ready", + "debtMinutes": 145, + "needMinutes": 420, + "nightsCounted": 5, + "windowNights": 5, + "nightsUntilReady": 0, + "source": "COMPUTED" + }, + "chronotype": { + "state": "ready", + "msfMinutes": 63.33521977432794, + "msfScMinutes": 63.335219774327925, + "band": "extreme_early", + "socialJetlagMinutes": 2.402527629787599, + "freeNightsCounted": 6, + "workNightsCounted": 15, + "freeNightsUntilReady": 0 + }, + "averagePerNight": { + "state": "ready", + "averageMinutes": 388, + "nightsCounted": 21, + "nightsUntilReady": 0 + } + }, + "lastUpdated": "anchor+0d+12:00:00" + }, + "error": null + }, + "events": [ + { + "status": 200, + "action": { + "name": "dashboard.summary" + }, + "meta": { + "cache.analytics.key_hash": 3272136333, + "cache.analytics.outcome": "hit", + "metrics_emitted": 10, + "metrics_gated": 0 + }, + "warnings": null, + "error": null + } + ], + "effects": [] +} diff --git a/tests/integration/routes/parity/__snapshots__/dashboard-summary.05-manager.json.snap b/tests/integration/routes/parity/__snapshots__/dashboard-summary.05-manager.json.snap new file mode 100644 index 000000000..24b0d1fb1 --- /dev/null +++ b/tests/integration/routes/parity/__snapshots__/dashboard-summary.05-manager.json.snap @@ -0,0 +1,374 @@ +{ + "status": 200, + "body": { + "data": { + "greeting": { + "salutation": "Hi, Sam", + "date": "anchor+0d+12:00:00" + }, + "streak": { + "currentDays": 120, + "longest": 120, + "label": "days in a row" + }, + "compliance": { + "scheduledToday": 2, + "takenToday": 0 + }, + "highlightInsight": null, + "metrics": [ + { + "id": "weight", + "kind": "weight", + "titleKey": "dashboard.metric.title.weight", + "latestValue": 82, + "secondaryValue": null, + "unitKey": "dashboard.metric.unit.weight", + "unit": null, + "sleepStages": null, + "sleepSourceDiscrepancy": null, + "trend": "flat", + "sparkline": [ + 82.2, + 82.2, + 82.2, + 82.1, + 82.1, + 82, + 82 + ], + "updatedAt": "", + "allTimeCount": 60, + "lastSeenAt": "anchor+0d+06:30:00", + "direction": { + "direction": "up-bad", + "targetPosition": null, + "basis": "metric_default" + }, + "trendSentiment": "neutral" + }, + { + "id": "bp", + "kind": "bloodPressure", + "titleKey": "dashboard.metric.title.bloodPressure", + "latestValue": 123, + "secondaryValue": 78, + "unitKey": "dashboard.metric.unit.bloodPressure", + "unit": null, + "sleepStages": null, + "sleepSourceDiscrepancy": null, + "trend": "down", + "sparkline": [ + 135, + 128, + 136, + 129, + 137, + 130, + 123 + ], + "updatedAt": "", + "allTimeCount": 182, + "lastSeenAt": "anchor+0d+07:00:00", + "direction": { + "direction": "up-bad", + "targetPosition": "above", + "basis": "profile_default" + }, + "trendSentiment": "positive" + }, + { + "id": "pulse", + "kind": "pulse", + "titleKey": "dashboard.metric.title.pulse", + "latestValue": 64, + "secondaryValue": null, + "unitKey": "dashboard.metric.unit.pulse", + "unit": null, + "sleepStages": null, + "sleepSourceDiscrepancy": null, + "trend": "flat", + "sparkline": [ + 64, + 69, + 68, + 67, + 66, + 65, + 64 + ], + "updatedAt": "", + "allTimeCount": 60, + "lastSeenAt": "anchor+0d+07:01:00", + "direction": { + "direction": "hold", + "targetPosition": "inside", + "basis": "profile_default" + }, + "trendSentiment": "positive" + }, + { + "id": "bodyFat", + "kind": "bodyFat", + "titleKey": "dashboard.metric.title.bodyFat", + "latestValue": 24, + "secondaryValue": null, + "unitKey": "dashboard.metric.unit.bodyFat", + "unit": null, + "sleepStages": null, + "sleepSourceDiscrepancy": null, + "trend": "flat", + "sparkline": [ + 24.8, + 24.7, + 24.6, + 24.4, + 24.3, + 24.1, + 24 + ], + "updatedAt": "", + "allTimeCount": 9, + "lastSeenAt": "anchor+0d+06:31:00", + "direction": { + "direction": "up-bad", + "targetPosition": null, + "basis": "metric_default" + }, + "trendSentiment": "neutral" + }, + { + "id": "glucose", + "kind": "glucose", + "titleKey": "dashboard.metric.title.glucose", + "latestValue": 128, + "secondaryValue": null, + "unitKey": "dashboard.metric.unit.glucose", + "unit": null, + "sleepStages": null, + "sleepSourceDiscrepancy": null, + "trend": "down", + "sparkline": [ + 117, + 115.33333333333333, + 113.66666666666667, + 113.33333333333333, + 111.66666666666667, + 110, + 108.33333333333333 + ], + "updatedAt": "", + "allTimeCount": 60, + "lastSeenAt": "anchor+0d+11:00:00", + "direction": { + "direction": "up-bad", + "targetPosition": null, + "basis": "metric_default" + }, + "trendSentiment": "positive" + }, + { + "id": "sleep", + "kind": "sleep", + "titleKey": "dashboard.metric.title.sleep", + "latestValue": 5.92, + "secondaryValue": null, + "unitKey": "dashboard.metric.unit.sleep", + "unit": "h", + "sleepStages": { + "CORE": 3.33, + "DEEP": 1.17, + "REM": 1.42, + "AWAKE": 0.2 + }, + "sleepSourceDiscrepancy": null, + "trend": "flat", + "sparkline": [ + 6.25, + 6.17, + 6.67, + 6.67, + 7.17, + 6.25, + 5.92 + ], + "updatedAt": "", + "allTimeCount": 85, + "lastSeenAt": "anchor+0d+04:15:00", + "direction": { + "direction": "up-good", + "targetPosition": null, + "basis": "metric_default" + }, + "trendSentiment": "neutral" + }, + { + "id": "steps", + "kind": "steps", + "titleKey": "dashboard.metric.title.steps", + "latestValue": 6000, + "secondaryValue": null, + "unitKey": "dashboard.metric.unit.steps", + "unit": null, + "sleepStages": null, + "sleepSourceDiscrepancy": null, + "trend": "down", + "sparkline": [ + 8238, + 7865, + 7492, + 7119, + 6746, + 6373, + 6000 + ], + "updatedAt": "", + "allTimeCount": 30, + "lastSeenAt": "anchor+0d+09:00:00", + "direction": { + "direction": "up-good", + "targetPosition": null, + "basis": "metric_default" + }, + "trendSentiment": "negative" + }, + { + "id": "oxygenSaturation", + "kind": "oxygenSaturation", + "titleKey": "dashboard.metric.title.oxygenSaturation", + "latestValue": 96, + "secondaryValue": null, + "unitKey": "dashboard.metric.unit.oxygenSaturation", + "unit": null, + "sleepStages": null, + "sleepSourceDiscrepancy": null, + "trend": "flat", + "sparkline": [ + 96, + 98, + 97, + 96, + 98, + 97, + 96 + ], + "updatedAt": "", + "allTimeCount": 10, + "lastSeenAt": "anchor+0d+04:40:00", + "direction": { + "direction": "up-good", + "targetPosition": null, + "basis": "metric_default" + }, + "trendSentiment": "neutral" + }, + { + "id": "mood", + "kind": "mood", + "titleKey": "dashboard.metric.title.mood", + "latestValue": 1, + "secondaryValue": null, + "unitKey": "dashboard.metric.unit.mood", + "unit": null, + "sleepStages": null, + "sleepSourceDiscrepancy": null, + "trend": "down", + "sparkline": [ + 4, + 1, + 3, + 5, + 2, + 4, + 1 + ], + "updatedAt": "", + "allTimeCount": 45, + "lastSeenAt": "anchor+0d+00:00:00", + "direction": { + "direction": "up-good", + "targetPosition": null, + "basis": "metric_default" + }, + "trendSentiment": "negative" + }, + { + "id": "bmi", + "kind": "bmi", + "titleKey": "dashboard.metric.title.bmi", + "latestValue": 25.9, + "secondaryValue": null, + "unitKey": "dashboard.metric.unit.bmi", + "unit": null, + "sleepStages": null, + "sleepSourceDiscrepancy": null, + "trend": "flat", + "sparkline": [ + 25.9, + 25.9, + 25.9, + 25.9, + 25.9, + 25.9, + 25.9 + ], + "updatedAt": "", + "allTimeCount": 60, + "lastSeenAt": "anchor+0d+06:30:00", + "direction": { + "direction": "up-bad", + "targetPosition": null, + "basis": "metric_default" + }, + "trendSentiment": "neutral" + } + ], + "sleepRhythm": { + "sleepDebt": { + "state": "ready", + "debtMinutes": 145, + "needMinutes": 420, + "nightsCounted": 5, + "windowNights": 5, + "nightsUntilReady": 0, + "source": "COMPUTED" + }, + "chronotype": { + "state": "ready", + "msfMinutes": 63.33521977432794, + "msfScMinutes": 63.335219774327925, + "band": "extreme_early", + "socialJetlagMinutes": 2.402527629787599, + "freeNightsCounted": 6, + "workNightsCounted": 15, + "freeNightsUntilReady": 0 + }, + "averagePerNight": { + "state": "ready", + "averageMinutes": 388, + "nightsCounted": 21, + "nightsUntilReady": 0 + } + }, + "lastUpdated": "anchor+0d+12:00:00" + }, + "error": null + }, + "events": [ + { + "status": 200, + "action": { + "name": "dashboard.summary" + }, + "meta": { + "cache.analytics.key_hash": 3272136333, + "cache.analytics.outcome": "hit", + "metrics_emitted": 10, + "metrics_gated": 0 + }, + "warnings": null, + "error": null + } + ], + "effects": [] +} diff --git a/tests/integration/routes/parity/__snapshots__/dashboard-summary.06-reader.json.snap b/tests/integration/routes/parity/__snapshots__/dashboard-summary.06-reader.json.snap new file mode 100644 index 000000000..b4e2a65a9 --- /dev/null +++ b/tests/integration/routes/parity/__snapshots__/dashboard-summary.06-reader.json.snap @@ -0,0 +1,26 @@ +{ + "status": 403, + "body": { + "data": null, + "error": "Account access denied", + "meta": { + "errorCode": "sharing.access.denied", + "requestId": "" + } + }, + "events": [ + { + "status": 403, + "action": null, + "meta": { + "sharing_refusal": "insufficient_access" + }, + "warnings": null, + "error": { + "type": "SharingAccessDeniedError", + "message": "Account access denied" + } + } + ], + "effects": [] +} diff --git a/tests/integration/routes/parity/__snapshots__/dashboard-summary.07-anonymous.json.snap b/tests/integration/routes/parity/__snapshots__/dashboard-summary.07-anonymous.json.snap new file mode 100644 index 000000000..b1fdd5326 --- /dev/null +++ b/tests/integration/routes/parity/__snapshots__/dashboard-summary.07-anonymous.json.snap @@ -0,0 +1,24 @@ +{ + "status": 401, + "body": { + "data": null, + "error": "Not authenticated", + "meta": { + "errorCode": "auth.missing", + "requestId": "" + } + }, + "events": [ + { + "status": 401, + "action": null, + "meta": null, + "warnings": null, + "error": { + "type": "HttpError", + "message": "Not authenticated" + } + } + ], + "effects": [] +} diff --git a/tests/integration/routes/parity/__snapshots__/dashboard-summary.08-empty-account.json.snap b/tests/integration/routes/parity/__snapshots__/dashboard-summary.08-empty-account.json.snap new file mode 100644 index 000000000..b71dc8fc2 --- /dev/null +++ b/tests/integration/routes/parity/__snapshots__/dashboard-summary.08-empty-account.json.snap @@ -0,0 +1,100 @@ +{ + "status": 200, + "body": { + "data": { + "greeting": { + "salutation": "Hi, empty-account", + "date": "anchor+0d+12:00:00" + }, + "streak": { + "currentDays": 0, + "longest": 0, + "label": "days in a row" + }, + "compliance": { + "scheduledToday": 0, + "takenToday": 0 + }, + "highlightInsight": null, + "metrics": [ + { + "id": "weight", + "kind": "weight", + "titleKey": "dashboard.metric.title.weight", + "latestValue": null, + "secondaryValue": null, + "unitKey": "dashboard.metric.unit.weight", + "unit": null, + "sleepStages": null, + "sleepSourceDiscrepancy": null, + "trend": "unknown", + "sparkline": [], + "updatedAt": null, + "allTimeCount": 0, + "lastSeenAt": null, + "direction": { + "direction": "up-bad", + "targetPosition": null, + "basis": "metric_default" + }, + "trendSentiment": "neutral" + } + ], + "sleepRhythm": { + "sleepDebt": { + "state": "partial", + "debtMinutes": 0, + "needMinutes": 420, + "nightsCounted": 0, + "windowNights": 5, + "nightsUntilReady": 4, + "source": "COMPUTED" + }, + "chronotype": { + "state": "learning", + "msfMinutes": null, + "msfScMinutes": null, + "band": null, + "socialJetlagMinutes": null, + "freeNightsCounted": 0, + "workNightsCounted": 0, + "freeNightsUntilReady": 3 + }, + "averagePerNight": { + "state": "partial", + "averageMinutes": 0, + "nightsCounted": 0, + "nightsUntilReady": 4 + } + }, + "lastUpdated": "anchor+0d+12:00:00" + }, + "error": null + }, + "events": [ + { + "status": 200, + "action": { + "name": "dashboard.summary" + }, + "meta": { + "cache.analytics.key_hash": 1944272078, + "cache.analytics.outcome": "miss", + "dashboard.sub_allTime_ms": 0, + "dashboard.sub_bmi_ms": 0, + "dashboard.sub_latestEver_ms": 0, + "dashboard.sub_medsToday_ms": 0, + "dashboard.sub_moodSeries_ms": 0, + "dashboard.sub_sleepNights_ms": 0, + "dashboard.sub_sparkline_ms": 0, + "dashboard.sub_streakDays_ms": 0, + "dashboard.sub_streakIntakes_ms": 0, + "metrics_emitted": 1, + "metrics_gated": 0 + }, + "warnings": null, + "error": null + } + ], + "effects": [] +} diff --git a/tests/integration/routes/parity/dashboard-summary.parity.test.ts b/tests/integration/routes/parity/dashboard-summary.parity.test.ts new file mode 100644 index 000000000..e70743b6b --- /dev/null +++ b/tests/integration/routes/parity/dashboard-summary.parity.test.ts @@ -0,0 +1,201 @@ +/** + * Parity for `GET /api/dashboard/summary` while its builder moves into + * `src/lib/dashboard/`. + * + * One record carries every block the summary shapes (`record-fixture.ts`): + * the walk reads it cold, warm, with modules off (gated after the cache), + * in another language (served from the cache that still holds the first + * greeting), for a delegate who may manage the record and one who may only + * read it, without credentials, and for an account with no data. The + * fire-and-forget rollup refresh is recorded instead of run. + * + * The clock is pinned to noon of the current UTC day and the snapshot is + * written relative to the start of that day (`relativeToAnchor`), because + * the per-type reads cut their windows in SQL against the database clock. + */ +import { afterAll, beforeAll, describe, expect, it, vi } from "vitest"; + +import { GET } from "@/app/api/dashboard/summary/route"; +import { settleBackgroundTasks } from "@/lib/logging/background-tasks"; + +import { anonymous, callRoute, type RouteAuth } from "../../../kit/call-route"; +import { makeGrant, makeSession, makeUser } from "../../../kit/factories"; +import { + effectRecorder, + eventFacts, + expectParity, + relativeToAnchor, + stable, + startOfUtcToday, + wideEventRecorder, +} from "../../../kit/parity"; +import { + getPrismaClient, + switchSessionTo, + truncateAllTables, +} from "../../setup"; +import { parityId, seedParityRecord } from "./record-fixture"; + +vi.mock("@/lib/logging/transports", async (importOriginal) => { + const actual = + await importOriginal(); + const { wideEventRecorder: recorder } = await import("../../../kit/parity"); + return { + ...actual, + emitIfSampled: (event: (typeof recorder.events)[number]) => { + recorder.events.push(event); + }, + }; +}); +vi.mock("@/lib/rollups/measurement-rollups", async (importOriginal) => { + const actual = + await importOriginal(); + const { effectRecorder } = await import("../../../kit/parity"); + return { + ...actual, + ensureUserRollupsFresh: async (...args: unknown[]) => { + effectRecorder.record("ensureUserRollupsFresh", args); + }, + }; +}); + +const prisma = getPrismaClient(); +const ANCHOR = startOfUtcToday(); +const NOW = new Date(ANCHOR.getTime() + 12 * 60 * 60 * 1000); +const TZ = "UTC"; +const OWNER_ID = parityId("dashsum", 1); +const EMPTY_ID = parityId("dashsum", 2); + +let owner: RouteAuth; +let empty: RouteAuth; +let manager: RouteAuth & { sessionId: string }; +let reader: RouteAuth & { sessionId: string }; + +async function step( + name: string, + auth: RouteAuth = owner, + contract?: { skip: string }, +): Promise { + wideEventRecorder.take(); + effectRecorder.take(); + const res = await callRoute(GET, { + method: "GET", + route: "/api/dashboard/summary", + auth, + ...(contract ? { contract } : {}), + }); + const events = wideEventRecorder.take(); + expect(events.length).toBeGreaterThan(0); + await settleBackgroundTasks(); + await expectParity( + `dashboard-summary.${name}`, + stable( + relativeToAnchor( + { + status: res.status, + body: res.body, + events: events.map(eventFacts).map(withSortedMeta), + effects: effectRecorder.take(), + }, + ANCHOR, + ), + { since: NOW }, + ), + ); +} + +/** + * The builder's sub-reads run concurrently and each annotates its own timing + * when it settles, so the meta keys arrive in a different order on each run. + * The values are the same; the keys are sorted. + */ +function withSortedMeta(facts: unknown): unknown { + const f = facts as { meta?: Record }; + if (!f.meta) return facts; + return { + ...f, + meta: Object.fromEntries( + Object.entries(f.meta).sort(([a], [b]) => a.localeCompare(b)), + ), + }; +} + +beforeAll(async () => { + vi.useFakeTimers({ toFake: ["Date"], now: NOW }); + await truncateAllTables(prisma); + const ownerRow = await makeUser({ + id: OWNER_ID, + timezone: TZ, + locale: "en", + displayName: "Sam", + heightCm: 178, + dateOfBirth: new Date("1975-04-02T00:00:00.000Z"), + gender: "male", + }); + await seedParityRecord({ userId: OWNER_ID, now: NOW, tz: TZ, tag: "ds" }); + const rollups = await vi.importActual< + typeof import("@/lib/rollups/measurement-rollups") + >("@/lib/rollups/measurement-rollups"); + await rollups.ensureUserRollupsFresh(OWNER_ID); + await settleBackgroundTasks(); + owner = await makeSession(ownerRow); + const emptyRow = await makeUser({ + id: EMPTY_ID, + username: "empty-account", + timezone: "UTC", + }); + empty = await makeSession(emptyRow); + const managerRow = await makeUser({ timezone: "UTC", locale: "de" }); + await makeGrant(ownerRow, managerRow, { access: "MANAGE" }); + manager = await makeSession(managerRow); + const readerRow = await makeUser({ timezone: "UTC" }); + await makeGrant(ownerRow, readerRow); + reader = await makeSession(readerRow); +}); + +afterAll(() => { + vi.useRealTimers(); +}); + +describe("GET /api/dashboard/summary parity", () => { + it("01 cold, then warm", async () => { + await step("01-cold"); + await step("02-warm"); + }); + + it("03 modules off, gated after the cache", async () => { + await prisma.user.update({ + where: { id: OWNER_ID }, + data: { + modulePreferencesJson: { glucose: false, sleep: false, mood: false }, + }, + }); + await step("03-modules-off"); + await prisma.user.update({ + where: { id: OWNER_ID }, + data: { modulePreferencesJson: {} }, + }); + }); + + it("04 another language, served from the cache", async () => { + await prisma.user.update({ + where: { id: OWNER_ID }, + data: { locale: "de" }, + }); + await step("04-de-cached"); + }); + + it("05 a delegate who may manage, and one who may only read", async () => { + await switchSessionTo(manager.sessionId, OWNER_ID); + await step("05-manager", manager); + await switchSessionTo(manager.sessionId, null); + await switchSessionTo(reader.sessionId, OWNER_ID); + await step("06-reader", reader); + await switchSessionTo(reader.sessionId, null); + }); + + it("07 no credentials, and an account with no data", async () => { + await step("07-anonymous", anonymous); + await step("08-empty-account", empty); + }); +});