mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-12 14:16:12 +00:00
test(dawarich): pin the movement block, the channels and the mocks; document the connection
Covers the day section, the model projection without the travel country and the two correlation channels; the backup and correlation mocks learn the new delegate. Adds the operator page for DAWARICH_PRIVATE_ORIGINS and regenerates the API contract.
This commit is contained in:
1 parent
b99bcaeec6
commit
c03f79afd5
7 files changed
+372
-58
No files matched your search
@@ -216,6 +216,7 @@ beforeEach(() => {
|
||||
vi.mocked(prisma.environmentTravelLocation.findMany).mockResolvedValue(
|
||||
[] as never,
|
||||
);
|
||||
vi.mocked(prisma.dawarichDay.findMany).mockResolvedValue([] as never);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
|
||||
@@ -160,6 +160,7 @@ beforeEach(() => {
|
||||
).mockResolvedValue([]);
|
||||
vi.mocked(prisma.customMetric.findMany).mockResolvedValue([] as never);
|
||||
vi.mocked(prisma.symptomDefinition.findMany).mockResolvedValue([] as never);
|
||||
vi.mocked(prisma.dawarichDay.findMany).mockResolvedValue([] as never);
|
||||
vi.mocked(hadFindingsBeforeSeasonalAdjustment).mockResolvedValue(false);
|
||||
});
|
||||
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
/**
|
||||
* "On the move" renders the server's values as they come and leaves out what
|
||||
* the day has no value for: a null is no coverage, never a zero.
|
||||
*/
|
||||
import { renderToStaticMarkup } from "react-dom/server";
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
import { I18nProvider } from "@/lib/i18n/context";
|
||||
|
||||
import { DayMovementSection } from "../day-movement";
|
||||
|
||||
function render(
|
||||
movement: Parameters<typeof DayMovementSection>[0]["movement"],
|
||||
) {
|
||||
return renderToStaticMarkup(
|
||||
<I18nProvider initialLocale="en">
|
||||
<DayMovementSection movement={movement} />
|
||||
</I18nProvider>,
|
||||
);
|
||||
}
|
||||
|
||||
const base = {
|
||||
source: "dawarich" as const,
|
||||
distance: { unit: "km" as const, total: 48.3, driving: 12, train: 0 },
|
||||
placesVisited: 4,
|
||||
awayFromHomeMinutes: 600,
|
||||
travel: { isTravelDay: true, countryCode: "ES" },
|
||||
fetchedAt: "2026-06-16T01:20:00.000Z",
|
||||
};
|
||||
|
||||
describe("DayMovementSection", () => {
|
||||
it("shows each value the day has", () => {
|
||||
const html = render(base);
|
||||
expect(html).toContain('data-movement="total"');
|
||||
expect(html).toContain("48.3 km");
|
||||
expect(html).toContain('data-movement="driving"');
|
||||
expect(html).toContain('data-movement="away"');
|
||||
expect(html).toContain("Spain");
|
||||
// No train that day: no row, rather than "0 km".
|
||||
expect(html).not.toContain('data-movement="train"');
|
||||
});
|
||||
|
||||
it("leaves out time away from home without coverage", () => {
|
||||
const html = render({
|
||||
...base,
|
||||
awayFromHomeMinutes: null,
|
||||
travel: null,
|
||||
});
|
||||
expect(html).not.toContain('data-movement="away"');
|
||||
expect(html).not.toContain('data-movement="travel"');
|
||||
});
|
||||
|
||||
it("renders nothing when the day has no value at all", () => {
|
||||
const html = render({
|
||||
...base,
|
||||
distance: { unit: "mi", total: null, driving: null, train: null },
|
||||
placesVisited: null,
|
||||
awayFromHomeMinutes: null,
|
||||
travel: null,
|
||||
});
|
||||
expect(html).toBe("");
|
||||
});
|
||||
});
|
||||
@@ -222,3 +222,36 @@ describe("scores", () => {
|
||||
expect(JSON.stringify(projected.scores)).not.toContain("COMPUTED");
|
||||
});
|
||||
});
|
||||
|
||||
describe("the movement block (v1.43)", () => {
|
||||
const withMovement: DayResponse = {
|
||||
...day,
|
||||
movement: {
|
||||
source: "dawarich",
|
||||
distance: { unit: "km", total: 48.3, driving: 12, train: 30.5 },
|
||||
placesVisited: 4,
|
||||
awayFromHomeMinutes: 600,
|
||||
travel: { isTravelDay: true, countryCode: "ES" },
|
||||
fetchedAt: "2026-03-30T01:20:00.000Z",
|
||||
},
|
||||
};
|
||||
|
||||
it("reaches a model without the country of the travel day", () => {
|
||||
const model = projectDayForModel(withMovement, []);
|
||||
expect(model.movement).toEqual({
|
||||
distance: { unit: "km", total: 48.3, driving: 12, train: 30.5 },
|
||||
placesVisited: 4,
|
||||
awayFromHomeMinutes: 600,
|
||||
travel: { isTravelDay: true },
|
||||
});
|
||||
expect(JSON.stringify(model)).not.toContain("ES");
|
||||
});
|
||||
|
||||
it("stays out when the caller excludes the environment section", () => {
|
||||
const model = projectDayForModel(withMovement, [], undefined, {
|
||||
sections: new Set(["environment"]),
|
||||
types: new Set(),
|
||||
});
|
||||
expect(model).not.toHaveProperty("movement");
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,47 @@
|
||||
/**
|
||||
* The two Dawarich movement channels: hours away from home and kilometres
|
||||
* travelled, one point per stored day that has the value. A day without it is
|
||||
* no coverage and gets no point, never a zero.
|
||||
*/
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
|
||||
const { findMany } = vi.hoisted(() => ({ findMany: vi.fn() }));
|
||||
vi.mock("@/lib/db", () => ({ prisma: { dawarichDay: { findMany } } }));
|
||||
|
||||
import { fetchMovementSeries } from "@/lib/insights/correlation-channel-series";
|
||||
import { metricFamily } from "@/lib/insights/correlation-discovery";
|
||||
|
||||
describe("fetchMovementSeries", () => {
|
||||
it("emits a point only where the day has the value", async () => {
|
||||
findMany.mockResolvedValue([
|
||||
{ date: "2026-06-14", awayFromHomeMinutes: 90, totalDistanceM: null },
|
||||
{ date: "2026-06-15", awayFromHomeMinutes: null, totalDistanceM: 48_300 },
|
||||
]);
|
||||
const [away, distance] = await fetchMovementSeries(
|
||||
"u1",
|
||||
"Europe/Berlin",
|
||||
new Date("2026-06-01T12:00:00Z"),
|
||||
);
|
||||
expect(away).toMatchObject({
|
||||
key: "MOVEMENT_AWAY",
|
||||
role: "behaviour",
|
||||
points: [{ day: "2026-06-14", value: 1.5 }],
|
||||
});
|
||||
expect(distance).toMatchObject({
|
||||
key: "MOVEMENT_DISTANCE",
|
||||
role: "behaviour",
|
||||
points: [{ day: "2026-06-15", value: 48.3 }],
|
||||
});
|
||||
expect(findMany.mock.calls[0][0].where).toEqual({
|
||||
userId: "u1",
|
||||
date: { gte: "2026-06-01" },
|
||||
});
|
||||
});
|
||||
|
||||
it("keeps the two channels in one family so they never pair with each other", () => {
|
||||
expect(metricFamily("MOVEMENT_AWAY")).toBe(
|
||||
metricFamily("MOVEMENT_DISTANCE"),
|
||||
);
|
||||
expect(metricFamily("MOVEMENT_AWAY")).not.toBe(metricFamily("MOOD"));
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user