// spec: frontend/vue-app/e2e/plans/parent-item-management.plan.md // seed: e2e/seed.spec.ts import { test, expect } from '@playwright/test' test.describe('Penalty management', () => { test.describe.configure({ mode: 'serial' }) test.beforeEach(async ({ page }, testInfo) => { test.skip(testInfo.project.name === 'chromium-no-pin', 'Requires parent-authenticated mode') }) test('Create a new penalty (parent mode)', async ({ page }) => { const name = `No screen time ${Date.now()}` await page.goto('/parent/tasks/chores') await page.click('text=Penalties') await expect(page.locator('text=Penalties')).toBeVisible() await page.getByRole('button', { name: 'Create Penalty' }).click() await page.evaluate((n) => { const setVal = (sel, val) => { const el = document.querySelector(sel) if (el) { el.value = val el.dispatchEvent(new Event('input', { bubbles: true })) el.dispatchEvent(new Event('change', { bubbles: true })) } } setVal('#name', n) setVal('#points', '30') }, name) await expect(page.getByRole('button', { name: 'Create' })).toBeEnabled() await page.getByRole('button', { name: 'Create' }).click() await expect(page.locator(`text=${name}`)).toBeVisible() }) test('Edit an existing penalty', async ({ page }) => { const suffix = Date.now() const original = `No screen time ${suffix}` const updated = `No dessert ${suffix}` await page.goto('/parent/tasks/chores') await page.click('text=Penalties') // create the item to edit await page.getByRole('button', { name: 'Create Penalty' }).click() await page.evaluate((n) => { const setVal = (sel, val) => { const el = document.querySelector(sel) if (el) { el.value = val el.dispatchEvent(new Event('input', { bubbles: true })) el.dispatchEvent(new Event('change', { bubbles: true })) } } setVal('#name', n) setVal('#points', '30') }, original) await page.getByRole('button', { name: 'Create' }).click() await expect(page.locator(`text=${original}`)).toBeVisible() // open edit by clicking the row itself await page.click(`text=${original}`) // wait for the edit form to finish loading data from the API await expect(page.locator('#name')).toHaveValue(original) await page.evaluate((n) => { const setVal = (sel, val) => { const el = document.querySelector(sel) if (el) { el.value = val el.dispatchEvent(new Event('input', { bubbles: true })) el.dispatchEvent(new Event('change', { bubbles: true })) } } setVal('#name', n) setVal('#points', '20') }, updated) await expect(page.getByRole('button', { name: 'Save' })).toBeEnabled() await page.getByRole('button', { name: 'Save' }).click() await expect(page.locator(`text=${updated}`)).toBeVisible() }) test('Delete a penalty', async ({ page }) => { const name = `No dessert ${Date.now()}` await page.goto('/parent/tasks/chores') await page.click('text=Penalties') await page.getByRole('button', { name: 'Create Penalty' }).click() await page.evaluate((n) => { const setVal = (sel, val) => { const el = document.querySelector(sel) if (el) { el.value = val el.dispatchEvent(new Event('input', { bubbles: true })) el.dispatchEvent(new Event('change', { bubbles: true })) } } setVal('#name', n) setVal('#points', '20') }, name) await page.getByRole('button', { name: 'Create' }).click() await expect(page.locator(`text=${name}`)).toBeVisible() await page .locator(`text=${name}`) .locator('..') .getByRole('button', { name: 'Delete item' }) .click() await page.locator('button.btn-danger:has-text("Delete")').click() await expect(page.locator(`text=${name}`)).toHaveCount(0) }) })