import { test, expect } from './fixtures'; import { randomUUID } from 'crypto'; test.describe('II. Workout Management', () => { 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(); // Wait for potential animation/loading await expect(page.getByText('Plan Editor')).toBeVisible({ timeout: 10000 }); await page.getByLabel(/Name/i).fill('My New Strength Plan'); await page.getByPlaceholder(/Describe preparation/i).fill('Focus on compound lifts'); await page.getByRole('button', { name: 'Add Exercise' }).click(); await expect(page.getByText('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.skip('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(); // Use the new aria-label selector 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(); // Check initial order by visibility for now await expect(page.locator('div').filter({ hasText: 'Ex One' }).first()).toBeVisible(); await expect(page.locator('div').filter({ hasText: 'Ex Two' }).last()).toBeVisible(); }); 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(); await expect(page.getByText('Startable Plan', { exact: false })).toBeVisible(); await expect(page.getByRole('button', { name: 'Finish' })).toBeVisible(); }); // --- Exercise Tests --- test('2.6 B. Exercise Library - Create Custom Exercise (Strength)', async ({ page, createUniqueUser }) => { await loginAndSetup(page, createUniqueUser); await page.getByRole('button', { name: 'Profile' }).click(); await page.getByRole('button', { name: /Manage Exercises/i }).click(); await page.getByRole('button', { name: /New Exercise/i }).click(); await page.getByLabel('Name').fill('Custom Bicep Curl'); await expect(page.getByText('Free Weights & Machines', { exact: false })).toBeVisible(); await page.getByRole('button', { name: 'Create' }).click(); // Reload and filter await page.reload(); await page.getByRole('button', { name: 'Profile' }).click(); await page.getByRole('button', { name: /Manage Exercises/i }).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' }).click(); await page.getByRole('button', { name: /Manage Exercises/i }).click(); await page.getByRole('button', { name: /New Exercise/i }).click(); await page.getByLabel('Name').fill('Adv Pushup'); // Scope to dialog to avoid background matches await page.locator('div[role="dialog"] button').filter({ hasText: /Bodyweight/i }).click(); await expect(page.getByLabel('Body Weight')).toBeVisible(); await page.getByLabel('Body Weight').fill('50'); await page.getByRole('button', { name: 'Create' }).click(); // Reload and filter await page.reload(); await page.getByRole('button', { name: 'Profile' }).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(); await expect(page.getByText('Bodyweight', { exact: false }).first()).toBeVisible(); }); test('2.8 B. Exercise Library - Edit Exercise Name', async ({ page, createUniqueUser, request }) => { const user = await loginAndSetup(page, createUniqueUser); await request.post('/api/exercises', { data: { name: 'Typo Name', type: 'STRENGTH' }, headers: { 'Authorization': `Bearer ${user.token}` } }); await page.reload(); await page.getByRole('button', { name: 'Profile' }).click(); await page.getByRole('button', { name: /Manage Exercises/i }).click(); const row = page.locator('div').filter({ hasText: 'Typo Name' }).last(); await row.locator('button').filter({ has: page.locator('svg.lucide-pencil') }).click(); await page.locator('div[role="dialog"] input').first().fill('Fixed Name'); await page.getByRole('button', { name: 'Save' }).click(); await expect(page.getByText('Fixed Name')).toBeVisible(); await expect(page.getByText('Typo Name')).not.toBeVisible(); }); test('2.9 B. Exercise Library - Archive/Unarchive', async ({ page, createUniqueUser, request }) => { const user = await loginAndSetup(page, createUniqueUser); await request.post('/api/exercises', { data: { name: 'Archive Me', type: 'STRENGTH' }, headers: { 'Authorization': `Bearer ${user.token}` } }); await page.reload(); await page.getByRole('button', { name: 'Profile' }).click(); await page.getByRole('button', { name: /Manage Exercises/i }).click(); const row = page.locator('div').filter({ hasText: 'Archive Me' }).last(); // Archive button (box-archive or similar) await row.locator('button').filter({ has: page.locator('svg.lucide-archive') }).click(); // It should disappear or fade. "Show Archived" is false by default. await expect(page.getByText('Archive Me')).not.toBeVisible(); // Toggle Show Archived await page.getByLabel('Show Archived').check(); await expect(page.getByText('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' }).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.skip('2.11 B. Exercise Library - Capitalization (Mobile)', async ({ page }) => { // ... }); test('2.12 B. Exercise Library - Unilateral', async ({ page, createUniqueUser }) => { await loginAndSetup(page, createUniqueUser); await page.getByRole('button', { name: 'Profile' }).click(); await page.getByRole('button', { name: /Manage Exercises/i }).click(); await page.getByRole('button', { name: /New Exercise/i }).click(); await page.getByLabel('Name').fill('Single Leg Squat'); await page.locator('input[type="checkbox"]').first().check(); await page.getByRole('button', { name: 'Create' }).click(); // Reload and filter await page.reload(); await page.getByRole('button', { name: 'Profile' }).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(); 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' }).click(); await page.getByRole('button', { name: /Manage Exercises/i }).click(); await page.getByRole('button', { name: /New Exercise/i }).click(); await page.getByLabel('Name').fill('Plank Test'); await page.locator('button').filter({ hasText: /Static/i }).click(); await page.getByRole('button', { name: 'Create' }).click(); // Reload and filter await page.reload(); await page.getByRole('button', { name: 'Profile' }).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(); }); }); 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 dashboard = page.getByText('Free Workout'); await expect(heading.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(dashboard).toBeVisible(); } } catch (e) { // Login might already be done or dashboard loaded fast } return user; }