import { test, expect } from './fixtures'; import { randomUUID } from 'crypto'; import { generateId } from '../src/utils/uuid'; // Helper from plan-from-session test.describe('II. Workout Management', () => { // Helper functions async function loginAndSetup(page: any, createUniqueUser: any) { const user = await createUniqueUser(); await page.goto('/'); await page.getByLabel('Email').fill(user.email); await page.getByLabel('Password').fill(user.password); await page.getByRole('button', { name: 'Login' }).click(); try { const heading = page.getByRole('heading', { name: /Change Password/i }); const initAcc = page.getByRole('heading', { name: /Setup Your Account/i }); const dashboard = page.getByText('Free Workout'); await expect(heading.or(initAcc).or(dashboard)).toBeVisible({ timeout: 5000 }); if (await heading.isVisible()) { await page.getByLabel('New Password').fill('StrongNewPass123!'); await page.getByRole('button', { name: /Save|Change/i }).click(); await expect(initAcc.or(dashboard)).toBeVisible(); } if (await initAcc.isVisible()) { await page.getByRole('button', { name: /Get Started/i }).click(); await expect(dashboard).toBeVisible(); } } catch (e) { // Login might already be done or dashboard loaded fast } return user; } test.describe('A. Workout Plans', () => { test('2.1 A. Workout Plans - Create New Plan', async ({ page, createUniqueUser, request }) => { const user = await loginAndSetup(page, createUniqueUser); // Seed exercise const seedResp = await request.post('/api/exercises', { data: { name: 'Test Sq', type: 'STRENGTH' }, headers: { 'Authorization': `Bearer ${user.token}` } }); expect(seedResp.ok()).toBeTruthy(); await page.reload(); await page.getByRole('button', { name: 'Plans' }).first().click(); await page.getByRole('button', { name: 'Create Plan' }).click(); await page.getByRole('button', { name: 'Create Plan Manually' }).click(); await expect(page.getByLabel(/Name/i)).toBeVisible({ timeout: 10000 }); await page.getByLabel(`Name`).fill('My New Strength Plan'); await page.getByLabel(`Preparation`).fill('Focus on compound lifts'); await page.getByRole('button', { name: 'Add Exercise' }).click(); await expect(page.getByRole('heading', { name: 'Select Exercise' })).toBeVisible(); await page.getByText('Test Sq').click(); await page.getByRole('button', { name: 'Save' }).click(); await expect(page.getByText('My New Strength Plan')).toBeVisible(); await expect(page.getByText('Focus on compound lifts')).toBeVisible(); }); test('2.2 A. Workout Plans - Edit Existing Plan', async ({ page, createUniqueUser, request }) => { const user = await loginAndSetup(page, createUniqueUser); const seedResp = await request.post('/api/plans', { data: { id: randomUUID(), name: 'Original Plan', description: 'Original Description', steps: [] }, headers: { 'Authorization': `Bearer ${user.token}` } }); expect(seedResp.ok()).toBeTruthy(); await page.reload(); await page.getByRole('button', { name: 'Plans' }).first().click(); await expect(page.getByText('Original Plan')).toBeVisible(); const card = page.locator('div') .filter({ hasText: 'Original Plan' }) .filter({ has: page.getByRole('button', { name: 'Edit Plan' }) }) .last(); await card.getByRole('button', { name: 'Edit Plan' }).click(); await page.getByLabel(/Name/i).fill('Updated Plan Name'); await page.getByRole('button', { name: 'Save' }).click(); await expect(page.getByText('Updated Plan Name')).toBeVisible(); await expect(page.getByText('Original Plan')).not.toBeVisible(); }); test('2.3 A. Workout Plans - Delete Plan', async ({ page, createUniqueUser, request }) => { const user = await loginAndSetup(page, createUniqueUser); const resp = await request.post('/api/plans', { data: { id: randomUUID(), name: 'Plan To Delete', description: 'Delete me', steps: [] }, headers: { 'Authorization': `Bearer ${user.token}` } }); expect(resp.ok()).toBeTruthy(); await page.reload(); await page.getByRole('button', { name: 'Plans' }).first().click(); page.on('dialog', dialog => dialog.accept()); const card = page.locator('div') .filter({ hasText: 'Plan To Delete' }) .filter({ has: page.getByRole('button', { name: 'Delete Plan' }) }) .last(); await card.getByRole('button', { name: 'Delete Plan' }).click(); await expect(page.getByText('Plan To Delete')).not.toBeVisible(); }); test('2.4 A. Workout Plans - Reorder Exercises', async ({ page, createUniqueUser, request }) => { page.on('console', msg => console.log('PAGE LOG:', msg.text())); const user = await loginAndSetup(page, createUniqueUser); // Need exercises const ex1Id = randomUUID(); const ex2Id = randomUUID(); await request.post('/api/exercises', { data: { id: ex1Id, name: 'Ex One', type: 'STRENGTH' }, headers: { 'Authorization': `Bearer ${user.token}` } }); await request.post('/api/exercises', { data: { id: ex2Id, name: 'Ex Two', type: 'STRENGTH' }, headers: { 'Authorization': `Bearer ${user.token}` } }); const planId = randomUUID(); await request.post('/api/plans', { data: { id: planId, name: 'Reorder Plan', description: 'Testing reorder', steps: [ { exerciseId: ex1Id, isWeighted: false }, { exerciseId: ex2Id, isWeighted: false } ] }, headers: { 'Authorization': `Bearer ${user.token}` } }); await page.reload(); await page.getByRole('button', { name: 'Plans' }).first().click(); const card = page.locator('div') .filter({ hasText: 'Reorder Plan' }) .filter({ has: page.getByRole('button', { name: 'Edit Plan' }) }) .last(); await card.getByRole('button', { name: 'Edit Plan' }).click(); // Verify order: Ex One then Ex Two const items = page.getByTestId('plan-exercise-item'); await expect(items.first()).toContainText('Ex One'); await expect(items.nth(1)).toContainText('Ex Two'); // Drag and drop to reorder manually (dnd-kit needs steps) const sourceHandle = items.first().locator('.lucide-grip-vertical'); const targetHandle = items.nth(1).locator('.lucide-grip-vertical'); const sourceBox = await sourceHandle.boundingBox(); const targetBox = await targetHandle.boundingBox(); if (sourceBox && targetBox) { await page.mouse.move(sourceBox.x + sourceBox.width / 2, sourceBox.y + sourceBox.height / 2); await page.mouse.down(); await page.mouse.move(targetBox.x + targetBox.width / 2, targetBox.y + targetBox.height / 2, { steps: 20 }); await page.mouse.up(); } // Verify new order: Ex Two then Ex One await expect(items.first()).toContainText('Ex Two'); await expect(items.nth(1)).toContainText('Ex One'); await page.getByRole('button', { name: 'Save' }).click(); await page.waitForTimeout(1000); await page.reload(); await page.getByRole('button', { name: 'Plans' }).first().click(); const cardRevisit = page.locator('div') .filter({ hasText: 'Reorder Plan' }) .filter({ has: page.getByRole('button', { name: 'Edit Plan' }) }) .last(); await cardRevisit.getByRole('button', { name: 'Edit Plan' }).click(); await expect(page.getByTestId('plan-exercise-item').first()).toContainText('Ex Two'); await expect(page.getByTestId('plan-exercise-item').last()).toContainText('Ex One'); }); test('2.5 A. Workout Plans - Start Session from Plan', async ({ page, createUniqueUser, request }) => { const user = await loginAndSetup(page, createUniqueUser); const resp = await request.post('/api/plans', { data: { id: randomUUID(), name: 'Startable Plan', description: 'Ready to go', steps: [] }, headers: { 'Authorization': `Bearer ${user.token}` } }); expect(resp.ok()).toBeTruthy(); await page.reload(); await page.getByRole('button', { name: 'Plans' }).first().click(); const card = page.locator('div') .filter({ hasText: 'Startable Plan' }) .filter({ has: page.getByRole('button', { name: 'Start' }) }) .last(); await card.getByRole('button', { name: 'Start' }).click(); const modal = page.locator('.fixed.inset-0.z-50'); await expect(modal).toBeVisible(); await expect(modal.getByText('Ready to go')).toBeVisible(); await modal.getByRole('button', { name: 'Start' }).click(); await expect(page.getByText('Startable Plan', { exact: false })).toBeVisible(); await expect(page.getByRole('button', { name: 'Finish' })).toBeVisible(); }); test('2.5a A. Workout Plans - Create Plan from Session', async ({ page, request, createUniqueUser }) => { // Seed data BEFORE login to ensure it's loaded when accessing history const user = await createUniqueUser(); const token = user.token; const pushupsId = generateId(); const squatsId = generateId(); await request.post('/api/exercises', { headers: { Authorization: `Bearer ${token}` }, data: { id: pushupsId, name: 'Test Pushups', type: 'BODYWEIGHT', isUnilateral: false } }); await request.post('/api/exercises', { headers: { Authorization: `Bearer ${token}` }, data: { id: squatsId, name: 'Test Squats', type: 'STRENGTH', isUnilateral: false } }); const sessionId = generateId(); const sessionData = { id: sessionId, startTime: Date.now() - 3600000, endTime: Date.now(), note: 'Killer workout', type: 'STANDARD', sets: [ { id: generateId(), exerciseId: pushupsId, exerciseName: 'Test Pushups', type: 'BODYWEIGHT', reps: 10, timestamp: Date.now() - 3000000, completed: true }, { id: generateId(), exerciseId: pushupsId, exerciseName: 'Test Pushups', type: 'BODYWEIGHT', reps: 12, weight: 10, timestamp: Date.now() - 2000000, completed: true }, { id: generateId(), exerciseId: squatsId, exerciseName: 'Test Squats', type: 'STRENGTH', reps: 5, weight: 100, timestamp: Date.now() - 1000000, completed: true } ] }; const response = await request.post('/api/sessions', { headers: { Authorization: `Bearer ${token}` }, data: sessionData }); expect(response.ok()).toBeTruthy(); // Login manually (using clean selectors) to avoid reload issues await page.goto('/'); await page.getByLabel('Email').fill(user.email); await page.getByLabel('Password').fill(user.password); await page.getByRole('button', { name: 'Login' }).click(); // Handle password change if it appears (reusing logic from helper) try { const heading = page.getByRole('heading', { name: /Change Password/i }); const initAcc = page.getByRole('heading', { name: /Setup Your Account/i }); const dashboard = page.getByText('Free Workout'); await expect(heading.or(initAcc).or(dashboard)).toBeVisible({ timeout: 10000 }); if (await heading.isVisible()) { await page.getByLabel('New Password').fill('StrongNewPass123!'); await page.getByRole('button', { name: /Save|Change/i }).click(); await expect(initAcc.or(dashboard)).toBeVisible(); } if (await initAcc.isVisible()) { await page.getByRole('button', { name: /Get Started/i }).click(); await expect(dashboard).toBeVisible(); } } catch (e) { // Login might already be done or dashboard loaded fast } await page.getByRole('button', { name: 'History' }).click(); await page.waitForURL('**/history'); // Wait for sessions to load const sessionActions = page.getByLabel('Session Actions').first(); await expect(sessionActions).toBeVisible({ timeout: 15000 }); await sessionActions.click(); await page.getByRole('button', { name: 'Create Plan' }).click(); // Verify Editor opens and data is populated (URL param is cleared immediately so we check UI) await expect(page.getByRole('heading', { name: 'Plan Editor' })).toBeVisible({ timeout: 10000 }); await expect(page.locator('textarea')).toHaveValue('Killer workout'); // Check exercises are populated const stepNames = page.getByTestId('plan-exercise-item'); await expect(stepNames).toHaveCount(3); await expect(stepNames.nth(0)).toContainText('Test Pushups'); await expect(stepNames.nth(1)).toContainText('Test Pushups'); await expect(stepNames.nth(2)).toContainText('Test Squats'); // Verify weighted checkboxes const items = page.getByTestId('plan-exercise-item'); await expect(items.nth(0).locator('input[type="checkbox"]')).not.toBeChecked(); await expect(items.nth(1).locator('input[type="checkbox"]')).toBeChecked(); await expect(items.nth(2).locator('input[type="checkbox"]')).toBeChecked(); }); test('2.14 A. Workout Plans - Create Plan with AI (Parametrized)', async ({ page, createUniqueUser }) => { // Merged from ai-plan-creation.spec.ts const user = await loginAndSetup(page, createUniqueUser); await page.route('**/api/ai/chat', async route => { const plan = { name: 'AI Advanced Plan', description: 'Generated High Intensity Plan', exercises: [ { name: 'Mock Push-ups', isWeighted: false, restTimeSeconds: 60, type: 'BODYWEIGHT', unilateral: false }, { name: 'Mock Weighted Pull-ups', isWeighted: true, restTimeSeconds: 90, type: 'BODYWEIGHT', unilateral: false } ] }; await route.fulfill({ json: { success: true, data: { response: JSON.stringify(plan) } } }); }); await page.getByRole('button', { name: 'Plans' }).first().click(); const fab = page.getByLabel('Create Plan').or(page.getByRole('button', { name: '+' })); await fab.click(); await page.getByRole('button', { name: 'With AI' }).click(); await expect(page.getByText('Create Plan with AI')).toBeVisible(); const eqSection = page.locator('div').filter({ hasText: 'Equipment' }).last(); const levelSection = page.locator('div').filter({ hasText: 'Level' }).last(); const intensitySection = page.locator('div').filter({ hasText: 'Intensity' }).last(); await levelSection.getByRole('button', { name: 'Advanced' }).click(); await intensitySection.getByRole('button', { name: 'High' }).click(); await eqSection.getByRole('button', { name: /Free weights/i }).click(); await page.getByRole('button', { name: 'Generate' }).click(); await expect(page.getByText('Generated Plan')).toBeVisible({ timeout: 10000 }); await expect(page.getByText('Mock Push-ups')).toBeVisible(); await page.getByRole('button', { name: 'Save Plan' }).click(); await expect(page.getByText('AI Advanced Plan')).toBeVisible(); }); }); test.describe('B. Exercise Library', () => { test('2.6 B. Exercise Library - Create Custom Exercise (Strength)', async ({ page, createUniqueUser }) => { await loginAndSetup(page, createUniqueUser); await page.getByRole('button', { name: 'Profile', exact: true }).click(); await page.locator('button:has-text("Manage Exercises")').click(); await page.getByRole('button', { name: /New Exercise/i }).click({ force: true }); await expect(page.locator('div[role="dialog"]')).toBeVisible(); await page.locator('div[role="dialog"]').getByLabel('Name').fill('Custom Bicep Curl'); await page.locator('div[role="dialog"]').getByRole('button', { name: 'Create' }).click(); await expect(page.locator('div[role="dialog"]')).not.toBeVisible(); await page.reload(); await page.getByRole('button', { name: 'Profile', exact: true }).click(); await page.locator('button:has-text("Manage Exercises")').click(); await page.getByLabel(/Filter by name/i).fill('Custom Bicep Curl'); await expect(page.getByText('Custom Bicep Curl')).toBeVisible(); }); test('2.7 B. Exercise Library - Create Custom Exercise (Bodyweight)', async ({ page, createUniqueUser }) => { await loginAndSetup(page, createUniqueUser); await page.getByRole('button', { name: 'Profile', exact: true }).click(); await page.getByRole('button', { name: /Manage Exercises/i }).click(); await page.getByRole('button', { name: /New Exercise/i }).click({ force: true }); await expect(page.locator('div[role="dialog"]')).toBeVisible(); await page.locator('div[role="dialog"]').getByLabel('Name').fill('Adv Pushup'); await page.locator('div[role="dialog"]').getByRole('button', { name: /Bodyweight/i }).click({ force: true }); await expect(page.getByLabel('Body Weight')).toBeVisible(); await page.getByLabel('Body Weight').fill('50'); await page.locator('div[role="dialog"]').getByRole('button', { name: 'Create' }).click(); await expect(page.locator('div[role="dialog"]')).not.toBeVisible(); await page.reload(); await page.getByRole('button', { name: 'Profile', exact: true }).click(); await page.getByRole('button', { name: /Manage Exercises/i }).click(); await page.getByLabel(/Filter by name/i).fill('Adv Pushup'); await expect(page.getByText('Adv Pushup')).toBeVisible(); }); test('2.8 B. Exercise Library - Edit Exercise Name', async ({ page, createUniqueUser }) => { await loginAndSetup(page, createUniqueUser); await page.getByRole('button', { name: 'Profile', exact: true }).click(); await page.locator('button:has-text("Manage Exercises")').click(); await page.getByRole('button', { name: /New Exercise/i }).click({ force: true }); await expect(page.locator('div[role="dialog"]')).toBeVisible(); await page.locator('div[role="dialog"]').getByLabel('Name').fill('Typo Name'); await page.locator('div[role="dialog"]').getByRole('button', { name: 'Create' }).click(); await expect(page.locator('div[role="dialog"]')).not.toBeVisible(); await page.reload(); await page.getByRole('button', { name: 'Profile', exact: true }).click(); await page.locator('button:has-text("Manage Exercises")').click(); await page.getByLabel(/Filter by name/i).fill('Typo Name'); await expect(page.getByText('Typo Name')).toBeVisible(); const row = page.locator('div') .filter({ hasText: 'Typo Name' }) .filter({ has: page.getByLabel('Edit Exercise') }) .last(); await row.getByLabel('Edit Exercise').click(); await page.locator('div[role="dialog"] input').first().fill('Fixed Name'); await page.locator('div[role="dialog"]').getByRole('button', { name: 'Save', exact: true }).click(); await page.getByLabel(/Filter by name/i).fill(''); await expect(page.getByText('Fixed Name')).toBeVisible(); }); test('2.9 B. Exercise Library - Archive/Unarchive', async ({ page, createUniqueUser }) => { await loginAndSetup(page, createUniqueUser); await page.getByRole('button', { name: 'Profile', exact: true }).click(); await page.locator('button:has-text("Manage Exercises")').click(); await page.getByRole('button', { name: /New Exercise/i }).click({ force: true }); await expect(page.locator('div[role="dialog"]')).toBeVisible(); await page.locator('div[role="dialog"]').getByLabel('Name').fill('Archive Me'); await page.locator('div[role="dialog"]').getByRole('button', { name: 'Create' }).click(); await expect(page.locator('div[role="dialog"]')).not.toBeVisible(); await page.reload(); await page.getByRole('button', { name: 'Profile', exact: true }).click(); await page.locator('button:has-text("Manage Exercises")').click(); await page.getByLabel(/Filter by name/i).fill('Archive Me'); await expect(page.getByText('Archive Me')).toBeVisible(); const row = page.locator('div.flex.justify-between').filter({ hasText: 'Archive Me' }).last(); await row.locator('[aria-label="Archive Exercise"]').click(); await expect(page.getByText('Archive Me')).not.toBeVisible(); // VERIFY: Should not appear in Plans Add Exercise selector await page.getByRole('button', { name: 'Plans' }).first().click(); await page.getByRole('button', { name: 'Create Plan' }).click(); await page.getByRole('button', { name: 'Create Plan Manually' }).click(); await page.getByRole('button', { name: 'Add Exercise' }).click(); await expect(page.getByRole('button', { name: 'Archive Me' })).not.toBeVisible(); // Close sidesheet - use more robust selector and wait for stability const closeBtn = page.getByLabel('Close'); await expect(closeBtn).toBeVisible(); await closeBtn.click(); // VERIFY: Should not appear in Tracker/Quick Log suggestions await page.getByRole('button', { name: 'Tracker' }).first().click(); await page.getByRole('button', { name: 'Quick Log' }).click(); await page.getByRole('textbox', { name: 'Select Exercise' }).fill('Archive'); await expect(page.getByRole('button', { name: 'Archive Me' })).not.toBeVisible(); // Go back to Profile and unarchive await page.getByRole('button', { name: 'Profile' }).first().click(); await page.locator('button:has-text("Manage Exercises")').click(); await page.locator('div').filter({ hasText: /Show Archived/i }).last().locator('input[type="checkbox"]').check(); await expect(page.getByText('Archive Me')).toBeVisible(); const archivedRow = page.locator('div') .filter({ hasText: 'Archive Me' }) .filter({ has: page.getByLabel('Unarchive Exercise') }) .last(); await archivedRow.getByLabel('Unarchive Exercise').click(); await page.locator('div').filter({ hasText: /Show Archived/i }).last().locator('input[type="checkbox"]').uncheck(); await expect(page.getByText('Archive Me')).toBeVisible(); // VERIFY: Should appear again in Tracker/Quick Log suggestions await page.getByRole('button', { name: 'Tracker' }).first().click(); await page.getByRole('button', { name: 'Quick Log' }).click(); await page.getByRole('textbox', { name: 'Select Exercise' }).fill('Archive'); await expect(page.getByRole('button', { name: 'Archive Me' })).toBeVisible(); }); test('2.10 B. Exercise Library - Filter by Name', async ({ page, createUniqueUser, request }) => { const user = await loginAndSetup(page, createUniqueUser); await request.post('/api/exercises', { data: { name: 'FindThisOne', type: 'STRENGTH' }, headers: { 'Authorization': `Bearer ${user.token}` } }); await request.post('/api/exercises', { data: { name: 'IgnoreThatOne', type: 'STRENGTH' }, headers: { 'Authorization': `Bearer ${user.token}` } }); await page.reload(); await page.getByRole('button', { name: 'Profile', exact: true }).click(); await page.getByRole('button', { name: /Manage Exercises/i }).click(); await page.getByLabel(/Filter by name/i).fill('FindThis'); await expect(page.getByText('FindThisOne')).toBeVisible(); await expect(page.getByText('IgnoreThatOne')).not.toBeVisible(); }); test('2.11 B. Exercise Library - Capitalization (Mobile)', async ({ page, createUniqueUser }) => { await page.setViewportSize({ width: 390, height: 844 }); await loginAndSetup(page, createUniqueUser); await page.getByRole('button', { name: 'Profile', exact: true }).click(); await page.locator('button:has-text("Manage Exercises")').click(); await page.getByRole('button', { name: /New Exercise/i }).click({ force: true }); const nameInput = page.locator('div[role="dialog"]').getByLabel('Name'); await expect(nameInput).toHaveAttribute('autocapitalize', 'words'); }); test('2.12 B. Exercise Library - Unilateral', async ({ page, createUniqueUser }) => { await loginAndSetup(page, createUniqueUser); await page.getByRole('button', { name: 'Profile', exact: true }).click(); await page.getByRole('button', { name: /Manage Exercises/i }).click(); await page.getByRole('button', { name: /New Exercise/i }).click({ force: true }); await page.locator('div[role="dialog"]').getByLabel('Name').fill('Single Leg Squat'); await page.getByLabel(/Unilateral exercise/).check(); await page.locator('div[role="dialog"]').getByRole('button', { name: 'Create' }).click(); await expect(page.locator('div[role="dialog"]')).not.toBeVisible(); await page.reload(); await page.getByRole('button', { name: 'Profile', exact: true }).click(); await page.getByRole('button', { name: /Manage Exercises/i }).click(); await page.getByLabel(/Filter by name/i).fill('Single Leg Squat'); await expect(page.getByText('Single Leg Squat')).toBeVisible(); // Verify Unilateral indicator might need text or specific element check, kept basic check: await expect(page.getByText('Unilateral', { exact: false }).first()).toBeVisible(); }); test('2.13 B. Exercise Library - Special Types', async ({ page, createUniqueUser }) => { await loginAndSetup(page, createUniqueUser); await page.getByRole('button', { name: 'Profile', exact: true }).click(); await page.getByRole('button', { name: /Manage Exercises/i }).click(); await page.getByRole('button', { name: /New Exercise/i }).click({ force: true }); await page.locator('div[role="dialog"]').getByLabel('Name').fill('Plank Test'); // Assuming the button name is 'Static' await page.locator('div[role="dialog"]').getByRole('button', { name: 'Static' }).click(); await page.locator('div[role="dialog"]').getByRole('button', { name: 'Create' }).click(); await expect(page.locator('div[role="dialog"]')).not.toBeVisible(); await page.reload(); await page.getByRole('button', { name: 'Profile', exact: true }).click(); await page.getByRole('button', { name: /Manage Exercises/i }).click(); await page.getByLabel(/Filter by name/i).fill('Plank Test'); await expect(page.getByText('Plank Test')).toBeVisible(); await expect(page.getByText('Static', { exact: false }).first()).toBeVisible(); }); test('2.15 B. Exercise Library - Edit to Unilateral & Verify Logger', async ({ page, createUniqueUser }) => { const user = await loginAndSetup(page, createUniqueUser); // 2. Create a standard exercise via Profile await page.getByRole('button', { name: 'Profile', exact: true }).click(); await page.getByRole('button', { name: 'Manage Exercises' }).click(); // Open create modal await page.getByRole('button', { name: 'New Exercise' }).click(); const exName = `Test Uni ${Date.now()}`; await page.locator('div[role="dialog"]').getByLabel('Name').fill(exName); await page.locator('div[role="dialog"]').getByRole('button', { name: 'Create' }).click(); // Verify it exists in list await expect(page.getByText(exName)).toBeVisible(); // 3. Edit exercise to be Unilateral const row = page.locator('div.flex.justify-between').filter({ hasText: exName }).first(); await row.getByRole('button', { name: 'Edit Exercise' }).click(); // Check the Unilateral checkbox await page.locator('div[role="dialog"]').getByLabel('Unilateral exercise').check(); await page.locator('div[role="dialog"]').getByRole('button', { name: 'Save' }).click(); // Verify "Unilateral" tag appears in the list (if UI shows it) await expect(row).toContainText('Unilateral'); // 4. Verify in Tracker await page.getByRole('button', { name: 'Tracker', exact: true }).click(); await page.getByRole('button', { name: 'Quick Log', exact: true }).click(); // Select the exercise await page.getByRole('textbox', { name: 'Select Exercise' }).fill(exName); await page.getByRole('button', { name: exName }).click(); // Verify L/A/R buttons appear await expect(page.getByTitle('Left')).toBeVisible(); await expect(page.getByTitle('Right')).toBeVisible(); await expect(page.getByTitle('Alternately')).toBeVisible(); }); }); });