feat: add enable/disable toggle for chore scheduling in ScheduleModal
All checks were successful
Chore App Build, Test, and Push Docker Images / build-and-push (push) Successful in 2m39s
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.
This commit is contained in:
@@ -0,0 +1,129 @@
|
||||
// spec: e2e/plans/chore-scheduler.plan.md — Section 1: Schedule Modal Opening & Structure
|
||||
|
||||
import { test, expect } from '@playwright/test'
|
||||
import {
|
||||
createChild,
|
||||
createChoreTask,
|
||||
assignChore,
|
||||
deleteSchedule,
|
||||
choreCard,
|
||||
openChoreOptions,
|
||||
openScheduleModal,
|
||||
} from './helpers'
|
||||
|
||||
const CHILD_NAME = 'ScheduleModalChild'
|
||||
const CHORE_NAME = 'ScheduleModalChore'
|
||||
|
||||
test.describe('Schedule Modal — Opening & Structure', () => {
|
||||
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('1.1 Schedule option appears in kebab menu', async ({ page }) => {
|
||||
await page.goto(`/parent/${childId}`)
|
||||
const card = choreCard(page, CHORE_NAME)
|
||||
await card.waitFor()
|
||||
await openChoreOptions(page, card)
|
||||
await expect(page.getByRole('button', { name: 'Schedule' })).toBeVisible()
|
||||
})
|
||||
|
||||
test('1.2 Schedule modal opens with correct title and subtitle', async ({ page }) => {
|
||||
await page.goto(`/parent/${childId}`)
|
||||
const card = choreCard(page, CHORE_NAME)
|
||||
await card.waitFor()
|
||||
await openScheduleModal(page, card)
|
||||
await expect(page.locator('.modal-title')).toHaveText('Schedule Chore')
|
||||
await expect(page.locator('.modal-subtitle')).toHaveText(CHORE_NAME)
|
||||
})
|
||||
|
||||
test('1.3 Default state: Specific Days mode, no chips selected, toggle Enabled', async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto(`/parent/${childId}`)
|
||||
const card = choreCard(page, CHORE_NAME)
|
||||
await card.waitFor()
|
||||
await openScheduleModal(page, card)
|
||||
|
||||
// Specific Days mode button is active
|
||||
await expect(page.getByRole('button', { name: 'Specific Days' })).toHaveClass(/active/)
|
||||
await expect(page.getByRole('button', { name: 'Every X Days' })).not.toHaveClass(/active/)
|
||||
|
||||
// No day chips are active
|
||||
const chips = page.locator('.day-chips').getByRole('button')
|
||||
for (const chip of await chips.all()) {
|
||||
await expect(chip).not.toHaveClass(/active/)
|
||||
}
|
||||
|
||||
// Toggle is ON and shows "Enabled"
|
||||
await expect(page.getByRole('switch')).toHaveAttribute('aria-checked', 'true')
|
||||
await expect(page.locator('.toggle-label')).toHaveText('Enabled')
|
||||
})
|
||||
|
||||
test('1.4 Mode toggle switches between Specific Days and Every X Days', async ({ page }) => {
|
||||
await page.goto(`/parent/${childId}`)
|
||||
const card = choreCard(page, CHORE_NAME)
|
||||
await card.waitFor()
|
||||
await openScheduleModal(page, card)
|
||||
|
||||
// Switch to Every X Days
|
||||
await page.getByRole('button', { name: 'Every X Days' }).click()
|
||||
await expect(page.locator('.interval-form')).toBeVisible()
|
||||
await expect(page.locator('.days-form')).not.toBeVisible()
|
||||
|
||||
// Switch back to Specific Days
|
||||
await page.getByRole('button', { name: 'Specific Days' }).click()
|
||||
await expect(page.locator('.days-form')).toBeVisible()
|
||||
await expect(page.locator('.interval-form')).not.toBeVisible()
|
||||
})
|
||||
|
||||
test('1.5 Cancel closes the modal without saving', async ({ page }) => {
|
||||
await page.goto(`/parent/${childId}`)
|
||||
const card = choreCard(page, CHORE_NAME)
|
||||
await card.waitFor()
|
||||
await openScheduleModal(page, card)
|
||||
|
||||
// Select Monday chip
|
||||
await page.locator('.day-chips').getByRole('button', { name: 'Mo' }).click()
|
||||
await expect(page.locator('.day-chips').getByRole('button', { name: 'Mo' })).toHaveClass(
|
||||
/active/,
|
||||
)
|
||||
|
||||
// Cancel — modal closes
|
||||
await page.getByRole('button', { name: 'Cancel' }).click()
|
||||
await expect(page.locator('.modal-title')).not.toBeVisible()
|
||||
|
||||
// Navigate fresh to reset card ready-state, then reopen modal
|
||||
await page.goto(`/parent/${childId}`)
|
||||
await card.waitFor()
|
||||
await openScheduleModal(page, card)
|
||||
await expect(page.locator('.day-chips').getByRole('button', { name: 'Mo' })).not.toHaveClass(
|
||||
/active/,
|
||||
)
|
||||
})
|
||||
|
||||
test('1.6 Save is disabled when form is not dirty', async ({ page }) => {
|
||||
await page.goto(`/parent/${childId}`)
|
||||
const card = choreCard(page, CHORE_NAME)
|
||||
await card.waitFor()
|
||||
await openScheduleModal(page, card)
|
||||
|
||||
// Save button is disabled — no changes made
|
||||
await expect(page.getByRole('button', { name: 'Save' })).toBeDisabled()
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user