// spec: e2e/plans/chore-scheduler.plan.md — Section 9: Interval Mode Anchor Date Logic import { test, expect } from '@playwright/test' import { createChild, createChoreTask, assignChore, setIntervalSchedule, choreCard, choreSection, todayISO, yesterdayISO, goToChildView, } from './helpers' const CHILD_NAME = 'IntervalAnchorChild' const CHORE_NAME = 'IntervalAnchorChore' test.describe('Schedule Interval Mode — Anchor Date Logic', () => { test.describe.configure({ mode: 'serial' }) let childId = '' let choreId = '' test.beforeAll(async ({ request }) => { childId = await createChild(request, CHILD_NAME) choreId = await createChoreTask(request, CHORE_NAME) await assignChore(request, childId, [choreId]) }) test.afterAll(async ({ request }) => { if (childId) await request.delete(`/api/child/${childId}`) if (choreId) await request.delete(`/api/task/${choreId}`) }) test('9.1 Interval every 1 day starting today — chore active today', async ({ page, request, }) => { await setIntervalSchedule(request, childId, choreId, 1, todayISO(), { hour: 23, minute: 59, }) // Parent mode: not grayed out await page.goto(`/parent/${childId}`) const parentCard = choreCard(page, CHORE_NAME) await parentCard.waitFor() await expect(parentCard).not.toHaveClass(/chore-inactive/) // Child mode: visible await goToChildView(page, childId) await expect(choreCard(page, CHORE_NAME)).toBeVisible() }) test('9.2 Interval every 2 days starting yesterday — chore NOT active today', async ({ page, request, }) => { // anchor=yesterday, interval=2: yesterday+2=tomorrow → today is skipped await setIntervalSchedule(request, childId, choreId, 2, yesterdayISO(), { hour: 23, minute: 59, }) // Parent mode: grayed out (not hitting today) await page.goto(`/parent/${childId}`) const parentCard = choreCard(page, CHORE_NAME) await parentCard.waitFor() await expect(parentCard).toHaveClass(/chore-inactive/) // Child mode: hidden (not scheduled for today) await goToChildView(page, childId) // Wait for list to finish loading — the chore should be filtered out await expect(choreSection(page).locator('.empty, .scroll-wrapper')).toBeVisible({ timeout: 10000, }) await expect( choreSection(page).locator('.item-card').filter({ hasText: CHORE_NAME }), ).toHaveCount(0) }) test('9.3 Interval every 2 days starting today — active today', async ({ page, request }) => { // anchor=today, interval=2: diffDays=0, 0%2=0 → hits today await setIntervalSchedule(request, childId, choreId, 2, todayISO(), { hour: 23, minute: 59, }) // Parent mode: not grayed out await page.goto(`/parent/${childId}`) const parentCard = choreCard(page, CHORE_NAME) await parentCard.waitFor() await expect(parentCard).not.toHaveClass(/chore-inactive/) // Child mode: visible await goToChildView(page, childId) await expect(choreCard(page, CHORE_NAME)).toBeVisible() }) test('9.4 Interval "Anytime" deadline — no "Due by" label', async ({ page, request }) => { await setIntervalSchedule(request, childId, choreId, 1, todayISO(), { hasDeadline: false, }) await page.goto(`/parent/${childId}`) const card = choreCard(page, CHORE_NAME) await card.waitFor() // Anytime = no due label await expect(card.locator('.due-label')).not.toBeVisible() }) })