import { test, expect } from './fixtures'; import { randomUUID } from 'crypto'; // Helper for setup 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 } return user; } test.describe('IV. Data & Progress', () => { test('4.1. A. Session History - View Past Sessions', async ({ page, createUniqueUser, request }) => { const user = await loginAndSetup(page, createUniqueUser); // Subtask 2.1: Complete a workout session const exNameSession = 'Hist View Session ' + randomUUID().slice(0, 4); await request.post('/api/exercises', { data: { name: exNameSession, type: 'STRENGTH' }, headers: { 'Authorization': `Bearer ${user.token}` } }); await page.getByRole('button', { name: /Free Workout|Start Empty/i }).click(); await page.getByRole('textbox', { name: /Select Exercise/i }).click(); await page.getByText(exNameSession).click(); await page.getByLabel('Weight (kg)').first().fill('50'); await page.getByLabel('Reps').first().fill('10'); await page.getByRole('button', { name: /Log Set/i }).click(); await page.getByRole('button', { name: 'Finish' }).click(); await page.getByRole('button', { name: 'Confirm' }).click(); // Subtask 2.2: Log a sporadic set const exNameSporadic = 'Hist View Sporadic ' + randomUUID().slice(0, 4); await request.post('/api/exercises', { data: { name: exNameSporadic, type: 'STRENGTH' }, headers: { 'Authorization': `Bearer ${user.token}` } }); await page.getByRole('button', { name: 'Quick Log' }).click(); await page.getByRole('textbox', { name: /Select Exercise/i }).click(); await page.getByText(exNameSporadic).click(); await page.getByLabel(/Reps/i).first().fill('12'); await page.getByRole('button', { name: /Log Set/i }).click(); await page.getByRole('button', { name: 'Quit' }).click(); // 3. Navigate to History await page.getByRole('button', { name: 'History' }).click(); // Verification await expect(page.getByRole('heading', { name: 'History' })).toBeVisible(); // Check for Quick Log entry details await expect(page.getByText(/50\s*kg\s*x\s*12\s*reps/).or(page.getByText(/x 12 reps/))).toBeVisible(); // Check for Workout Session entry (shows summary) await expect(page.getByText('No plan').first()).toBeVisible(); await expect(page.getByText('Sets:').first()).toBeVisible(); // Check for Quick Log heading await expect(page.getByRole('heading', { name: 'Quick Log' })).toBeVisible(); }); test('4.2. A. Session History - View Detailed Session', async ({ page, createUniqueUser, request }) => { const user = await loginAndSetup(page, createUniqueUser); const exName = 'Detail View ' + randomUUID().slice(0, 4); await request.post('/api/exercises', { data: { name: exName, type: 'STRENGTH' }, headers: { 'Authorization': `Bearer ${user.token}` } }); // Complete session await page.getByRole('button', { name: /Free Workout|Start Empty/i }).click(); await page.getByRole('textbox', { name: /Select Exercise/i }).click(); await page.getByText(exName).click(); await page.getByLabel('Weight (kg)').first().fill('50'); await page.getByLabel('Reps').first().fill('10'); await page.getByRole('button', { name: /Log Set/i }).click(); await expect(page.getByText('50 kg x 10 reps')).toBeVisible(); await page.getByRole('button', { name: 'Finish' }).click(); await page.getByRole('button', { name: 'Confirm' }).click(); // Navigate to History await page.getByRole('button', { name: 'History' }).click(); // Click on a workout session entry await page.getByText('No plan').first().click(); // Verification await expect(page.getByRole('heading', { name: /Edit|Session Details/ })).toBeVisible(); // Check details await expect(page.getByText('Start')).toBeVisible(); await expect(page.getByText('End')).toBeVisible(); await expect(page.getByText('Weight (kg)').first()).toBeVisible(); // Verify set details await expect(page.getByRole('heading', { name: /Sets/ })).toBeVisible(); }); test('4.3. A. Session History - Edit Past Session Details', async ({ page, createUniqueUser, request }) => { const user = await loginAndSetup(page, createUniqueUser); const exName = 'Edit Sess ' + randomUUID().slice(0, 4); await request.post('/api/exercises', { data: { name: exName, type: 'STRENGTH' }, headers: { 'Authorization': `Bearer ${user.token}` } }); await page.getByRole('button', { name: /Free Workout/i }).click(); await page.getByRole('textbox', { name: /Select/i }).click(); await page.getByText(exName).click(); await page.getByLabel(/Weight/i).first().fill('50'); await page.getByLabel(/Reps/i).first().fill('10'); await page.getByRole('button', { name: /Log/i }).click(); await page.getByRole('button', { name: 'Finish' }).click(); await page.getByRole('button', { name: 'Confirm' }).click(); await page.getByRole('button', { name: 'History' }).click(); // Open details await page.getByText('No plan').first().click(); // Modify Body Weight (first spinbutton usually) await page.getByRole('spinbutton').first().fill('75.5'); // Save await page.getByRole('button', { name: 'Save' }).click(); // Verify await expect(page.getByText('75.5kg')).toBeVisible(); }); test('4.4. A. Session History - Edit Individual Set in Past Session', async ({ page, createUniqueUser, request }) => { const user = await loginAndSetup(page, createUniqueUser); const exName = 'Edit Set ' + randomUUID().slice(0, 4); await request.post('/api/exercises', { data: { name: exName, type: 'STRENGTH' }, headers: { 'Authorization': `Bearer ${user.token}` } }); await page.getByRole('button', { name: /Free Workout/i }).click(); await page.getByRole('textbox', { name: /Select/i }).click(); await page.getByText(exName).click(); await page.getByLabel(/Weight/i).first().fill('50'); await page.getByLabel(/Reps/i).first().fill('10'); await page.getByRole('button', { name: /Log/i }).click(); await expect(page.getByText('50 kg x 10 reps')).toBeVisible(); await page.getByRole('button', { name: 'Finish' }).click(); await page.getByRole('button', { name: 'Confirm' }).click(); await page.getByRole('button', { name: 'History' }).click(); // Open details await page.getByText('No plan').first().click(); // Modify weight from 50 to 55 // Be specific with locator if possible, or use first matching input await page.locator('input[value="50"]').fill('55'); // Save await page.getByRole('button', { name: 'Save' }).click(); // Verify await page.getByText('No plan').first().click(); await expect(page.locator('input[value="55"]')).toBeVisible(); }); test('4.5. A. Session History - Delete Past Session', async ({ page, createUniqueUser, request }) => { const user = await loginAndSetup(page, createUniqueUser); const exName = 'Del Sess ' + randomUUID().slice(0, 4); await request.post('/api/exercises', { data: { name: exName, type: 'STRENGTH' }, headers: { 'Authorization': `Bearer ${user.token}` } }); await page.getByRole('button', { name: /Free Workout/i }).click(); await page.getByRole('textbox', { name: /Select/i }).click(); await page.getByText(exName).click(); await page.getByLabel(/Weight/i).first().fill('50'); await page.getByLabel(/Reps/i).first().fill('10'); await page.getByRole('button', { name: /Log/i }).click(); await expect(page.getByText('50 kg x 10 reps')).toBeVisible(); await page.getByRole('button', { name: 'Finish' }).click(); await page.getByRole('button', { name: 'Confirm' }).click(); await page.getByRole('button', { name: 'History' }).click(); await expect(page.getByText('No plan').first()).toBeVisible(); // Delete (2nd button usually) await page.getByRole('main').getByRole('button').nth(1).click(); // Confirm await expect(page.getByRole('heading', { name: 'Delete workout?' })).toBeVisible(); await page.getByRole('button', { name: 'Delete' }).click(); // Verify empty await expect(page.getByText('History is empty')).toBeVisible(); }); test('4.6. A. Session History - Edit Sporadic Set', async ({ page, createUniqueUser, request }) => { const user = await loginAndSetup(page, createUniqueUser); const exName = 'Spor Edit ' + randomUUID().slice(0, 4); await request.post('/api/exercises', { data: { name: exName, type: 'STRENGTH' }, headers: { 'Authorization': `Bearer ${user.token}` } }); await page.getByRole('button', { name: 'Quick Log' }).click(); await page.getByRole('textbox', { name: /Select/i }).click(); await page.getByText(exName).click(); await page.getByLabel(/Weight/i).first().fill('50'); await page.getByLabel(/Reps/i).first().fill('12'); await page.getByRole('button', { name: /Log/i }).click(); await page.getByRole('button', { name: 'Quit' }).click(); await page.getByRole('button', { name: 'History' }).click(); await expect(page.getByRole('heading', { name: 'Quick Log' })).toBeVisible(); // Edit (1st button for sporadic row) await page.getByRole('main').getByRole('button').nth(0).click(); await expect(page.getByRole('heading', { name: 'Edit' })).toBeVisible(); await page.locator('input[value="12"]').fill('15'); await page.getByRole('button', { name: 'Save' }).click(); await expect(page.getByText(/50\s*kg\s*x\s*15\s*reps/)).toBeVisible(); }); test('4.7. A. Session History - Delete Sporadic Set', async ({ page, createUniqueUser, request }) => { const user = await loginAndSetup(page, createUniqueUser); const exName = 'Spor Del ' + randomUUID().slice(0, 4); await request.post('/api/exercises', { data: { name: exName, type: 'STRENGTH' }, headers: { 'Authorization': `Bearer ${user.token}` } }); await page.getByRole('button', { name: 'Quick Log' }).click(); await page.getByRole('textbox', { name: /Select/i }).click(); await page.getByText(exName).click(); await page.getByLabel(/Weight/i).first().fill('50'); await page.getByLabel(/Reps/i).first().fill('12'); await page.getByRole('button', { name: /Log/i }).click(); await page.getByRole('button', { name: 'Quit' }).click(); await page.getByRole('button', { name: 'History' }).click(); // Delete (2nd button for sporadic row, or last button in main if only one row) // With only one row, buttons are Edit, Delete. Delete is 2nd. await page.getByRole('main').getByRole('button').last().click(); await expect(page.getByRole('dialog')).toBeVisible(); await page.getByRole('button', { name: 'Delete' }).click(); await expect(page.getByText('50 kg x 12 reps')).not.toBeVisible(); }); test('4.8. B. Performance Statistics - View Volume Chart', async ({ page, createUniqueUser, request }) => { test.setTimeout(120000); const user = await loginAndSetup(page, createUniqueUser); const exName = 'Vol Chart ' + randomUUID().slice(0, 4); await request.post('/api/exercises', { data: { name: exName, type: 'STRENGTH' }, headers: { 'Authorization': `Bearer ${user.token}` } }); // Session 1 await page.getByRole('button', { name: /Free Workout/i }).click(); await page.getByRole('textbox', { name: /Select/i }).click(); await page.getByText(exName).click(); await page.getByLabel(/Weight/i).first().fill('50'); await page.getByLabel(/Reps/i).first().fill('10'); await page.getByRole('button', { name: /Log/i }).click(); await expect(page.getByText('50 kg x 10 reps')).toBeVisible(); await page.getByRole('button', { name: 'Finish' }).click(); await page.getByRole('button', { name: 'Confirm' }).click(); // Session 2 await page.getByRole('button', { name: /Free Workout/i }).click(); await page.getByRole('textbox', { name: /Select/i }).click(); await page.getByText(exName).click(); await page.getByLabel(/Weight/i).first().fill('60'); await page.getByLabel(/Reps/i).first().fill('10'); await page.getByRole('button', { name: /Log/i }).click(); await page.getByRole('button', { name: 'Finish' }).click(); await page.getByRole('button', { name: 'Confirm' }).click(); await page.getByRole('button', { name: 'Stats' }).click(); await expect(page.getByText('Work Volume')).toBeVisible(); }); test('4.9. B. Performance Statistics - View Set Count Chart', async ({ page, createUniqueUser, request }) => { test.setTimeout(120000); const user = await loginAndSetup(page, createUniqueUser); const exName = 'Set Chart ' + randomUUID().slice(0, 4); await request.post('/api/exercises', { data: { name: exName, type: 'STRENGTH' }, headers: { 'Authorization': `Bearer ${user.token}` } }); // Session 1 await page.getByRole('button', { name: /Free Workout/i }).click(); await page.getByRole('textbox', { name: /Select/i }).click(); await page.getByText(exName).click(); await page.getByLabel(/Weight/i).first().fill('50'); await page.getByLabel(/Reps/i).first().fill('10'); await page.getByRole('button', { name: /Log/i }).click(); await page.getByRole('button', { name: 'Finish' }).click(); await page.getByRole('button', { name: 'Confirm' }).click(); // Session 2 await page.getByRole('button', { name: /Free Workout/i }).click(); await page.getByRole('textbox', { name: /Select/i }).click(); await page.getByText(exName).click(); await page.getByLabel(/Weight/i).first().fill('60'); await page.getByLabel(/Reps/i).first().fill('10'); await page.getByRole('button', { name: /Log/i }).click(); await page.getByRole('button', { name: 'Finish' }).click(); await page.getByRole('button', { name: 'Confirm' }).click(); await page.getByRole('button', { name: 'Stats' }).click(); await expect(page.getByText('Number of Sets')).toBeVisible(); }); test('4.10. B. Performance Statistics - View Body Weight Chart', async ({ page, createUniqueUser, request }) => { test.setTimeout(120000); const user = await loginAndSetup(page, createUniqueUser); const exName = 'BW Chart ' + randomUUID().slice(0, 4); await request.post('/api/exercises', { data: { name: exName, type: 'STRENGTH' }, headers: { 'Authorization': `Bearer ${user.token}` } }); // Complete 2 sessions (to unlock stats page - assuming constraint) // Session 1 await page.getByRole('button', { name: /Free Workout/i }).click(); await page.getByRole('textbox', { name: /Select/i }).click(); await page.getByText(exName).click(); await page.getByLabel(/Weight/i).first().fill('50'); await page.getByLabel(/Reps/i).first().fill('10'); await page.getByRole('button', { name: /Log/i }).click(); await page.getByRole('button', { name: 'Finish' }).click(); await page.getByRole('button', { name: 'Confirm' }).click(); // Session 2 await page.getByRole('button', { name: /Free Workout/i }).click(); await page.getByRole('textbox', { name: /Select/i }).click(); await page.getByText(exName).click(); await page.getByLabel(/Weight/i).first().fill('60'); await page.getByLabel(/Reps/i).first().fill('10'); await page.getByRole('button', { name: /Log/i }).click(); await page.getByRole('button', { name: 'Finish' }).click(); await page.getByRole('button', { name: 'Confirm' }).click(); // Log body weight history via API const yesterday = new Date(); yesterday.setDate(yesterday.getDate() - 1); const dateStr = yesterday.toISOString().split('T')[0]; await page.evaluate(async ({ token, dateStr }) => { await fetch('/api/weight', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` }, body: JSON.stringify({ weight: 70, dateStr }) }); }, { token: user.token, dateStr }); // Log today's weight via UI await page.getByRole('button', { name: 'Profile' }).click(); await page.getByRole('button', { name: 'Weight Tracker' }).click(); await page.getByPlaceholder('Enter weight...').fill('72'); await page.getByRole('button', { name: 'Log', exact: true }).click(); await expect(page.getByText('Weight logged successfully')).toBeVisible(); await page.getByRole('button', { name: 'Stats' }).click(); await expect(page.getByText('Body Weight History')).toBeVisible(); }); });