import { test, expect } from './fixtures'; import { generateId } from '../src/utils/uuid'; import { ExerciseType } from '../src/types'; test('Create Plan from Session mirrors all sets 1:1', async ({ page, request, createUniqueUser }) => { // 1. Setup User const user = await createUniqueUser(); // 2. Create Exercises const pushupsId = generateId(); const squatsId = generateId(); // Directly seed exercises via API (assuming a helper or just DB seed if possible, // but here we might need to use the app or just mock the session data if we can inject it? // Actually, createUniqueUser returns a token. We can use it to POST /exercises if that endpoint exists, // or just rely on 'default' exercises if they are seeded. // Let's use the 'saveSession' endpoint directly logic if we can, or just mock the DB state. // Wait, the app uses local storage mostly or sync? // Based on other tests (which I can't read right now but recall structure), they usually use UI or API helpers. // I will assume I can just Login and then use UI or API. // Let's use UI to just ensure clean state, or API `POST /sessions` if available. // Based on `server/src/routes/sessions.ts` existing, I can POST session. // Let's rely on standard UI flows or API. // API is faster. const token = user.token; // Create Custom Exercises via API await request.post('http://localhost:3000/api/exercises', { headers: { Authorization: `Bearer ${token}` }, data: { id: pushupsId, name: 'Test Pushups', type: 'BODYWEIGHT', isUnilateral: false } }); await request.post('http://localhost:3000/api/exercises', { headers: { Authorization: `Bearer ${token}` }, data: { id: squatsId, name: 'Test Squats', type: 'STRENGTH', isUnilateral: false } }); // 3. Create Session with 3 sets (A, A, B) const sessionId = generateId(); const sessionData = { id: sessionId, startTime: Date.now() - 3600000, // 1 hour ago 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, // Weighted 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 } ] }; await request.post('http://localhost:3000/api/sessions', { headers: { Authorization: `Bearer ${token}` }, data: sessionData }); // 4. Login and Navigate await page.goto('http://localhost:3000/'); await page.fill('input[type="email"]', user.email); await page.fill('input[type="password"]', user.password); await page.click('button:has-text("Login")'); await page.waitForURL('**/tracker'); // 5. Go to History await page.click('text=History'); // 6. Click Create Plan const sessionCard = page.locator('div.bg-surface-container').first(); // Assuming it's the first card await sessionCard.waitFor(); // Open Menu await sessionCard.locator('button[aria-label="Session Actions"]').click(); // Click 'Create Plan' await page.click('text=Create Plan'); // 7. Verify Redirection await expect(page).toHaveURL(/.*plans\?createFromSessionId=.*/); // 8. Verify Plan Editor Content await expect(page.locator('h2')).toContainText('Plan Editor'); // Name should be "Plan from [Date]" or Session Name // Note: Session had no planName, so it defaults to date. // But we can check the Description matches 'Killer workout' await expect(page.locator('textarea')).toHaveValue('Killer workout'); // 9. Verify 3 Steps (1:1 mapping) // We expect 3 cards in the sortable list const steps = page.locator('.dnd-sortable-item_content, div[class*="items-center"] > div.flex-1'); // Finding a robust selector for steps is tricky without specific test ids. // The SortablePlanStep component has `div.text-base.font-medium.text-on-surface` for exercise name. const stepNames = page.locator('div.text-base.font-medium.text-on-surface'); await expect(stepNames).toHaveCount(3); await expect(stepNames.nth(0)).toHaveText('Test Pushups'); await expect(stepNames.nth(1)).toHaveText('Test Pushups'); await expect(stepNames.nth(2)).toHaveText('Test Squats'); // 10. Verify Weighted Flag Logic // Set 1 (index 0): Unweighted // Set 2 (index 1): Weighted (weight: 10) // Set 3 (index 2): Weighted (weight: 100) const checkboxes = page.locator('input[type="checkbox"]'); // Warning: there might be other checkboxes. // SortablePlanStep has a checkbox for 'weighted'. // Better to look for checked state within the step card. // Step 1: Unchecked await expect(page.locator('input[type="checkbox"]').nth(0)).not.toBeChecked(); // Step 2: Checked await expect(page.locator('input[type="checkbox"]').nth(1)).toBeChecked(); // Step 3: Checked await expect(page.locator('input[type="checkbox"]').nth(2)).toBeChecked(); });