mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-13 14:32:03 +00:00
fix(sleep): round night minute totals to whole numbers
`GET /api/sleep/night` summed second-precision stage rows into asleep / awake totals and serialised them unrounded (e.g. 433.4999), which also violated the OpenAPI integer contract. Round the present minute values; `inBedMinutes` / `awakeMinutes` stay null when the night never saw that stage.
This commit is contained in:
1 parent
6a4d3fd553
commit
b59f8118a9
2 files changed
+25
-3
No files matched your search
@@ -103,6 +103,24 @@ describe("GET /api/sleep/night", () => {
|
||||
expect(core.end).toBe("2026-06-04T01:00:00.000Z");
|
||||
});
|
||||
|
||||
it("rounds asleep / awake minutes to whole numbers", async () => {
|
||||
// iOS #18 — `asleepMinutesOf` / awake totals sum raw second-precision
|
||||
// minute values, so a night sums to e.g. 433.4999; the serializer must
|
||||
// emit whole minutes. CORE+DEEP = 433.4999 → 433; AWAKE 12.6 → 13.
|
||||
vi.mocked(getSession).mockResolvedValue(SESSION_OK as never);
|
||||
vi.mocked(prisma.measurement.findMany).mockResolvedValue([
|
||||
stage("2026-06-04T03:00:00.000Z", "CORE", 300.25),
|
||||
stage("2026-06-04T05:00:00.000Z", "DEEP", 133.2499),
|
||||
stage("2026-06-04T05:10:00.000Z", "AWAKE", 12.6),
|
||||
] as never);
|
||||
const res = await GET(req("date=2026-06-04"));
|
||||
const body = await res.json();
|
||||
expect(body.data.main.asleepMinutes).toBe(433);
|
||||
expect(body.data.main.awakeMinutes).toBe(13);
|
||||
expect(Number.isInteger(body.data.main.asleepMinutes)).toBe(true);
|
||||
expect(Number.isInteger(body.data.main.awakeMinutes)).toBe(true);
|
||||
});
|
||||
|
||||
it("defaults to the most recent scorable night when date omitted", async () => {
|
||||
vi.mocked(getSession).mockResolvedValue(SESSION_OK as never);
|
||||
vi.mocked(prisma.measurement.findMany).mockResolvedValue([
|
||||
|
||||
@@ -56,9 +56,13 @@ function serializeSession(s: SleepSession) {
|
||||
source: s.source,
|
||||
start: s.start.toISOString(),
|
||||
end: s.end.toISOString(),
|
||||
asleepMinutes: s.asleepMinutes,
|
||||
inBedMinutes: s.inBedMinutes,
|
||||
awakeMinutes: s.awakeMinutes,
|
||||
// iOS #18 — round to whole minutes; the underlying totals are summed from
|
||||
// second-precision segments and otherwise serialise as e.g. 433.4999.
|
||||
// `inBedMinutes` / `awakeMinutes` stay null when the night never saw that
|
||||
// stage — rounding only the present values.
|
||||
asleepMinutes: Math.round(s.asleepMinutes),
|
||||
inBedMinutes: s.inBedMinutes === null ? null : Math.round(s.inBedMinutes),
|
||||
awakeMinutes: s.awakeMinutes === null ? null : Math.round(s.awakeMinutes),
|
||||
awakenings: s.awakenings,
|
||||
stages: s.stages,
|
||||
segments: s.segments.map((seg) => ({
|
||||
|
||||
Reference in new issue
Block a user