diff --git a/apps/pwa/e2e/calendar.spec.ts b/apps/pwa/e2e/calendar.spec.ts index 94ba8eb..d364048 100644 --- a/apps/pwa/e2e/calendar.spec.ts +++ b/apps/pwa/e2e/calendar.spec.ts @@ -67,14 +67,19 @@ test.describe('Rule 5 — populated calendar state', () => { // The Schedule-X React adapter emits a div.sx-react-calendar-wrapper. // Prefer a stable locator: the class name is documented in apps/pwa/src/styles/index.css. // No semantic role exists for the widget wrapper, so CSS class is the documented fallback. + // NOTE: the wrapper renders on any successful auth — this proves the grid mounts, NOT that + // the seed reached the UI. The DB→UI proof is the separate "seeded event is rendered" test. const calendarGrid = page.locator('.sx-react-calendar-wrapper') await expect(calendarGrid).toBeVisible() }) - test('EmptyState "Nothing here" is NOT present when events are seeded', async ({ page }) => { - // CalendarShell renders EmptyState when the events query succeeds with zero occurrences. - // With the seeded event, EmptyState must not appear. Use toHaveCount(0) for strict absence. - await expect(page.getByText('Nothing here')).toHaveCount(0) + test('seeded event "Seeded Test Event" is rendered in the grid (DB→UI proof)', async ({ page }) => { + // The one assertion that actually proves the seeded row flows DB → API → query → grid. + // global-setup seeds a timed event titled 'Seeded Test Event' (noon today) on calendar 10. + // Schedule-X renders the event with its title text inside the grid. If the seed broke, the + // /api/events join regressed, or hydration dropped events, THIS fails (unlike a wrapper / + // dead-EmptyState check, which would stay green). Deep-review BL-01. + await expect(page.getByText('Seeded Test Event').first()).toBeVisible() }) test('no horizontal overflow on populated /calendar (Rule 2)', async ({ page }) => { diff --git a/apps/pwa/e2e/global-setup.ts b/apps/pwa/e2e/global-setup.ts index c4189b6..be0e13b 100644 --- a/apps/pwa/e2e/global-setup.ts +++ b/apps/pwa/e2e/global-setup.ts @@ -92,9 +92,17 @@ export default async function globalSetup(): Promise { ) // Seed one timed (not all-day) calendar event on shared calendar id=10. - // Uses a future dtstart_utc so the event is visible in the UI's default "upcoming" view. + // Anchor to NOON TODAY (UTC) — deliberately NOT "tomorrow" (deep-review BL-02): + // both device profiles are phone-width and render the month-agenda view of the + // CURRENT month. On the last day of a month "tomorrow" rolls into the next month + // and disappears from the rendered grid, making any "seeded event is visible" + // assertion date-fragile. Noon-today lands on today's local calendar date in every + // project timezone and is always inside the current-month view. const uid = 'e2e-seed-event-001' - const futureStart = new Date(Date.now() + 24 * 60 * 60 * 1000) // tomorrow UTC + const _now = new Date() + const futureStart = new Date( + Date.UTC(_now.getUTCFullYear(), _now.getUTCMonth(), _now.getUTCDate(), 12, 0, 0), + ) // MariaDB TIMESTAMP requires 'YYYY-MM-DD HH:MM:SS' format, not ISO 8601 with 'T'. const futureStartUtc = futureStart .toISOString()