// spec: e2e/plans/chore-scheduler.plan.md — Section 4: Schedule Enable/Disable Toggle import { test, expect } from '@playwright/test' import { createChild, createChoreTask, assignChore, deleteSchedule, setDaysSchedule, choreCard, openScheduleModal, todayDayIndex, nonTodayDayIndex, goToChildView, } from './helpers' const CHILD_NAME = 'ScheduleToggleChild' const CHORE_NAME = 'ScheduleToggleChore' test.describe('Schedule Enable/Disable Toggle', () => { 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.beforeEach(async ({ request }) => { await deleteSchedule(request, childId, choreId) }) test('4.1 Toggle row is visible in the schedule modal', async ({ page, request }) => { // Seed a schedule so the modal has something to show await setDaysSchedule(request, childId, choreId, [nonTodayDayIndex()]) await page.goto(`/parent/${childId}`) const card = choreCard(page, CHORE_NAME) await card.waitFor() await openScheduleModal(page, card) await expect(page.locator('.schedule-toggle-row')).toBeVisible() await expect(page.getByRole('switch')).toBeVisible() await expect(page.locator('.toggle-label')).toBeVisible() }) test('4.2 Toggling OFF shows "Paused" label and dims the form body', async ({ page, request, }) => { await setDaysSchedule(request, childId, choreId, [nonTodayDayIndex()]) await page.goto(`/parent/${childId}`) const card = choreCard(page, CHORE_NAME) await card.waitFor() await openScheduleModal(page, card) // Toggle is ON initially await expect(page.getByRole('switch')).toHaveAttribute('aria-checked', 'true') // Toggle OFF await page.getByRole('switch').click() await expect(page.getByRole('switch')).toHaveAttribute('aria-checked', 'false') await expect(page.locator('.toggle-label')).toHaveText('Paused') // Form body dims await expect(page.locator('.schedule-body')).toHaveClass(/disabled/) // Cancel/Save buttons remain interactive await expect(page.getByRole('button', { name: 'Cancel' })).toBeEnabled() }) test('4.3 Toggling ON restores "Enabled" label and form body', async ({ page, request }) => { await setDaysSchedule(request, childId, choreId, [nonTodayDayIndex()]) await page.goto(`/parent/${childId}`) const card = choreCard(page, CHORE_NAME) await card.waitFor() await openScheduleModal(page, card) // Toggle OFF then back ON await page.getByRole('switch').click() await expect(page.locator('.toggle-label')).toHaveText('Paused') await page.getByRole('switch').click() await expect(page.getByRole('switch')).toHaveAttribute('aria-checked', 'true') await expect(page.locator('.toggle-label')).toHaveText('Enabled') await expect(page.locator('.schedule-body')).not.toHaveClass(/disabled/) }) test('4.4 Save paused state — persists on reopen', async ({ page, request }) => { await setDaysSchedule(request, childId, choreId, [nonTodayDayIndex()]) await page.goto(`/parent/${childId}`) const card = choreCard(page, CHORE_NAME) await card.waitFor() await openScheduleModal(page, card) // Toggle OFF and save await page.getByRole('switch').click() await expect(page.locator('.toggle-label')).toHaveText('Paused') await page.getByRole('button', { name: 'Save' }).click() await expect(page.locator('.modal-title')).not.toBeVisible() // Navigate fresh to reset card ready-state, then reopen to verify await page.goto(`/parent/${childId}`) await card.waitFor() await openScheduleModal(page, card) await expect(page.getByRole('switch')).toHaveAttribute('aria-checked', 'false') await expect(page.locator('.toggle-label')).toHaveText('Paused') await expect(page.locator('.schedule-body')).toHaveClass(/disabled/) }) test('4.5 Dirty detection — toggling enabled state enables/disables Save', async ({ page, request, }) => { await setDaysSchedule(request, childId, choreId, [nonTodayDayIndex()]) await page.goto(`/parent/${childId}`) const card = choreCard(page, CHORE_NAME) await card.waitFor() await openScheduleModal(page, card) // Save is disabled initially await expect(page.getByRole('button', { name: 'Save' })).toBeDisabled() // Toggle OFF → dirty await page.getByRole('switch').click() await expect(page.getByRole('button', { name: 'Save' })).toBeEnabled() // Toggle back ON → not dirty again await page.getByRole('switch').click() await expect(page.getByRole('button', { name: 'Save' })).toBeDisabled() }) test('4.6 Paused schedule in parent mode — chore is visible and not grayed out', async ({ page, request, }) => { // Schedule for a non-today weekday, but paused (enabled=false) await setDaysSchedule(request, childId, choreId, [nonTodayDayIndex()], { enabled: false }) await page.goto(`/parent/${childId}`) const card = choreCard(page, CHORE_NAME) await card.waitFor() // Chore is visible await expect(card).toBeVisible() // Paused = acts like unscheduled = not grayed out await expect(card).not.toHaveClass(/chore-inactive/) }) test('4.7 Paused schedule in child mode — chore is visible', async ({ page, request }) => { // Non-today schedule, paused await setDaysSchedule(request, childId, choreId, [nonTodayDayIndex()], { enabled: false }) await goToChildView(page, childId) const card = choreCard(page, CHORE_NAME) // Paused = isScheduledToday returns true → chore is visible in child mode await expect(card).toBeVisible() }) test('4.8 Paused schedule shows no "Due by" label', async ({ page, request }) => { // Schedule for today with a deadline, but paused await setDaysSchedule(request, childId, choreId, [todayDayIndex()], { hour: 23, minute: 59, enabled: false, }) await page.goto(`/parent/${childId}`) const card = choreCard(page, CHORE_NAME) await card.waitFor() // Paused = getDueTimeToday returns null → no "Due by" label await expect(card.locator('.due-label')).not.toBeVisible() }) })