mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-09 04:50:59 +00:00
test(meds): green the wizard e2e locale and one-shot timezone fixtures
The medication-wizard e2e specs assert the German step counter, but the seeded e2e user falls back to the English default locale; pin the `healthlog-locale=de` cookie for the wizard flow and correct the storage-state cookie allowlist to the hyphenated cookie name the i18n layer actually reads. The one-shot cadence integration fixture derived `startsOn`/`endsOn` from the UTC calendar date but checked emission against the Europe/Berlin today-window, so the assertion flipped when the suite ran in the UTC evening. Derive the fixture dates from the same Berlin calendar day the window uses. Also refresh the OpenAPI spec version to 1.6.0. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
8ee7aaac44
commit
ac1d03f8ea
4 files changed
+41
-24
No files matched your search
@@ -1,7 +1,7 @@
|
||||
openapi: 3.1.0
|
||||
info:
|
||||
title: HealthLog API
|
||||
version: 1.5.6
|
||||
version: 1.6.0
|
||||
description: >-
|
||||
Self-hosted personal-health-tracking PWA — public API surface for the iOS native client and external ingest.
|
||||
|
||||
|
||||
@@ -124,6 +124,23 @@ export async function stubDashboardAnalytics(page: Page): Promise<void> {
|
||||
* redirects to `/medications?new=1` and opens the create dialog).
|
||||
*/
|
||||
export async function openCreateWizard(page: Page): Promise<void> {
|
||||
// Pin the German locale for the wizard flow. The app default locale is
|
||||
// English; these specs assert the "Schritt N von M" counter and other
|
||||
// German label surfaces, which only render when the `healthlog-locale`
|
||||
// cookie resolves to "de". Both the server layout and the client i18n
|
||||
// provider read this exact cookie name, so setting it before the first
|
||||
// navigation makes the dialog render German on first paint. Scoped here
|
||||
// rather than in the shared auth state so English-asserting specs keep
|
||||
// the default locale.
|
||||
await page.context().addCookies([
|
||||
{
|
||||
name: "healthlog-locale",
|
||||
value: "de",
|
||||
url: page.url().startsWith("http")
|
||||
? new URL(page.url()).origin
|
||||
: "http://localhost:3000",
|
||||
},
|
||||
]);
|
||||
await page.goto("/medications/new", { waitUntil: "domcontentloaded" });
|
||||
await expect(
|
||||
page.locator('[data-slot="medication-wizard-dialog"]'),
|
||||
|
||||
@@ -181,7 +181,7 @@ export default async function globalSetup(config: FullConfig): Promise<void> {
|
||||
// already-onboarded ones, so for our pre-seeded completed e2e user
|
||||
// the cookie is absent and the proxy passes the dashboard through.
|
||||
state.cookies = state.cookies.filter((c) =>
|
||||
["healthlog_session", "healthlog_locale", "hl_onboarding"].includes(c.name),
|
||||
["healthlog_session", "healthlog-locale", "hl_onboarding"].includes(c.name),
|
||||
);
|
||||
await writeFile(STORAGE_STATE_PATH, JSON.stringify(state, null, 2));
|
||||
await ctx.dispose();
|
||||
|
||||
@@ -133,6 +133,26 @@ async function loadCanonical(medicationId: string): Promise<{
|
||||
* matching `getUserTodayBounds` in `src/lib/timezone.ts` so the test
|
||||
* window matches what the worker would build on that tick.
|
||||
*/
|
||||
// UTC midnight on the local calendar day that `now` falls within for `tz`.
|
||||
// Mirrors the column convention for `startsOn`/`endsOn` (stored as
|
||||
// `...T00:00:00.000Z` on the local calendar day). Deriving the day from
|
||||
// the same timezone `todayBounds` uses keeps a one-shot's emit day inside
|
||||
// the checked window regardless of wall-clock time — reading the UTC date
|
||||
// instead drifts a day late in the UTC evening when the local zone has
|
||||
// already rolled into the next calendar day.
|
||||
function localCalendarMidnightUtc(now: Date, tz: string): Date {
|
||||
const parts = new Intl.DateTimeFormat("en-CA", {
|
||||
timeZone: tz,
|
||||
year: "numeric",
|
||||
month: "2-digit",
|
||||
day: "2-digit",
|
||||
}).formatToParts(now);
|
||||
const y = Number(parts.find((p) => p.type === "year")?.value);
|
||||
const m = Number(parts.find((p) => p.type === "month")?.value);
|
||||
const d = Number(parts.find((p) => p.type === "day")?.value);
|
||||
return new Date(Date.UTC(y, m - 1, d, 0, 0, 0, 0));
|
||||
}
|
||||
|
||||
function todayBounds(now: Date, tz: string): { start: Date; end: Date } {
|
||||
const parts = new Intl.DateTimeFormat("en-CA", {
|
||||
timeZone: tz,
|
||||
@@ -467,17 +487,7 @@ describe("one-shot lifecycle", () => {
|
||||
it("mints the slot, the intake POST flips medication.active to false", async () => {
|
||||
const prisma = getPrismaClient();
|
||||
const today = new Date();
|
||||
const todayDate = new Date(
|
||||
Date.UTC(
|
||||
today.getUTCFullYear(),
|
||||
today.getUTCMonth(),
|
||||
today.getUTCDate(),
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
),
|
||||
);
|
||||
const todayDate = localCalendarMidnightUtc(today, "Europe/Berlin");
|
||||
|
||||
const med = await prisma.medication.create({
|
||||
data: {
|
||||
@@ -543,17 +553,7 @@ describe("one-shot lifecycle", () => {
|
||||
it("does NOT deactivate when the intake is skipped", async () => {
|
||||
const prisma = getPrismaClient();
|
||||
const today = new Date();
|
||||
const todayDate = new Date(
|
||||
Date.UTC(
|
||||
today.getUTCFullYear(),
|
||||
today.getUTCMonth(),
|
||||
today.getUTCDate(),
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
),
|
||||
);
|
||||
const todayDate = localCalendarMidnightUtc(today, "Europe/Berlin");
|
||||
|
||||
const med = await prisma.medication.create({
|
||||
data: {
|
||||
|
||||
Reference in new issue
Block a user