Refactored frontend directory
Some checks failed
Chore App Build, Test, and Push Docker Images / build-and-push (push) Failing after 2m46s

This commit is contained in:
2026-04-25 00:40:15 -04:00
parent db846f4e31
commit 127378797c
263 changed files with 88 additions and 79 deletions

View File

@@ -0,0 +1,181 @@
// spec: e2e/plans/user-profile.plan.md
import { test, expect, type APIRequestContext } from '@playwright/test'
import { E2E_PIN } from '../../e2e-constants'
const BACKEND = 'http://localhost:5000'
const NEW_PIN = '5678'
async function setPinDirectly(request: APIRequestContext, pin: string): Promise<void> {
// Request a new code, retrieve it via test endpoint, verify it, then set the pin
await request.post(`${BACKEND}/user/request-pin-setup`)
const codeRes = await request.get(`${BACKEND}/user/e2e-get-pin-code`)
const { code } = await codeRes.json()
await request.post(`${BACKEND}/user/verify-pin-setup`, { data: { code } })
await request.post(`${BACKEND}/user/set-pin`, { data: { pin } })
}
test.describe('User Profile Change Parent PIN', () => {
test.describe.configure({ mode: 'serial' })
test.afterAll(async ({ request }) => {
// Restore original PIN so subsequent test runs start fresh
await setPinDirectly(request, E2E_PIN)
})
test('Change Parent PIN link navigates to PIN setup page', async ({ page }) => {
await page.goto('/parent/profile')
await page.getByRole('button', { name: 'Change Parent PIN' }).click()
await expect(page).toHaveURL(/\/parent\/pin-setup/)
await expect(page.getByRole('heading', { name: 'Set up your Parent PIN' })).toBeVisible()
})
test('Back from PIN setup page returns to profile', async ({ page }) => {
// Navigate from the profile page so browser history exists
await page.goto('/parent/profile')
await page.getByRole('button', { name: 'Change Parent PIN' }).click()
await expect(page).toHaveURL(/\/parent\/pin-setup/)
await page.goBack()
await expect(page).toHaveURL(/\/parent\/profile/)
})
test('Send Verification Code advances to step 2', async ({ page }) => {
await page.goto('/parent/pin-setup')
await page.getByRole('button', { name: 'Send Verification Code' }).click()
await expect(page.getByRole('heading', { name: 'Enter Verification Code' })).toBeVisible()
const codeInput = page.getByPlaceholder('6-digit code')
await expect(codeInput).toBeVisible()
// Verify Code is disabled while input is empty
await expect(page.getByRole('button', { name: 'Verify Code' })).toBeDisabled()
})
test('Resend Code button appears after delay', async ({ page }) => {
await page.goto('/parent/pin-setup')
await page.getByRole('button', { name: 'Send Verification Code' }).click()
await expect(page.getByRole('heading', { name: 'Enter Verification Code' })).toBeVisible()
// According to the component, resend appears after 10 seconds
await expect(page.getByRole('button', { name: 'Resend Code' })).toBeVisible({ timeout: 15000 })
})
test('Invalid code shows error', async ({ page }) => {
await page.goto('/parent/pin-setup')
await page.getByRole('button', { name: 'Send Verification Code' }).click()
await expect(page.getByRole('heading', { name: 'Enter Verification Code' })).toBeVisible()
await page.getByPlaceholder('6-digit code').fill('ZZZZZZ')
await page.getByRole('button', { name: 'Verify Code' }).click()
await expect(page.getByText(/invalid code/i)).toBeVisible()
})
test('Valid code advances to step 3 (Create PIN)', async ({ page, request }) => {
await page.goto('/parent/pin-setup')
await page.getByRole('button', { name: 'Send Verification Code' }).click()
await expect(page.getByRole('heading', { name: 'Enter Verification Code' })).toBeVisible()
// Retrieve the code via the test-only endpoint
const codeRes = await request.get(`${BACKEND}/user/e2e-get-pin-code`)
const { code } = await codeRes.json()
await page.getByPlaceholder('6-digit code').fill(code)
await page.getByRole('button', { name: 'Verify Code' }).click()
await expect(page.getByRole('heading', { name: 'Create Parent PIN' })).toBeVisible()
await expect(page.getByPlaceholder('New PIN')).toBeVisible()
await expect(page.getByPlaceholder('Confirm PIN')).toBeVisible()
await expect(page.getByRole('button', { name: 'Set PIN' })).toBeDisabled()
})
test('Set PIN disabled when PINs do not match', async ({ page, request }) => {
await page.goto('/parent/pin-setup')
await page.getByRole('button', { name: 'Send Verification Code' }).click()
await expect(page.getByRole('heading', { name: 'Enter Verification Code' })).toBeVisible()
const codeRes = await request.get(`${BACKEND}/user/e2e-get-pin-code`)
const { code } = await codeRes.json()
await page.getByPlaceholder('6-digit code').fill(code)
await page.getByRole('button', { name: 'Verify Code' }).click()
await expect(page.getByRole('heading', { name: 'Create Parent PIN' })).toBeVisible()
await page.getByPlaceholder('New PIN').fill('1111')
await page.getByPlaceholder('Confirm PIN').fill('2222')
await expect(page.getByRole('button', { name: 'Set PIN' })).toBeDisabled()
})
test('Set PIN disabled for fewer than 4 digits', async ({ page, request }) => {
await page.goto('/parent/pin-setup')
await page.getByRole('button', { name: 'Send Verification Code' }).click()
await expect(page.getByRole('heading', { name: 'Enter Verification Code' })).toBeVisible()
const codeRes = await request.get(`${BACKEND}/user/e2e-get-pin-code`)
const { code } = await codeRes.json()
await page.getByPlaceholder('6-digit code').fill(code)
await page.getByRole('button', { name: 'Verify Code' }).click()
await expect(page.getByRole('heading', { name: 'Create Parent PIN' })).toBeVisible()
await page.getByPlaceholder('New PIN').fill('12')
await page.getByPlaceholder('Confirm PIN').fill('12')
await expect(page.getByRole('button', { name: 'Set PIN' })).toBeDisabled()
})
test('Set PIN succeeds with matching 4-digit PIN shows success step', async ({
page,
request,
}) => {
await page.goto('/parent/pin-setup')
await page.getByRole('button', { name: 'Send Verification Code' }).click()
await expect(page.getByRole('heading', { name: 'Enter Verification Code' })).toBeVisible()
const codeRes = await request.get(`${BACKEND}/user/e2e-get-pin-code`)
const { code } = await codeRes.json()
await page.getByPlaceholder('6-digit code').fill(code)
await page.getByRole('button', { name: 'Verify Code' }).click()
await expect(page.getByRole('heading', { name: 'Create Parent PIN' })).toBeVisible()
await page.getByPlaceholder('New PIN').fill(NEW_PIN)
await page.getByPlaceholder('Confirm PIN').fill(NEW_PIN)
await expect(page.getByRole('button', { name: 'Set PIN' })).toBeEnabled()
await page.getByRole('button', { name: 'Set PIN' }).click()
await expect(page.getByRole('heading', { name: 'Parent PIN Set!' })).toBeVisible()
await expect(page.getByRole('button', { name: 'Back', exact: true })).toBeVisible()
})
test('Back from success step exits parent mode and goes to child selector', async ({
page,
request,
}) => {
await page.goto('/parent/pin-setup')
await page.getByRole('button', { name: 'Send Verification Code' }).click()
await expect(page.getByRole('heading', { name: 'Enter Verification Code' })).toBeVisible()
const codeRes = await request.get(`${BACKEND}/user/e2e-get-pin-code`)
const { code } = await codeRes.json()
await page.getByPlaceholder('6-digit code').fill(code)
await page.getByRole('button', { name: 'Verify Code' }).click()
await expect(page.getByRole('heading', { name: 'Create Parent PIN' })).toBeVisible()
await page.getByPlaceholder('New PIN').fill(NEW_PIN)
await page.getByPlaceholder('Confirm PIN').fill(NEW_PIN)
await page.getByRole('button', { name: 'Set PIN' }).click()
await expect(page.getByRole('heading', { name: 'Parent PIN Set!' })).toBeVisible()
await page.getByRole('button', { name: 'Back', exact: true }).click()
await expect(page).toHaveURL(/\/child(\/|$)/)
// Parent mode exited "Parent login" button visible instead of parent menu
await expect(page.getByRole('button', { name: 'Parent login' })).toBeVisible()
})
})