All checks were successful
Chore App Build, Test, and Push Docker Images / build-and-push (push) Successful in 2m39s
- Introduced a toggle button to enable or disable chores in the scheduler. - The toggle will be available in both types of schedulers. - Added UI design proposal and considerations for mobile dimensions. - Included E2E tests to ensure toggle state persistence and correct behavior in child view.
129 lines
4.6 KiB
TypeScript
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()
|
|
})
|
|
})
|