feat: implement routines feature for child and parent modes
All checks were successful
Chore App Build, Test, and Push Docker Images / build-and-push (push) Successful in 2m23s
All checks were successful
Chore App Build, Test, and Push Docker Images / build-and-push (push) Successful in 2m23s
- Added backend models for routines, routine items, and schedules. - Created API endpoints for managing routines and their items. - Implemented frontend components for routine creation, detail view, and assignment. - Integrated routines into child view with a scrolling list and approval workflow. - Added push notifications for routine confirmations and pending approvals. - Refactored existing components to accommodate new routines functionality. - Updated tests to cover new routines feature and ensure proper functionality.
This commit is contained in:
@@ -32,6 +32,13 @@ async function restoreProfile(request: APIRequestContext, profile: ProfileData):
|
||||
})
|
||||
}
|
||||
|
||||
/** Navigate to /parent/profile and wait for the form to finish loading. */
|
||||
async function gotoProfile(page: import('@playwright/test').Page): Promise<void> {
|
||||
await page.goto('/parent/profile')
|
||||
// EntityEditForm hides the form behind v-if while loading=true; wait for it to render.
|
||||
await expect(page.getByLabel('First Name')).toBeVisible({ timeout: 10000 })
|
||||
}
|
||||
|
||||
test.describe('User Profile – editing', () => {
|
||||
test.describe.configure({ mode: 'serial' })
|
||||
|
||||
@@ -46,7 +53,7 @@ test.describe('User Profile – editing', () => {
|
||||
})
|
||||
|
||||
test('Profile page loads with correct data', async ({ page }) => {
|
||||
await page.goto('/parent/profile')
|
||||
await gotoProfile(page)
|
||||
|
||||
await expect(page.getByRole('heading', { name: 'User Profile' })).toBeVisible()
|
||||
await expect(page.getByLabel('First Name')).toHaveValue(E2E_FIRST_NAME)
|
||||
@@ -68,13 +75,13 @@ test.describe('User Profile – editing', () => {
|
||||
})
|
||||
|
||||
test('Save is disabled when form is clean (not dirty)', async ({ page }) => {
|
||||
await page.goto('/parent/profile')
|
||||
await gotoProfile(page)
|
||||
|
||||
await expect(page.getByRole('button', { name: 'Save' })).toBeDisabled()
|
||||
})
|
||||
|
||||
test('Save is disabled when First Name is empty', async ({ page }) => {
|
||||
await page.goto('/parent/profile')
|
||||
await gotoProfile(page)
|
||||
|
||||
await page.getByLabel('First Name').fill('')
|
||||
await page.getByLabel('First Name').blur()
|
||||
@@ -83,7 +90,7 @@ test.describe('User Profile – editing', () => {
|
||||
})
|
||||
|
||||
test('Save is disabled when Last Name is empty', async ({ page }) => {
|
||||
await page.goto('/parent/profile')
|
||||
await gotoProfile(page)
|
||||
|
||||
await page.getByLabel('Last Name').fill('')
|
||||
await page.getByLabel('Last Name').blur()
|
||||
@@ -92,7 +99,7 @@ test.describe('User Profile – editing', () => {
|
||||
})
|
||||
|
||||
test('Save is disabled when both name fields are empty', async ({ page }) => {
|
||||
await page.goto('/parent/profile')
|
||||
await gotoProfile(page)
|
||||
|
||||
await page.getByLabel('First Name').fill('')
|
||||
await page.getByLabel('Last Name').fill('')
|
||||
@@ -101,7 +108,7 @@ test.describe('User Profile – editing', () => {
|
||||
})
|
||||
|
||||
test('Save enables when a name is changed', async ({ page }) => {
|
||||
await page.goto('/parent/profile')
|
||||
await gotoProfile(page)
|
||||
|
||||
await page.getByLabel('First Name').fill('UpdatedE2E')
|
||||
|
||||
@@ -109,7 +116,7 @@ test.describe('User Profile – editing', () => {
|
||||
})
|
||||
|
||||
test('Save persists name changes and shows confirmation modal', async ({ page }) => {
|
||||
await page.goto('/parent/profile')
|
||||
await gotoProfile(page)
|
||||
|
||||
await page.getByLabel('First Name').fill('UpdatedE2E')
|
||||
await page.getByLabel('Last Name').fill('UpdatedTester')
|
||||
@@ -121,25 +128,25 @@ test.describe('User Profile – editing', () => {
|
||||
await dialog.getByRole('button', { name: 'OK' }).click()
|
||||
|
||||
// OK navigates back; go back to profile to verify persistence
|
||||
await page.goto('/parent/profile')
|
||||
await gotoProfile(page)
|
||||
await expect(page.getByLabel('First Name')).toHaveValue('UpdatedE2E')
|
||||
await expect(page.getByLabel('Last Name')).toHaveValue('UpdatedTester')
|
||||
})
|
||||
|
||||
test('Cancel discards unsaved changes', async ({ page }) => {
|
||||
await page.goto('/parent/profile')
|
||||
await gotoProfile(page)
|
||||
|
||||
await page.getByLabel('First Name').fill('Discarded')
|
||||
|
||||
await page.getByRole('button', { name: 'Cancel' }).click()
|
||||
|
||||
// Navigate back to verify no changes were saved
|
||||
await page.goto('/parent/profile')
|
||||
await gotoProfile(page)
|
||||
await expect(page.getByLabel('First Name')).toHaveValue(E2E_FIRST_NAME)
|
||||
})
|
||||
|
||||
test('Email field is read-only', async ({ page }) => {
|
||||
await page.goto('/parent/profile')
|
||||
await gotoProfile(page)
|
||||
|
||||
const emailInput = page.locator('#email')
|
||||
await expect(emailInput).toBeDisabled()
|
||||
@@ -147,7 +154,7 @@ test.describe('User Profile – editing', () => {
|
||||
})
|
||||
|
||||
test('Change profile image (built-in)', async ({ page }) => {
|
||||
await page.goto('/parent/profile')
|
||||
await gotoProfile(page)
|
||||
|
||||
// Wait for images to load
|
||||
await page.waitForSelector('.selectable-image')
|
||||
@@ -181,7 +188,7 @@ test.describe('User Profile – editing', () => {
|
||||
await page.locator('.modal-dialog').getByRole('button', { name: 'OK' }).click()
|
||||
|
||||
// Re-visit and confirm selection persists
|
||||
await page.goto('/parent/profile')
|
||||
await gotoProfile(page)
|
||||
await page.waitForSelector('.selectable-image')
|
||||
const selectedSrc = await page.locator('.selectable-image.selected').getAttribute('src')
|
||||
expect(selectedSrc).toBeTruthy()
|
||||
@@ -191,7 +198,7 @@ test.describe('User Profile – editing', () => {
|
||||
})
|
||||
|
||||
test('Upload a custom profile image', async ({ page }) => {
|
||||
await page.goto('/parent/profile')
|
||||
await gotoProfile(page)
|
||||
|
||||
await page.waitForSelector('.selectable-image')
|
||||
|
||||
@@ -214,7 +221,7 @@ test.describe('User Profile – editing', () => {
|
||||
})
|
||||
|
||||
test('Change Password shows email-sent modal', async ({ page }) => {
|
||||
await page.goto('/parent/profile')
|
||||
await gotoProfile(page)
|
||||
|
||||
await page.getByRole('button', { name: 'Change Password' }).click()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user