Files
chore/frontend/e2e/mode_parent/chore-scheduler/child-card-states.spec.ts
Ryan Kegel 127378797c
Some checks failed
Chore App Build, Test, and Push Docker Images / build-and-push (push) Failing after 2m46s
Refactored frontend directory
2026-04-25 00:40:15 -04:00

129 lines
4.6 KiB
TypeScript

// spec: e2e/plans/chore-scheduler.plan.md — Section 6: Child Mode Chore Visibility & States
import { test, expect } from '@playwright/test'
import {
createChild,
createChoreTask,
assignChore,
setDaysSchedule,
choreCard,
choreSection,
todayDayIndex,
nonTodayDayIndex,
goToChildView,
} from './helpers'
const CHILD_NAME = 'ChildCardChild'
const CHILD_ALWAYS = 'ChildAlwaysChore'
const CHILD_TODAY = 'ChildTodayChore'
const CHILD_NOT_TODAY = 'ChildNotTodayChore'
const CHILD_EXPIRED = 'ChildExpiredChore'
const CHILD_ANYTIME = 'ChildAnytimeChore'
test.describe('Child Mode — Chore Visibility and Schedule States', () => {
test.describe.configure({ mode: 'serial' })
let childId = ''
let alwaysId = ''
let todayId = ''
let notTodayId = ''
let expiredId = ''
let anytimeId = ''
test.beforeAll(async ({ request }) => {
childId = await createChild(request, CHILD_NAME)
alwaysId = await createChoreTask(request, CHILD_ALWAYS)
todayId = await createChoreTask(request, CHILD_TODAY)
notTodayId = await createChoreTask(request, CHILD_NOT_TODAY)
expiredId = await createChoreTask(request, CHILD_EXPIRED)
anytimeId = await createChoreTask(request, CHILD_ANYTIME)
await assignChore(request, childId, [alwaysId, todayId, notTodayId, expiredId, anytimeId])
const today = todayDayIndex()
const nonToday = nonTodayDayIndex()
// ChildTodayChore: scheduled for today, deadline 23:59
await setDaysSchedule(request, childId, todayId, [today], { hour: 23, minute: 59 })
// ChildNotTodayChore: scheduled for a non-today day
await setDaysSchedule(request, childId, notTodayId, [nonToday], { hour: 8, minute: 0 })
// ChildExpiredChore: scheduled for today, deadline 00:01 (guaranteed expired)
await setDaysSchedule(request, childId, expiredId, [today], { hour: 0, minute: 1 })
// ChildAnytimeChore: scheduled for today, no deadline
await setDaysSchedule(request, childId, anytimeId, [today], { hasDeadline: false })
// ChildAlwaysChore: no schedule
})
test.afterAll(async ({ request }) => {
if (childId) await request.delete(`/api/child/${childId}`)
for (const id of [alwaysId, todayId, notTodayId, expiredId, anytimeId]) {
if (id) await request.delete(`/api/task/${id}`)
}
})
test('6.1 Chore with no schedule — visible normally in child mode', async ({ page }) => {
await goToChildView(page, childId)
const card = choreCard(page, CHILD_ALWAYS)
await expect(card).toBeVisible()
await expect(card).not.toHaveClass(/chore-inactive/)
})
test('6.2 Chore scheduled for today — visible with "Due by" label', async ({ page }) => {
await goToChildView(page, childId)
const card = choreCard(page, CHILD_TODAY)
await expect(card).toBeVisible()
await expect(card).not.toHaveClass(/chore-inactive/)
await expect(card.locator('.due-label')).toHaveText('Due by 11:59 PM')
})
test('6.3 Chore not scheduled for today — HIDDEN in child mode', async ({ page }) => {
await goToChildView(page, childId)
// Wait for the chores section to fully load (uses other cards as anchor)
const alwaysCard = choreCard(page, CHILD_ALWAYS)
await expect(alwaysCard).toBeVisible()
// Off-day chore must not appear at all
await expect(
choreSection(page).locator('.item-card').filter({ hasText: CHILD_NOT_TODAY }),
).toHaveCount(0)
})
test('6.4 Chore with expired deadline — grayed out with TOO LATE badge (not hidden)', async ({
page,
}) => {
await goToChildView(page, childId)
const card = choreCard(page, CHILD_EXPIRED)
// Expired chore is still visible (was scheduled for today)
await expect(card).toBeVisible()
await expect(card).toHaveClass(/chore-inactive/)
await expect(card.getByText('TOO LATE')).toBeVisible()
})
test('6.5 Chore with "Anytime" — visible, no badge, no "Due by"', async ({ page }) => {
await goToChildView(page, childId)
const card = choreCard(page, CHILD_ANYTIME)
await expect(card).toBeVisible()
await expect(card).not.toHaveClass(/chore-inactive/)
await expect(card.locator('.due-label')).not.toBeVisible()
await expect(card.getByText('TOO LATE')).not.toBeVisible()
})
test('6.6 No kebab menu or schedule controls in child mode', async ({ page }) => {
await goToChildView(page, childId)
const card = choreCard(page, CHILD_TODAY)
await expect(card).toBeVisible()
// Click the card — no Options button should appear
await card.click()
await page.waitForTimeout(500)
await expect(card.getByRole('button', { name: 'Options' })).not.toBeVisible()
await expect(page.getByRole('button', { name: 'Schedule' })).not.toBeVisible()
})
})