Playwright tests removed

This commit is contained in:
AG
2025-12-08 07:27:45 +02:00
parent a3a9aa7194
commit e477f72e64
58 changed files with 0 additions and 2262 deletions

View File

@@ -1,42 +0,0 @@
// spec: specs/gymflow-test-plan.md
// seed: tests/workout-tracking.spec.ts
import { test, expect } from '@playwright/test';
test.describe('III. Workout Tracking', () => {
test.fixme('C. Active Session - Delete Logged Set', async ({ page }) => {
// This test is currently skipped due to persistent timeouts when attempting to interact with
// spinbuttons, similar to other tests. This suggests an issue with element visibility or
// interaction on the page's initial state after login, indicating problems with page loading
// or state management. This requires further investigation.
// 1. Start a 'Free Workout' session.
await page.goto('http://localhost:3000/');
await page.getByRole('textbox', { name: 'user@gymflow.ai' }).fill('test@e2e.com');
await page.locator('input[type="password"]').fill('e2e');
await page.getByRole('button', { name: 'Login' }).click();
await page.getByRole('spinbutton').first().fill('83');
await page.getByRole('button', { name: 'Free Workout' }).click();
// 2. Log at least one set.
await page.getByRole('textbox', { name: '0' }).fill('Bench Press');
await page.getByRole('button', { name: 'Bench Press' }).click();
await page.getByPlaceholder('0').nth(1).fill('80');
await page.getByPlaceholder('0').nth(2).fill('5');
await page.getByRole('button', { name: 'Log Set' }).click();
// 3. Click the 'Delete' icon for a logged set.
await page.locator('div').filter({ has: page.getByText('Bench Press') }).locator('button[title="Delete"]').click();
// 4. Confirm deletion.
// NOTE: There is no explicit confirmation dialog in the UI. The set is deleted directly.
await page.waitForLoadState('networkidle');
// Expected Results:
// - The set is removed from the session history.
await expect(page.locator('div').filter({ has: page.getByText('Bench Press') })).toHaveCount(0);
// - No error messages.
await expect(page.locator('text=Error')).not.toBeVisible();
});
});

View File

@@ -1,38 +0,0 @@
// spec: specs/gymflow-test-plan.md
// seed: tests/workout-tracking.spec.ts
import { test, expect } from '@playwright/test';
test.describe('III. Workout Tracking', () => {
test('C. Active Session - Finish Session', async ({ page }) => {
// 1. Start a 'Free Workout' session.
await page.goto('http://localhost:3000/');
await page.locator('input[type="email"]').fill('admin@gymflow.ai');
await page.locator('input[type="password"]').fill('admin123');
await page.getByRole('button', { name: 'Login' }).click();
await page.getByRole('spinbutton').fill('83');
await page.getByRole('button', { name: 'Free Workout' }).click();
// 2. Log at least one set.
await page.getByRole('textbox', { name: '0' }).fill('Bench Press');
await page.getByRole('button', { name: 'Bench Press' }).click();
await page.getByRole('spinbutton').nth(1).fill('80');
await page.getByRole('spinbutton').nth(2).fill('5');
await page.getByRole('button', { name: 'Log Set' }).click();
// 3. Click 'Finish' button.
await page.getByRole('button', { name: 'Finish' }).click();
// 4. Confirm finishing the session.
await page.getByRole('button', { name: 'Confirm' }).click();
// Expected Results:
// - Session data is saved.
// NOTE: This cannot be directly verified from the UI in this step, but implicitly tested if user returns to idle state without error.
// - User is returned to the 'Idle State' of the Tracker.
await expect(page.getByRole('heading', { name: 'Ready?' })).toBeVisible();
// - No error messages.
await expect(page.locator('text=Error')).not.toBeVisible();
});
});

View File

@@ -1,41 +0,0 @@
// spec: specs/gymflow-test-plan.md
// seed: tests/workout-tracking.spec.ts
import { test, expect } from '@playwright/test';
test.describe('III. Workout Tracking', () => {
test('C. Active Session - Log Bodyweight Set', async ({ page }) => {
// 1. Start a 'Free Workout' session.
await page.goto('http://localhost:3000/');
await page.locator('input[type="email"]').fill('admin@gymflow.ai');
await page.locator('input[type="password"]').fill('admin123');
await page.getByRole('button', { name: 'Login' }).click();
await page.getByRole('spinbutton').fill('83');
await page.getByRole('button', { name: 'Free Workout' }).click();
// 2. Select a Bodyweight exercise (e.g., 'Pull-up').
await page.getByRole('textbox', { name: '0' }).fill('Pull-up');
await page.getByRole('button', { name: 'Pull-Ups' }).click();
// 3. Enter 'Weight' (e.g., '10') and 'Reps' (e.g., '8').
await page.getByPlaceholder('0').nth(1).fill('10');
await page.getByPlaceholder('0').nth(2).fill('8');
// 4. Verify 'Body Weight Percentage' defaults to '100'.
// NOTE: This field is not directly visible in the UI. Assuming it's handled internally.
// To properly test this, an API call or a different UI element would be needed.
// 5. Click 'Log Set'.
await page.getByRole('button', { name: 'Log Set' }).click();
// Expected Results:
// - The set is added to the session history.
await expect(page.locator('div').filter({ hasText: /^1Pull-Ups10kg x 8$/ }).getByText('Pull-Ups')).toBeVisible();
// - Input fields are cleared.
// - Body weight percentage is used in calculations.
// NOTE: Cannot directly verify this from UI. Implicitly covered if the set is logged correctly.
// - No error messages are displayed.
await expect(page.locator('text=Error')).not.toBeVisible();
});
});

View File

@@ -1,39 +0,0 @@
// spec: specs/gymflow-test-plan.md
// seed: tests/workout-tracking.spec.ts
import { test, expect } from '@playwright/test';
test.describe('III. Workout Tracking', () => {
test('C. Active Session - Log Cardio Set', async ({ page }) => {
// 1. Start a 'Free Workout' session.
await page.goto('http://localhost:3000/');
await page.locator('input[type="email"]').fill('admin@gymflow.ai');
await page.locator('input[type="password"]').fill('admin123');
await page.getByRole('button', { name: 'Login' }).click();
await page.getByRole('spinbutton').fill('83');
await page.getByRole('button', { name: 'Free Workout' }).click();
// Ensure Running exercise exists for selection
// (This part would ideally be handled by seed data or a setup step)
// For now, assuming "Running" is available from previous manual creation or seed.
// 2. Select a Cardio exercise (e.g., 'Running').
await page.getByRole('textbox', { name: '0' }).fill('Running');
await page.getByRole('button', { name: 'Running' }).click();
// 3. Enter 'Time (sec)' (e.g., '300') and 'Distance (m)' (e.g., '1000').
await page.getByPlaceholder('0').nth(1).fill('300');
await page.getByPlaceholder('0').nth(2).fill('1000');
// 4. Click 'Log Set'.
await page.getByRole('button', { name: 'Log Set' }).click();
// Expected Results:
// - The set is added to the session history.
await expect(page.locator('div').filter({ hasText: /^1Running300s \/ 1000m$/ }).getByText('Running')).toBeVisible();
// - Input fields are cleared.
// - No error messages are displayed.
await expect(page.locator('text=Error')).not.toBeVisible();
});
});

View File

@@ -1,39 +0,0 @@
// spec: specs/gymflow-test-plan.md
// seed: tests/workout-tracking.spec.ts
import { test, expect } from '@playwright/test';
test.describe('III. Workout Tracking', () => {
test('C. Active Session - Log Strength Set', async ({ page }) => {
// 1. Start a 'Free Workout' session (ensure body weight is set).
await page.goto('http://localhost:3000/');
await page.locator('input[type="email"]').fill('admin@gymflow.ai');
await page.locator('input[type="password"]').fill('admin123');
await page.getByRole('button', { name: 'Login' }).click();
await page.getByRole('spinbutton').fill('83');
await page.getByRole('button', { name: 'Free Workout' }).click();
// Ensure Bench Press exercise exists for selection
// (This part would ideally be handled by seed data or a setup step)
// For now, assuming "Bench Press" is available from previous manual creation or seed.
// 2. Select a Strength exercise (e.g., 'Bench Press').
await page.getByRole('textbox', { name: '0' }).fill('Bench Press');
await page.getByRole('button', { name: 'Bench Press' }).click();
// 3. Enter 'Weight' (e.g., '80') and 'Reps' (e.g., '5').
await page.getByPlaceholder('0').nth(1).fill('80');
await page.getByPlaceholder('0').nth(2).fill('5');
// 4. Click 'Log Set'.
await page.getByRole('button', { name: 'Log Set' }).click();
// Expected Results:
// - The set is added to the session history.
await expect(page.locator('div').filter({ hasText: /^1Bench Press80kg x 5$/ }).getByText('Bench Press')).toBeVisible();
// - Input fields are cleared.
// - No error messages are displayed.
await expect(page.locator('text=Error')).not.toBeVisible();
});
});

View File

@@ -1,59 +0,0 @@
// spec: specs/gymflow-test-plan.md
// seed: tests/workout-tracking.spec.ts
import { test, expect } from '@playwright/test';
test.describe('III. Workout Tracking', () => {
test('C. Active Session - Plan Progression and Jump to Step', async ({ page }) => {
// 1. Start a session from a workout plan with multiple steps.
await page.goto('http://localhost:3000/');
await page.locator('input[type="email"]').fill('admin@gymflow.ai');
await page.locator('input[type="password"]').fill('admin123');
await page.getByRole('button', { name: 'Login' }).click();
// Create a plan with multiple exercises
await page.getByRole('button', { name: 'Plans' }).click();
await page.locator('.absolute.bottom-6').click(); // Click FAB
await page.getByRole('textbox', { name: 'E.g. Full-body Routine' }).fill('Plan Progression Test Plan');
await page.getByRole('textbox', { name: 'Describe preparation...' }).fill('Test plan for plan progression');
await page.getByRole('button', { name: 'Add Exercise' }).click();
await page.getByRole('button', { name: 'Bench Press STRENGTH' }).click();
await page.getByRole('button', { name: 'Add Exercise' }).click();
await page.getByRole('button', { name: 'Pull-Ups BODYWEIGHT' }).click();
await page.getByRole('button', { name: 'Add Exercise' }).click();
await page.getByRole('button', { name: 'Dips BODYWEIGHT' }).click();
await page.getByRole('button', { name: 'Save' }).click();
// Start the plan
await page.getByRole('button', { name: 'Start' }).nth(3).click();
// NOTE: BUG: The session currently starts as a "Free Workout" and does not pre-populate with the plan's exercises.
// The following steps and assertions are adapted to the current (buggy) behavior.
// 2. Log sets for the first exercise in the plan until it's considered complete.
// (Simulating logging a set in a free workout, as plan exercises are not loaded)
await page.getByRole('textbox', { name: '0' }).fill('Bench Press');
await page.getByRole('button', { name: 'Bench Press' }).click();
await page.getByPlaceholder('0').nth(1).fill('80');
await page.getByPlaceholder('0').nth(2).fill('5');
await page.getByRole('button', { name: 'Log Set' }).click();
// 3. Observe the plan progression to the next step.
// In current buggy state, there is no plan progression to observe.
// Assertions related to plan progression cannot be made.
// 4. Click on the plan progression bar to expand the plan list.
// In current buggy state, there is no plan progression bar.
// Assertions related to expanding plan list cannot be made.
// 5. Click on a different (e.g., third) step in the expanded plan list.
// In current buggy state, there is no expanded plan list.
// Assertions related to navigating to a step cannot be made.
// Expected Results: (Adapted to current buggy behavior)
// - The application transitions to the 'Active Session' view (as a Free Workout).
await expect(page.getByRole('heading', { name: 'Plan Progression Test Plan' })).toBeVisible();
await expect(page.getByText(/(\d{2}:){2}\d{2}/)).toBeVisible();
await expect(page.locator('div').filter({ hasText: /^1Bench Press80kg x 5$/ }).getByText('Bench Press')).toBeVisible();
});
});

View File

@@ -1,41 +0,0 @@
// spec: specs/gymflow-test-plan.md
// seed: tests/workout-tracking.spec.ts
import { test, expect } from '@playwright/test';
test.describe('III. Workout Tracking', () => {
test('C. Active Session - Quit Session Without Saving', async ({ page }) => {
// 1. Start a 'Free Workout' session.
await page.goto('http://localhost:3000/');
await page.locator('input[type="email"]').fill('admin@gymflow.ai');
await page.locator('input[type="password"]').fill('admin123');
await page.getByRole('button', { name: 'Login' }).click();
await page.getByRole('spinbutton').fill('83');
await page.getByRole('button', { name: 'Free Workout' }).click();
// 2. Log at least one set.
await page.getByRole('textbox', { name: '0' }).fill('Bench Press');
await page.getByRole('button', { name: 'Bench Press' }).click();
await page.getByPlaceholder('0').nth(1).fill('80');
await page.getByPlaceholder('0').nth(2).fill('5');
await page.getByRole('button', { name: 'Log Set' }).click();
// 3. Click 'More' (three dots) menu.
await page.getByRole('button').filter({ hasText: /^$/ }).first().click();
// 4. Select 'Quit Without Saving'.
await page.getByRole('button', { name: 'Quit without saving' }).click();
// 5. Confirm quitting.
await page.getByRole('button', { name: 'Confirm' }).click();
// Expected Results:
// - Session data is discarded.
// NOTE: This cannot be directly verified from the UI in this step, but implicitly tested if user returns to idle state without error.
// - User is returned to the 'Idle State' of the Tracker.
await expect(page.getByRole('heading', { name: 'Ready?' })).toBeVisible();
// - No error messages.
await expect(page.locator('text=Error')).not.toBeVisible();
});
});

View File

@@ -1,31 +0,0 @@
// spec: specs/gymflow-test-plan.md
// seed: tests/ui-ux.spec.ts
import { test, expect } from '@playwright/test';
test.describe('User Interface & Experience', () => {
test.fixme('Adaptive GUI - Desktop Navigation (Width >= 768px)', async ({ page }) => {
// This test is currently skipped because of a persistent login issue.
// The test user credentials appear to be invalid, preventing the test from proceeding.
// This needs to be investigated and fixed before the test can be re-enabled.
// 1. Log in as a regular user.
await page.goto('http://192.168.50.234:3000/');
await page.getByRole('textbox', { name: 'user@gymflow.ai' }).fill('test@e2e.com');
await page.locator('input[type="password"]').fill('e2e');
await page.getByRole('button', { name: 'Login' }).click();
// 2. Resize the browser window to a desktop width (e.g., 1280px).
await page.setViewportSize({ width: 1280, height: 720 });
// 3. Verify the vertical navigation rail is visible and functional.
await expect(page.getByRole('link', { name: 'Tracker' })).toBeVisible();
await expect(page.getByRole('link', { name: 'Plans' })).toBeVisible();
await expect(page.getByRole('link', { name: 'History' })).toBeVisible();
await expect(page.getByRole('link', { name: 'Stats' })).toBeVisible();
await expect(page.getByRole('link', { name: 'AI Coach' })).toBeVisible();
await expect(page.getByRole('link', { name: 'Profile' })).toBeVisible();
// 4. Verify the mobile bottom navigation bar is hidden.
await expect(page.getByRole('navigation', { name: 'Bottom navigation bar' })).toBeHidden();
});
});

View File

@@ -1,22 +0,0 @@
// spec: specs/gymflow-test-plan.md
// seed: tests/ui-ux.spec.ts
import { test, expect } from '@playwright/test';
test.describe('User Interface & Experience', () => {
test('Adaptive GUI - Fluid Layout Responsiveness', async ({ page }) => {
// 1. Log in as a regular user.
await page.goto('http://192.168.50.234:3000/');
await page.getByRole('textbox', { name: '0' }).first().fill('admin@gymflow.ai');
await page.locator('input[type="password"]').fill('admin');
await page.getByRole('button', { name: 'Login' }).click();
// The following steps require a successful login to execute.
// Once logged in, these steps would verify fluid layout responsiveness:
// 2. Navigate through various sections (e.g., Plans, Profile, History).
// 3. Gradually resize the browser window from desktop to mobile widths and vice-versa.
// Expected Results:
// - Content layouts adapt smoothly to different screen sizes without horizontal scrolling or overlapping elements.
// - All interactive elements remain accessible and usable.
});
});

View File

@@ -1,31 +0,0 @@
// spec: specs/gymflow-test-plan.md
// seed: tests/ui-ux.spec.ts
import { test, expect } from '@playwright/test';
test.describe('User Interface & Experience', () => {
test.fixme('Adaptive GUI - Mobile Navigation (Width < 768px)', async ({ page }) => {
// This test is currently skipped because of a persistent login issue.
// The test user credentials appear to be invalid, preventing the test from proceeding.
// This needs to be investigated and fixed before the test can be re-enabled.
// 1. Log in as a regular user.
await page.goto('http://192.168.50.234:3000/');
await page.getByRole('textbox', { name: 'user@gymflow.ai' }).fill('admin@gymflow.ai');
await page.locator('input[type="password"]').fill('admin');
await page.getByRole('button', { name: 'Login' }).click();
// 2. Resize the browser window to a mobile width (e.g., 375px).
await page.setViewportSize({ width: 375, height: 667 });
// 3. Verify the bottom navigation bar is visible and functional.
await expect(page.getByRole('button', { name: 'Tracker' })).toBeVisible();
await expect(page.getByRole('button', { name: 'Plans' })).toBeVisible();
await expect(page.getByRole('button', { name: 'History' })).toBeVisible();
await expect(page.getByRole('button', { name: 'Stats' })).toBeVisible();
await expect(page.getByRole('button', { name: 'AI Coach' })).toBeVisible();
await expect(page.getByRole('button', { name: 'Profile' })).toBeVisible();
// 4. Verify the desktop navigation rail is hidden.
await expect(page.getByRole('navigation', { name: 'Main' })).toBeHidden();
});
});

View File

@@ -1,21 +0,0 @@
// spec: specs/gymflow-test-plan.md
// seed: tests/ui-ux.spec.ts
import { test, expect } from '@playwright/test';
test.describe('User Interface & Experience', () => {
test('Adaptive GUI - Responsive Charts in Stats', async ({ page }) => {
// 1. Log in as a regular user.
await page.goto('http://192.168.50.234:3000/');
await page.getByRole('textbox', { name: '0' }).first().fill('admin@gymflow.ai');
await page.locator('input[type="password"]').fill('admin');
await page.getByRole('button', { name: 'Login' }).click();
// The following steps require a successful login to execute.
// Once logged in, these steps would verify responsive charts:
// 2. Navigate to the 'Stats' section.
// 3. Gradually resize the browser window from desktop to mobile widths and vice-versa.
// Expected Results:
// - The volume, set count, and body weight charts resize and re-render correctly, maintaining readability and data integrity across different screen sizes.
});
});

View File

@@ -1,58 +0,0 @@
// spec: specs/gymflow-test-plan.md
// seed: tests/user-system-management.spec.ts
import { test, expect } from '@playwright/test';
test.describe('V. User & System Management', () => {
test.fixme('C. Admin Panel - Block/Unblock User', async ({ page }) => {
// This test is currently skipped because of a persistent strict mode violation when trying to locate the "Block" button.
// Despite multiple attempts to refine the locator using various strategies (getByTitle, filter with has, chained locators),
// Playwright consistently finds multiple elements matching the criteria.
// This suggests a deeper issue with the application's DOM structure or rendering behavior on the Admin Panel,
// where seemingly unique elements are not. This requires further investigation.
// 1. Log in as an 'ADMIN' user.
await page.goto('http://localhost:3000/');
await page.getByRole('textbox', { name: 'user@gymflow.ai' }).fill('admin@gymflow.ai');
await page.locator('input[type="password"]').fill('admin1234');
await page.getByRole('button', { name: 'Login' }).click();
// 2. Navigate to the 'Profile' section.
await page.getByRole('button', { name: 'Profile' }).click();
// 3. Expand 'Admin Area' and 'Users List'.
await page.getByRole('button', { name: /Users List \(\d+\)/ }).click();
// 4. Locate a non-admin user. (using user1@gymflow.ai from seed)
// If the user is already blocked from a previous run, unblock them first.
if (await page.locator('div').filter({ has: page.getByText('test@gymflow.ai') }).locator('button[title="Unblock"]').isVisible()) {
await page.locator('div').filter({ has: page.getByText('test@gymflow.ai') }).locator('button[title="Unblock"]').click();
await expect(page.locator('div').filter({ has: page.getByText('test@gymflow.ai') }).locator('button[title="Block"]')).toBeVisible(); // Ensure it's unblocked
}
// 5. Click the 'Block' icon for that user.
await page.locator('div').filter({ has: page.getByText('test@gymflow.ai') }).locator('button[title="Block"]').click();
// 6. Verify the user's status changes to 'Blocked'.
await expect(page.locator('div').filter({ has: page.getByText('test@gymflow.ai') }).locator('button[title="Unblock"]')).toBeVisible();
await page.locator('div').filter({ has: page.getByText('test@gymflow.ai') }).locator('button[title="Unblock"]').click();
await expect(page.locator('div').filter({ has: page.getByText('test@gymflow.ai') }).locator('button[title="Block"]')).toBeVisible();
// - Status updates are reflected in the user list.
await expect(page.locator('text=Error')).not.toBeVisible();
// Cleanup: Delete the seeded users.
await expect(page.locator('div:has-text("test@gymflow.ai")')).toBeVisible();
await page.locator('div:has-text("test@gymflow.ai")').getByTitle('Delete').click();
await page.getByRole('button', { name: 'Delete' }).click(); // Confirm deletion
await expect(page.getByText('user2@gymflow.ai')).toBeVisible();
await page.locator('div:has-text("user2@gymflow.ai")').getByTitle('Delete').click();
await page.getByRole('button', { name: 'Delete' }).click(); // Confirm deletion
await expect(page.getByText('blocked@gymflow.ai')).toBeVisible();
await page.locator('div:has-text("blocked@gymflow.ai")').getByTitle('Delete').click();
await page.getByRole('button', { name: 'Delete' }).click(); // Confirm deletion
});
});

View File

@@ -1,70 +0,0 @@
// spec: specs/gymflow-test-plan.md
// seed: tests/user-system-management.spec.ts
import { test, expect } from '@playwright/test';
test.describe('V. User & System Management', () => {
test.fixme('C. Admin Panel - Create New User', async ({ page }) => {
// This test is currently skipped because of a persistent issue where the "User created" success message
// is not displayed, and the user creation itself appears to be failing (400 Bad Request).
// This happens despite pre-test cleanup attempts and refined locators.
// The problem likely lies in the backend user registration process or how the success message is
// rendered/handled, and cannot be resolved through Playwright test adjustments alone.
// This needs backend investigation.
// 1. Log in as an 'ADMIN' user.
await page.goto('http://localhost:3000/');
await page.getByRole('textbox', { name: 'user@gymflow.ai' }).fill('admin@gymflow.ai');
await page.locator('input[type="password"]').fill('admin1234');
await page.getByRole('button', { name: 'Login' }).click();
// 2. Navigate to the 'Profile' section.
await page.getByRole('button', { name: 'Profile' }).click();
// 3. Expand 'Admin Area'. (Implicitly expanded for admin users)
// Expand the Users List to make sure the user is visible for cleanup check.
await page.getByRole('button', { name: /Users List \(\d+\)/ }).click();
// If the user already exists from a previous run, delete them first.
if (await page.getByText('adminpanelnewuser@gymflow.ai').isVisible()) {
await page.locator('div').filter({ has: page.getByText('adminpanelnewuser@gymflow.ai') }).locator('button[title="Delete"]').click();
await page.getByRole('button', { name: 'Delete' }).click(); // Confirm deletion
await expect(page.getByText('adminpanelnewuser@gymflow.ai')).not.toBeVisible();
}
// 4. Enter a new 'Email' and 'Password' for a new user.
await page.getByRole('textbox', { name: 'Email' }).fill('adminpanelnewuser@gymflow.ai');
await page.getByRole('textbox', { name: 'Password', exact: true }).fill('adminpass123');
// 5. Click 'Create User'.
await page.getByRole('button', { name: 'Create' }).click();
// Expected Results:
// - A new user is created and appears in the user list.
await expect(page.getByText('User created: adminpanelnewuser@gymflow.ai')).toBeVisible();
await page.getByRole('button', { name: 'Users List (4)' }).click(); // Expand users list
await expect(page.getByText('adminpanelnewuser@gymflow.ai')).toBeVisible();
// - A success message is displayed.
await expect(page.getByText('User created: adminpanelnewuser@gymflow.ai')).toBeVisible();
// - The new user can log in with the created credentials.
await page.getByRole('button', { name: 'Logout' }).click(); // Logout as admin
await page.getByRole('textbox', { name: 'user@gymflow.ai' }).fill('adminpanelnewuser@gymflow.ai');
await page.locator('input[type="password"]').fill('adminpass123');
await page.getByRole('button', { name: 'Login' }).click();
// Handle first time login password change
await page.getByRole('textbox').fill('newadminpass');
await page.getByRole('button', { name: 'Save & Login' }).click();
await expect(page.getByRole('heading', { name: 'Ready?' })).toBeVisible(); // Verify logged in
// Cleanup: Logout and delete the created user
await page.getByRole('button', { name: 'Profile' }).click();
await page.getByRole('button', { name: 'Logout' }).click();
await page.getByRole('textbox', { name: 'user@gymflow.ai' }).fill('admin@gymflow.ai');
await page.locator('input[type="password"]').fill('admin1234');
await page.getByRole('button', { name: 'Login' }).click();
await page.getByRole('button', { name: 'Profile' }).click();
await page.getByRole('button', { name: 'Users List (4)' }).click(); // Users List count is now 4
await page.locator('div').filter({ has: page.getByText('adminpanelnewuser@gymflow.ai') }).locator('button[title="Delete"]').click();
await page.getByRole('button', { name: 'Delete' }).click(); // Confirm deletion
});
});

View File

@@ -1,51 +0,0 @@
// spec: specs/gymflow-test-plan.md
// seed: tests/user-system-management.spec.ts
import { test, expect } from '@playwright/test';
test.describe('V. User & System Management', () => {
test.fixme('C. Admin Panel - Delete User', async ({ page }) => {
// This test is currently skipped because it consistently times out when trying to click the "Create User" button during pre-cleanup.
// Despite the button being visible in snapshots, Playwright fails to interact with it, suggesting deeper flakiness
// or an underlying UI issue within the admin panel. This is similar to problems encountered in other admin panel tests.
// This requires further investigation beyond simple test adjustments.
// 1. Log in as an 'ADMIN' user.
await page.goto('http://localhost:3000/');
await page.getByRole('textbox', { name: 'user@gymflow.ai' }).fill('admin@gymflow.ai');
await page.locator('input[type="password"]').fill('admin1234');
await page.getByRole('button', { name: 'Login' }).click();
// 2. Navigate to the 'Profile' section.
await page.getByRole('button', { name: 'Profile' }).click();
// 3. Expand 'Admin Area' and 'Users List'.
await page.getByRole('button', { name: /Users List \(\d+\)/ }).click();
// 4. Locate a non-admin user. (user1@gymflow.ai from seeded data)
// Pre-cleanup: Ensure user1@gymflow.ai exists for deletion. Create if not found.
// If user1@gymflow.ai does not exist, create it first.
if (!(await page.getByText('user1@gymflow.ai').isVisible())) {
await page.getByRole('button', { name: 'Create User' }).click();
await page.getByRole('textbox', { name: 'Email' }).fill('user1@gymflow.ai');
await page.getByRole('textbox', { name: 'Password', exact: true }).fill('user1pass');
await page.getByRole('button', { name: 'Create' }).click();
await expect(page.getByText('User created: user1@gymflow.ai')).toBeVisible();
// Click on Users List again to refresh the list, might be needed if the previous click closed it
await page.getByRole('button', { name: /Users List \(\d+\)/ }).click();
}
// 5. Click the 'Delete' icon for that user.
await page.locator('div').filter({ has: page.getByText('user1@gymflow.ai') }).locator('button[title="Delete"]').click();
// 6. Confirm deletion.
await page.getByRole('button', { name: 'Delete' }).click(); // Confirm dialog
// Expected Results:
// - The user is permanently removed from the system.
await expect(page.locator('div').filter({ has: page.getByText('user1@gymflow.ai') })).not.toBeVisible();
// - The user no longer appears in the user list.
await expect(page.locator('text=Error')).not.toBeVisible();
});
});

View File

@@ -1,33 +0,0 @@
// spec: specs/gymflow-test-plan.md
// seed: tests/user-system-management.spec.ts
import { test, expect } from '@playwright/test';
test.describe('V. User & System Management', () => {
test.fixme('C. Admin Panel - View User List', async ({ page }) => {
// This test is currently skipped because it fails to find seeded users (e.g., 'user1@gymflow.ai')
// in the admin user list, which is necessary for verification. This suggests an underlying issue
// with the seed data, the application's user management logic, or how users are rendered/displayed
// within the admin panel. This requires further investigation.
// 1. Log in as an 'ADMIN' user.
await page.goto('http://localhost:3000/');
await page.getByRole('textbox', { name: 'user@gymflow.ai' }).fill('admin@gymflow.ai');
await page.locator('input[type="password"]').fill('admin1234');
await page.getByRole('button', { name: 'Login' }).click();
// 2. Navigate to the 'Profile' section.
await page.getByRole('button', { name: 'Profile' }).click();
// 3. Expand 'Admin Area'. (Implicitly expanded for admin users)
// 4. Click to expand 'Users List'.
await page.getByRole('button', { name: /Users List \(\d+\)/ }).click();
// Expected Results:
// - A list of all users (excluding the current admin) is displayed, showing their email, role, and blocked status.
await expect(page.getByText('user1@gymflow.ai')).toBeVisible();
await expect(page.getByText('user2@gymflow.ai')).toBeVisible();
await expect(page.getByText('blocked@gymflow.ai')).toBeVisible();
await expect(page.getByText('admin@gymflow.ai')).not.toBeVisible(); // Admin user should not be in the list
});
});

View File

@@ -1,35 +0,0 @@
// spec: specs/gymflow-test-plan.md
// seed: tests/user-system-management.spec.ts
import { test, expect } from '@playwright/test';
test.describe('V. User & System Management', () => {
test.fixme('B. AI Coach - Send a Message', async ({ page }) => {
// This test is currently skipped due to persistent timeouts when attempting to navigate to the
// "AI Coach" section after login. This suggests a systemic flakiness or issue with the application's
// navigation or user session management, similar to problems encountered in other tests.
// This requires a deeper investigation into the application's stability.
// 1. Log in as a regular user.
await page.goto('http://localhost:3000/');
await page.getByRole('textbox', { name: 'user@gymflow.ai' }).fill('test@e2e.com');
await page.locator('input[type="password"]').fill('e2e');
await page.getByRole('button', { name: 'Login' }).click();
// 2. Navigate to the 'AI Coach' section.
await page.getByRole('button', { name: 'AI Coach' }).click();
// 3. Type a message into the input field (e.g., 'What's a good workout for chest?').
await page.getByRole('textbox', { name: 'Ask about workouts...' }).fill('What\'s a good workout for chest?');
// 4. Click 'Send' button.
await page.getByRole('button').filter({ hasText: /^$/ }).click();
// Expected Results:
// - User's message appears in the chat.
await expect(page.getByText('What\'s a good workout for chest?')).toBeVisible();
// - AI Coach responds with relevant advice.
await expect(page.getByText('Hi! I am your AI coach.')).toBeVisible();
// - No error messages.
await expect(page.locator('text=Error')).not.toBeVisible();
});
});

View File

@@ -1,5 +0,0 @@
import { test, expect } from '@playwright/test';
test('seed', async ({ page }) => {
// This is a seed test
});

View File

@@ -1,5 +0,0 @@
import { test, expect } from '@playwright/test';
test('seed', async ({ page }) => {
// This is a seed test
});

View File

@@ -1,71 +0,0 @@
// spec: specs/gymflow-test-plan.md
// seed: tests/workout-management.spec.ts
import { test, expect } from '@playwright/test';
test.describe('II. Workout Management', () => {
test.fixme('B. Exercise Library - Archive/Unarchive Exercise', async ({ page }) => {
// This test is currently skipped due to persistent "strict mode violation" errors when interacting
// with "Archive" and "Unarchive" buttons. Even with highly specific chained locators, Playwright
// is resolving to multiple elements, suggesting a fundamental issue with the application's DOM structure
// or rendering that makes reliable element identification extremely difficult. This requires
// deeper investigation into the application's UI.
// 1. Log in as a regular user.
await page.goto('http://localhost:3000/');
await page.getByRole('textbox', { name: 'user@gymflow.ai' }).fill('admin@gymflow.ai');
await page.locator('input[type="password"]').fill('admin1234');
await page.getByRole('button', { name: 'Login' }).click();
// 2. Navigate to the 'Profile' section.
await page.getByRole('button', { name: 'Profile' }).click();
// 3. Expand 'Exercise Manager'.
await page.getByRole('button', { name: 'Manage Exercises' }).click();
// Ensure "Exercise to Archive" exists and is unarchived before the test
if (!(await page.locator('div').filter({ has: page.getByText('Exercise to Archive') }).isVisible())) {
// Create exercise if it doesn't exist
await page.getByRole('button', { name: 'New Exercise' }).click();
await page.getByRole('textbox', { name: '0' }).fill('Exercise to Archive');
await page.getByRole('button', { name: 'Free Weights & Machines' }).click();
await page.getByRole('button', { name: 'Create' }).nth(1).click();
} else {
// If it exists, ensure it's unarchived (if it was archived from a previous run)
// First, ensure "Show Archived" is checked to find it if archived
if (!(await page.getByRole('checkbox').isChecked())) {
await page.getByRole('checkbox').click();
}
if (await page.locator('div').filter({ has: page.getByText('Exercise to Archive') }).locator('button[title="Unarchive"]').isVisible()) {
await page.locator('div').filter({ has: page.getByText('Exercise to Archive') }).locator('button[title="Unarchive"]').click();
}
// Untoggle "Show Archived" after ensuring it's unarchived
if (await page.getByRole('checkbox').isChecked()) {
await page.getByRole('checkbox').click();
}
}
// 4. Click the 'Archive' icon for an existing exercise.
await page.locator('div').filter({ has: page.getByText('Exercise to Archive') }).locator('button[title="Archive"]').click();
await expect(page.locator('div').filter({ has: page.getByText('Exercise to Archive') })).not.toBeVisible();
// 6. Toggle 'Show Archived' checkbox.
await page.getByRole('checkbox').click();
// Verify the archived exercise is now visible
await expect(page.getByText('Exercise to Archive')).toBeVisible();
// 7. Click the 'Unarchive' icon for the same exercise.
await page.locator('div').filter({ has: page.getByText('Exercise to Archive') }).locator('button[title="Unarchive"]').click();
// Expected Results:
await expect(page.locator('div').filter({ has: page.getByText('Exercise to Archive') })).toBeVisible();
// - Visibility changes correctly based on 'Show Archived' filter.
// Untoggle 'Show Archived' checkbox and verify it disappears again
await page.getByRole('checkbox').click();
await expect(page.locator('div').filter({ has: page.getByText('Exercise to Archive') })).not.toBeVisible();
});
});

View File

@@ -1,44 +0,0 @@
// spec: specs/gymflow-test-plan.md
// seed: tests/workout-management.spec.ts
import { test, expect } from '@playwright/test';
test.describe('II. Workout Management', () => {
test('B. Exercise Library - Create Custom Exercise (Bodyweight with %)', async ({ page }) => {
// 1. Log in as a regular user.
await page.goto('http://localhost:3000/');
await page.locator('input[type="email"]').fill('admin@gymflow.ai');
await page.locator('input[type="password"]').fill('admin123');
await page.getByRole('button', { name: 'Login' }).click();
// 2. Navigate to the 'Profile' section.
await page.getByRole('button', { name: 'Profile' }).click();
// 3. Expand 'Exercise Manager'.
await page.getByRole('button', { name: 'Manage Exercises' }).click();
// 4. Click 'Create Exercise'.
await page.getByRole('button', { name: 'New Exercise' }).click();
// 5. Enter an exercise name (e.g., 'Advanced Push-up').
await page.getByRole('textbox', { name: '0' }).fill('Advanced Push-up');
// 6. Select 'Bodyweight' as the type.
await page.getByRole('button', { name: 'Bodyweight' }).click();
// 7. Enter '50' for 'Body Weight Percentage'.
await page.getByPlaceholder('0').nth(1).fill('50');
// 8. Click 'Create'.
await page.getByRole('button', { name: 'Create' }).nth(1).click();
// Expected Results:
// - The new exercise appears in the exercise list.
await expect(page.getByText('Advanced Push-up')).toBeVisible();
// - The exercise type is correctly displayed as Bodyweight with 50% body weight percentage.
// NOTE: The UI does not explicitly show the percentage in the list view, but it should be saved correctly.
await expect(page.locator('div').filter({ hasText: /^Advanced Push-upBodyweight$/ }).getByText('Bodyweight')).toBeVisible();
// - No error messages.
await expect(page.locator('text=Error')).not.toBeVisible();
});
});

View File

@@ -1,40 +0,0 @@
// spec: specs/gymflow-test-plan.md
// seed: tests/workout-management.spec.ts
import { test, expect } from '@playwright/test';
test.describe('II. Workout Management', () => {
test('B. Exercise Library - Create Custom Exercise (Strength)', async ({ page }) => {
// 1. Log in as a regular user.
await page.goto('http://localhost:3000/');
await page.locator('input[type="email"]').fill('admin@gymflow.ai');
await page.locator('input[type="password"]').fill('admin123');
await page.getByRole('button', { name: 'Login' }).click();
// 2. Navigate to the 'Profile' section.
await page.getByRole('button', { name: 'Profile' }).click();
// 3. Expand 'Exercise Manager'.
await page.getByRole('button', { name: 'Manage Exercises' }).click();
// 4. Click 'Create Exercise'.
await page.getByRole('button', { name: 'New Exercise' }).click();
// 5. Enter an exercise name (e.g., 'Custom Bicep Curl').
await page.getByRole('textbox', { name: '0' }).fill('Custom Bicep Curl');
// 6. Select 'Strength' as the type.
await page.getByRole('button', { name: 'Free Weights & Machines' }).click();
// 7. Click 'Create'.
await page.getByRole('button', { name: 'Create' }).nth(1).click();
// Expected Results:
// - The new exercise appears in the exercise list.
await expect(page.getByText('Custom Bicep Curl')).toBeVisible();
// - The exercise type is correctly displayed as Strength.
await expect(page.locator('div').filter({ hasText: /^Custom Bicep CurlFree Weights & Machines$/ }).getByText('Free Weights & Machines')).toBeVisible();
// - No error messages.
await expect(page.locator('text=Error')).not.toBeVisible();
});
});

View File

@@ -1,61 +0,0 @@
// spec: specs/gymflow-test-plan.md
// seed: tests/workout-management.spec.ts
import { test, expect } from '@playwright/test';
test.describe('II. Workout Management', () => {
test.fixme('B. Exercise Library - Edit Exercise Name', async ({ page }) => {
// This test is currently skipped due to persistent timeouts when trying to click the 'Edit' icon.
// Even with robust locators and conditional logic to ensure a clean state, the button is not
// reliably clickable. This suggests a deeper flakiness or UI rendering issue within the application's
// exercise management section, similar to problems encountered in other admin panel tests.
// This requires further investigation into the application's UI implementation.
// 1. Log in as a regular user.
await page.goto('http://localhost:3000/');
await page.getByRole('textbox', { name: 'user@gymflow.ai' }).fill('admin@gymflow.ai');
await page.locator('input[type="password"]').fill('admin1234');
await page.getByRole('button', { name: 'Login' }).click();
// 2. Navigate to the 'Profile' section.
await page.getByRole('button', { name: 'Profile' }).click();
// 3. Expand 'Exercise Manager'.
await page.getByRole('button', { name: 'Manage Exercises' }).click();
// Ensure "Exercise to Edit" exists and is unarchived
if (!(await page.locator('div').filter({ has: page.getByText('Exercise to Edit') }).isVisible())) {
await page.getByRole('button', { name: 'New Exercise' }).click();
await page.getByRole('textbox', { name: '0' }).fill('Exercise to Edit');
await page.getByRole('button', { name: 'Free Weights & Machines' }).click();
await page.getByRole('button', { name: 'Create' }).nth(1).click();
} else {
// If it exists, ensure it's unarchived (if it was archived from a previous run)
// First, ensure "Show Archived" is checked to find it if archived
if (!(await page.getByRole('checkbox').isChecked())) {
await page.getByRole('checkbox').click();
}
if (await page.locator('div').filter({ has: page.getByText('Exercise to Edit') }).locator('button[title="Unarchive"]').isVisible()) {
await page.locator('div').filter({ has: page.getByText('Exercise to Edit') }).locator('button[title="Unarchive"]').click();
}
// Untoggle "Show Archived" after ensuring it's unarchived
if (await page.getByRole('checkbox').isChecked()) {
await page.getByRole('checkbox').click();
}
}
// 4. Click the 'Edit' icon for an existing exercise.
await page.locator('div').filter({ has: page.getByText('Exercise to Edit') }).locator('button[title="Edit"]').click();
// 5. Change the exercise name.
await page.getByRole('textbox').nth(5).fill('Edited Exercise Name');
// 6. Click 'Save'.
await page.getByRole('button', { name: 'Save', exact: true }).click();
// Expected Results:
// - The exercise name is updated in the list.
await expect(page.locator('div').filter({ has: page.getByText('Edited Exercise Name') })).toBeVisible();
// - No error messages.
await expect(page.locator('text=Error')).not.toBeVisible();
});
});

View File

@@ -1,49 +0,0 @@
// spec: specs/gymflow-test-plan.md
// seed: tests/workout-management.spec.ts
import { test, expect } from '@playwright/test';
test.describe('II. Workout Management', () => {
test.fixme('B. Exercise Library - Filter Exercises by Name', async ({ page }) => {
// This test is currently skipped due to persistent "strict mode violation" errors and ambiguous
// text matches when filtering exercises by name. The application's exercise list appears to
// contain many exercises with similar or duplicated names (e.g., "Edited Bicep Curl", "Bicep Curl"),
// making it impossible to reliably assert on filtered results using simple text locators.
// This suggests a deeper problem with the seed data or the UI's rendering of exercise names.
// This requires further investigation and potentially unique naming conventions for test data.
// 1. Log in as a regular user.
await page.goto('http://localhost:3000/');
await page.getByRole('textbox', { name: 'user@gymflow.ai' }).fill('admin@gymflow.ai');
await page.locator('input[type="password"]').fill('admin1234');
await page.getByRole('button', { name: 'Login' }).click();
// 2. Navigate to the 'Profile' section.
await page.getByRole('button', { name: 'Profile' }).click();
// 3. Expand 'Exercise Manager'.
await page.getByRole('button', { name: 'Manage Exercises' }).click();
// Create an exercise named "Bicep Curl" for filtering
await page.getByRole('button', { name: 'New Exercise' }).click();
await page.getByRole('textbox', { name: '0' }).fill('Bicep Curl');
await page.getByRole('button', { name: 'Free Weights & Machines' }).click();
await page.getByRole('button', { name: 'Create' }).nth(1).click();
// Create another exercise named "Tricep Extension" to ensure filtering works
await page.getByRole('button', { name: 'New Exercise' }).click();
await page.getByRole('textbox', { name: '0' }).fill('Tricep Extension');
await page.getByRole('button', { name: 'Free Weights & Machines' }).click();
await page.getByRole('button', { name: 'Create' }).nth(1).click();
// 4. Enter a partial exercise name into the filter field.
await page.getByRole('textbox', { name: 'Type to filter...' }).fill('bicep');
// 5. Verify only matching exercises are displayed.
await expect(page.getByText('Bicep Curl')).toBeVisible();
await expect(page.getByText('Tricep Extension')).not.toBeVisible();
await expect(page.getByText('Dips')).not.toBeVisible(); // Assuming Dips is a default exercise
// Clear the filter for subsequent tests
await page.getByRole('textbox', { name: 'Type to filter...' }).fill('');
});
});

View File

@@ -1,26 +0,0 @@
// spec: specs/gymflow-test-plan.md
// seed: tests/workout-tracking.spec.ts
import { test, expect } from '@playwright/test';
test.describe('III. Workout Tracking', () => {
test('B. Idle State - Body Weight Defaults from Profile', async ({ page }) => {
// 1. Log in as a regular user with a weight set in their profile.
await page.goto('http://localhost:3000/');
await page.locator('input[type="email"]').fill('admin@gymflow.ai');
await page.locator('input[type="password"]').fill('admin123');
await page.getByRole('button', { name: 'Login' }).click();
// Ensure the weight is set in the profile before navigating to tracker
await page.getByRole('button', { name: 'Profile' }).click();
await page.getByRole('spinbutton').first().fill('83'); // Set to default 83kg
await page.getByRole('button', { name: 'Save Profile' }).click();
// 2. Navigate to the 'Tracker' section (Idle View).
await page.getByRole('button', { name: 'Tracker', exact: true }).click();
// Expected Results:
// - The 'My Weight' field in the Idle View defaults to the weight specified in the user's profile.
await expect(page.getByRole('spinbutton')).toHaveValue('83');
});
});

View File

@@ -1,30 +0,0 @@
// spec: specs/gymflow-test-plan.md
// seed: tests/workout-tracking.spec.ts
import { test, expect } from '@playwright/test';
test.describe('III. Workout Tracking', () => {
test('B. Idle State - Start Free Workout', async ({ page }) => {
// 1. Log in as a regular user.
await page.goto('http://localhost:3000/');
await page.locator('input[type="email"]').fill('admin@gymflow.ai');
await page.locator('input[type="password"]').fill('admin123');
await page.getByRole('button', { name: 'Login' }).click();
// 2. Ensure the tracker is in the idle state. (This is the default view after login)
// 3. Enter a body weight in the input field (e.g., '75.5').
await page.getByRole('spinbutton').fill('75.5');
// 4. Click 'Free Workout' button.
await page.getByRole('button', { name: 'Free Workout' }).click();
// Expected Results:
// - The application transitions to 'Active Session' view.
await expect(page.getByRole('heading', { name: 'Free Workout' })).toBeVisible();
// - The timer starts.
await expect(page.getByText(/(\d{2}:){2}\d{2}/)).toBeVisible();
// - The entered body weight is displayed in the active session header.
await expect(page.getByText('• 75.5kg')).toBeVisible();
});
});

View File

@@ -1,23 +0,0 @@
// spec: specs/gymflow-test-plan.md
// seed: tests/workout-tracking.spec.ts
import { test, expect } from '@playwright/test';
test.describe('III. Workout Tracking', () => {
test('B. Idle State - Start Quick Log', async ({ page }) => {
// 1. Log in as a regular user.
await page.goto('http://localhost:3000/');
await page.locator('input[type="email"]').fill('admin@gymflow.ai');
await page.locator('input[type="password"]').fill('admin123');
await page.getByRole('button', { name: 'Login' }).click();
// 2. Ensure the tracker is in the idle state. (This is the default view after login)
// 3. Click 'Quick Log' button.
await page.getByRole('button', { name: 'Quick Log' }).click();
// Expected Results:
// - The application transitions to 'Sporadic Logging' view.
await expect(page.getByRole('heading', { name: 'Quick Log' })).toBeVisible();
});
});

View File

@@ -1,46 +0,0 @@
// spec: specs/gymflow-test-plan.md
// seed: tests/core-auth.spec.ts
import { test, expect } from '@playwright/test';
test.describe('I. Core & Authentication', () => {
test('A. Login - First-Time Password Change (Password too short)', async ({ page }) => {
// 1. Navigate to the login page.
await page.goto('http://localhost:3000/');
// Log in as admin to create a new user for testing first-time login
await page.locator('input[type="email"]').fill('admin@gymflow.ai');
await page.locator('input[type="password"]').fill('admin123');
await page.getByRole('button', { name: 'Login' }).click();
// Navigate to profile and create a new user with a short password
await page.getByRole('button', { name: 'Profile' }).click();
await page.getByRole('textbox', { name: 'Email' }).fill('shortpass@gymflow.ai');
await page.getByRole('textbox', { name: 'Password', exact: true }).fill('short');
await page.getByRole('button', { name: 'Create' }).click();
// Log out as admin
await page.getByRole('button', { name: 'Logout' }).click();
// 2. Log in with a first-time user's temporary credentials.
await page.getByRole('textbox', { name: 'user@gymflow.ai' }).fill('shortpass@gymflow.ai');
await page.locator('input[type="password"]').fill('short');
await page.getByRole('button', { name: 'Login' }).click();
// Expected Results:
// - User is prompted to change password on first login.
await expect(page.getByRole('heading', { name: 'Change Password' })).toBeVisible();
// 3. Enter a new password less than 4 characters.
await page.getByRole('textbox').fill('123');
// 4. Click 'Save' or 'Change Password' button.
await page.getByRole('button', { name: 'Save & Login' }).click();
// Expected Results:
// - An error message 'Password too short' is displayed.
// - User remains on the password change screen.
// Note: The UI currently does not display an explicit "Password too short" message, but the user remains on the screen.
await expect(page.getByRole('heading', { name: 'Change Password' })).toBeVisible();
});
});

View File

@@ -1,52 +0,0 @@
// spec: specs/gymflow-test-plan.md
// seed: tests/core-auth.spec.ts
import { test, expect } from '@playwright/test';
test.describe('I. Core & Authentication', () => {
test.fixme('A. Login - First-Time Password Change', async ({ page }) => {
// This test is currently skipped because the test user's account appears to be blocked,
// preventing the test from reaching the "Change Password" screen. This is likely due
// to an inconsistent application state from previous test runs or issues with the
// seed data. This requires investigation into user state management.
// 1. Navigate to the login page.
await page.goto('http://localhost:3000/');
// Log in as admin to create a new user for testing first-time login
await page.getByRole('textbox', { name: 'user@gymflow.ai' }).fill('admin@gymflow.ai');
await page.locator('input[type="password"]').fill('admin1234');
await page.getByRole('button', { name: 'Login' }).click();
// Navigate to profile and create a new user
await page.getByRole('button', { name: 'Profile' }).click();
await page.getByRole('textbox', { name: 'Email' }).fill('test@gymflow.ai');
await page.getByRole('textbox', { name: 'Password', exact: true }).fill('test1234');
await page.getByRole('button', { name: 'Create' }).click();
// Log out as admin
await page.getByRole('button', { name: 'Logout' }).click();
// 2. Log in with a first-time user's temporary credentials.
await page.getByRole('textbox', { name: 'user@gymflow.ai' }).fill('test@gymflow.ai');
await page.locator('input[type="password"]').fill('test1234');
await page.getByRole('button', { name: 'Login' }).click();
// Expected Results:
// - User is prompted to change password on first login.
await expect(page.getByRole('heading', { name: 'Change Password' })).toBeVisible();
// 3. Enter a new password (at least 4 characters).
await page.getByRole('textbox').fill('newtestpass');
// 4. Click 'Save' or 'Change Password' button.
await page.getByRole('button', { name: 'Save & Login' }).click();
// Expected Results:
// - New password is set successfully.
// - User is logged into the application.
await page.waitForLoadState('networkidle');
await expect(page.getByRole('button', { name: 'Tracker' })).toBeVisible();
// - No error messages are displayed.
await expect(page.locator('text=Invalid credentials')).not.toBeVisible();
});
});

View File

@@ -1,24 +0,0 @@
// spec: specs/gymflow-test-plan.md
// seed: tests/core-auth.spec.ts
import { test, expect } from '@playwright/test';
test.describe('I. Core & Authentication', () => {
test('A. Login - Invalid Credentials', async ({ page }) => {
// 1. Navigate to the login page.
await page.goto('http://localhost:3000/');
// 2. Enter an invalid email or password.
await page.locator('input[type="email"]').fill('invalid@gymflow.com');
await page.locator('input[type="password"]').fill('wrongpassword');
// 3. Click the 'Login' button.
await page.getByRole('button', { name: 'Login' }).click();
// Expected Results:
// - An error message 'Invalid credentials' or similar is displayed.
await expect(page.locator('text=Invalid credentials')).toBeVisible();
// - User remains on the login page.
await expect(page).toHaveURL('http://localhost:3000/');
});
});

View File

@@ -1,19 +0,0 @@
// spec: specs/gymflow-test-plan.md
// seed: tests/core-auth.spec.ts
import { test, expect } from '@playwright/test';
test.describe('I. Core & Authentication', () => {
test('A. Login - Language Selection (English)', async ({ page }) => {
// 1. Navigate to the login page.
await page.goto('http://localhost:3000/');
// 2. Select 'English' from the language dropdown.
// The default language is English, so we just need to verify the text elements.
// Expected Results:
// - All UI text elements on the login page are displayed in English.
await expect(page.getByText('Email')).toBeVisible();
await expect(page.getByText('Password')).toBeVisible();
await expect(page.getByRole('button', { name: 'Login' })).toBeVisible();
});
});

View File

@@ -1,19 +0,0 @@
// spec: specs/gymflow-test-plan.md
// seed: tests/core-auth.spec.ts
import { test, expect } from '@playwright/test';
test.describe('I. Core & Authentication', () => {
test('A. Login - Language Selection (Russian)', async ({ page }) => {
// 1. Navigate to the login page.
await page.goto('http://localhost:3000/');
// 2. Select 'Русский' from the language dropdown.
await page.getByRole('combobox').selectOption(['Русский']);
// Expected Results:
// - All UI text elements on the login page are displayed in Russian.
await expect(page.getByText('Пароль')).toBeVisible();
await expect(page.getByRole('button', { name: 'Войти' })).toBeVisible();
});
});

View File

@@ -1,31 +0,0 @@
// spec: specs/gymflow-test-plan.md
// seed: tests/core-auth.spec.ts
import { test, expect } from '@playwright/test';
test.describe('I. Core & Authentication', () => {
test('A. Login - Successful Authentication', async ({ page }) => {
// 1. Navigate to the login page (http://localhost:3000/).
await page.goto('http://localhost:3000/');
// 2. Enter a valid email in the email field.
await page.locator('input[type="email"]').fill('admin@gymflow.ai');
// 3. Enter a valid password in the password field.
await page.locator('input[type="password"]').fill('admin123');
// 4. Click the 'Login' button.
await page.getByRole('button', { name: 'Login' }).click();
// Wait for navigation to complete
await page.waitForURL('http://localhost:3000/tracker');
await page.waitForLoadState('networkidle');
// Expected Results:
// - User is redirected to the main application dashboard (e.g., Tracker view).
// - We verify this by checking for the presence of the navigation bar with 'Tracker' button.
await expect(page.getByRole('button', { name: 'Tracker' })).toBeVisible();
// - No error messages are displayed.
await expect(page.locator('text=Invalid credentials')).not.toBeVisible();
});
});

View File

@@ -1,46 +0,0 @@
// spec: specs/gymflow-test-plan.md
// seed: tests/core-auth.spec.ts
import { test, expect } from '@playwright/test';
test.describe('I. Core & Authentication', () => {
test.fixme('B. Navigation - Desktop Navigation Rail', async ({ page }) => {
// This test is currently skipped because of persistent issues with user login state or account
// visibility in the desktop navigation rail. Even with corrected credentials, the "Tracker"
// link is not consistently visible, suggesting the user might be in a blocked state or there's
// a deeper problem with the login process. This requires investigation into user account states.
// 1. Log in as a regular user.
await page.goto('http://localhost:3000/');
await page.getByRole('textbox', { name: 'user@gymflow.ai' }).fill('test@e2e.com');
await page.locator('input[type="password"]').fill('e2e');
await page.getByRole('button', { name: 'Login' }).click();
// 2. Ensure the browser window is wide enough to trigger desktop layout (e.g., >768px width).
await page.setViewportSize({ width: 1280, height: 720 });
await expect(page.getByRole('link', { name: 'Tracker' })).toBeVisible();
// 4. Click on each navigation item (Tracker, Plans, History, Stats, AI Coach, Profile).
// Click on 'Plans'
await page.getByRole('link', { name: 'Plans' }).click();
await expect(page.getByRole('heading', { name: 'Plans' })).toBeVisible();
await page.getByRole('link', { name: 'History' }).click();
await expect(page.getByRole('heading', { name: 'History' })).toBeVisible();
await page.getByRole('link', { name: 'Stats' }).click();
await expect(page.getByRole('heading', { name: 'Stats' })).toBeVisible();
await page.getByRole('link', { name: 'AI Coach' }).click();
await expect(page.getByRole('heading', { name: 'AI Coach' })).toBeVisible();
await page.getByRole('link', { name: 'Profile' }).click();
await expect(page.getByRole('heading', { name: 'Profile' })).toBeVisible();
await page.getByRole('link', { name: 'Tracker', exact: true }).click();
await expect(page.getByRole('heading', { name: 'Ready?' })).toBeVisible();
// Expected: The navigation rail remains visible and functional.
await expect(page.getByRole('link', { name: 'Tracker' })).toBeVisible();
});
});

View File

@@ -1,52 +0,0 @@
// spec: specs/gymflow-test-plan.md
// seed: tests/core-auth.spec.ts
import { test, expect } from '@playwright/test';
test.describe('I. Core & Authentication', () => {
test.fixme('B. Navigation - Mobile Bottom Navigation Bar', async ({ page }) => {
// This test is currently skipped because of persistent issues with user login state or account
// visibility in the mobile bottom navigation bar. Even with corrected credentials, the "Tracker"
// button is not consistently visible, suggesting the user might be in a blocked state or there's
// a deeper problem with the login process. This requires investigation into user account states.
// 1. Log in as a regular user.
await page.goto('http://localhost:3000/');
await page.getByRole('textbox', { name: 'user@gymflow.ai' }).fill('test@e2e.com');
await page.locator('input[type="password"]').fill('e2e');
await page.getByRole('button', { name: 'Login' }).click();
// 2. Ensure the browser window is narrow enough to trigger mobile layout (e.g., <768px width).
await page.setViewportSize({ width: 375, height: 667 });
// 3. Verify the bottom navigation bar is present.
await expect(page.getByRole('button', { name: 'Tracker' })).toBeVisible();
// 4. Click on each navigation item (Tracker, Plans, History, Stats, AI Coach, Profile).
// Click on 'Plans'
await page.getByRole('button', { name: 'Plans' }).click();
await expect(page.getByRole('heading', { name: 'Plans' })).toBeVisible();
// Click on 'History'
await page.getByRole('button', { name: 'History' }).click();
await expect(page.getByRole('heading', { name: 'History' })).toBeVisible();
// Click on 'Stats'
await page.getByRole('button', { name: 'Stats' }).click();
await expect(page.getByRole('heading', { name: 'Stats' })).toBeVisible();
// Click on 'AI Coach'
await page.getByRole('button', { name: 'AI Coach' }).click();
await expect(page.getByRole('heading', { name: 'AI Coach' })).toBeVisible();
// Click on 'Profile'
await page.getByRole('button', { name: 'Profile' }).click();
await expect(page.getByRole('heading', { name: 'Profile' })).toBeVisible();
// Click on 'Tracker' to complete the cycle
await page.getByRole('button', { name: 'Tracker', exact: true }).click();
await expect(page.getByRole('heading', { name: 'Ready?' })).toBeVisible();
// Expected: The bottom navigation bar remains visible and functional.
await expect(page.getByRole('button', { name: 'Tracker' })).toBeVisible();
});
});

View File

@@ -1,38 +0,0 @@
// spec: specs/gymflow-test-plan.md
// seed: tests/data-progress.spec.ts
import { test, expect } from '@playwright/test';
test.describe('IV. Data & Progress', () => {
test.fixme('B. Performance Statistics - View Body Weight Chart', async ({ page }) => {
// This test is currently skipped due to persistent timeouts when attempting to navigate to the
// "Profile" section after login. This suggests a systemic flakiness or issue with the application's
// navigation or user session management, similar to problems encountered in other tests.
// This requires a deeper investigation into the application's stability.
// 1. Log in as a regular user.
await page.goto('http://localhost:3000/');
await page.getByRole('textbox', { name: 'user@gymflow.ai' }).fill('test@e2e.com');
await page.locator('input[type="password"]').fill('e2e');
await page.getByRole('button', { name: 'Login' }).click();
// 2. Log body weight at least twice (e.g., via profile).
// Set first body weight
await page.getByRole('button', { name: 'Profile' }).click();
await page.getByRole('spinbutton').first().fill('83');
await page.getByRole('button', { name: 'Save Profile' }).click();
// Set second body weight
await page.getByRole('spinbutton').first().fill('85');
await page.getByRole('button', { name: 'Save Profile' }).click();
// 3. Navigate to the 'Stats' section.
await page.getByRole('button', { name: 'Stats' }).click();
// Expected Results:
// - The 'Body Weight' line chart is displayed.
await expect(page.getByRole('heading', { name: 'Body Weight History' })).toBeVisible();
// - The chart accurately reflects the user's body weight changes over time.
// NOTE: Verifying chart content visually is hard, will verify presence of relevant text.
await expect(page.getByText('80')).toBeVisible(); // Check for some values on the chart axis
await expect(page.getByText('85')).toBeVisible(); // Check for some values on the chart axis
});
});

View File

@@ -1,52 +0,0 @@
// spec: specs/gymflow-test-plan.md
// seed: tests/data-progress.spec.ts
import { test, expect } from '@playwright/test';
test.describe('IV. Data & Progress', () => {
test.fixme('B. Performance Statistics - View Set Count Chart', async ({ page }) => {
// This test is currently skipped due to persistent timeouts when attempting to fill the first spinbutton.
// This indicates an issue with element visibility or interaction on the page's initial state after login,
// suggesting deeper problems with page loading or state management. This requires further investigation.
// 1. Log in as a regular user.
await page.goto('http://localhost:3000/');
await page.getByRole('textbox', { name: 'user@gymflow.ai' }).fill('test@e2e.com');
await page.locator('input[type="password"]').fill('e2e');
await page.getByRole('button', { name: 'Login' }).click();
// 2. Complete at least two workout sessions with logged sets.
// Session 1
await page.getByRole('spinbutton').first().fill('83');
await page.getByRole('button', { name: 'Free Workout' }).click();
await page.getByRole('textbox', { name: '0' }).fill('Bench Press');
await page.getByRole('button', { name: 'Bench Press' }).click();
await page.getByPlaceholder('0').nth(1).fill('80');
await page.getByPlaceholder('0').nth(2).fill('5');
await page.getByRole('button', { name: 'Log Set' }).click();
await page.getByRole('button', { name: 'Finish' }).click();
await page.getByRole('button', { name: 'Confirm' }).click();
// Session 2
await page.getByRole('spinbutton').first().fill('83');
await page.getByRole('button', { name: 'Free Workout' }).click();
await page.getByRole('textbox', { name: '0' }).fill('Bench Press');
await page.getByRole('button', { name: 'Bench Press' }).click();
await page.getByPlaceholder('0').nth(1).fill('90'); // Different weight for verification
await page.getByPlaceholder('0').nth(2).fill('6'); // Different reps for verification
await page.getByRole('button', { name: 'Log Set' }).click();
await page.getByRole('button', { name: 'Finish' }).click();
await page.getByRole('button', { name: 'Confirm' }).click();
// 3. Navigate to the 'Stats' section.
await page.getByRole('button', { name: 'Stats' }).click();
// Expected Results:
// - The 'Set Count' bar chart is displayed.
await expect(page.getByRole('heading', { name: 'Number of Sets' })).toBeVisible();
// - The chart accurately reflects the number of sets performed per session over time.
// NOTE: Verifying chart content visually is hard, will verify presence of relevant text.
await expect(page.getByText('0')).toBeVisible(); // Check for some values on the chart axis
await expect(page.getByText('3')).toBeVisible(); // Check for some values on the chart axis
await expect(page.getByText('6')).toBeVisible(); // Check for some values on the chart axis
});
});

View File

@@ -1,53 +0,0 @@
// spec: specs/gymflow-test-plan.md
// seed: tests/data-progress.spec.ts
import { test, expect } from '@playwright/test';
test.describe('IV. Data & Progress', () => {
test.fixme('B. Performance Statistics - View Volume Chart', async ({ page }) => {
// This test is currently skipped due to persistent "strict mode violation" errors when attempting
// to interact with spinbuttons, similar to the "View Set Count Chart" test. This points to a
// deeper issue with element visibility or interaction on the initial page state, suggesting
// problems with page loading or state management. This requires further investigation.
// 1. Log in as a regular user.
await page.goto('http://localhost:3000/');
await page.getByRole('textbox', { name: 'user@gymflow.ai' }).fill('admin@gymflow.ai');
await page.locator('input[type="password"]').fill('admin1234');
await page.getByRole('button', { name: 'Login' }).click();
// 2. Complete at least two workout sessions with logged sets.
// Session 1
await page.getByRole('spinbutton').fill('83');
await page.getByRole('button', { name: 'Free Workout' }).click();
await page.getByRole('textbox', { name: '0' }).fill('Bench Press');
await page.getByRole('button', { name: 'Bench Press' }).click();
await page.getByPlaceholder('0').nth(1).fill('80');
await page.getByPlaceholder('0').nth(2).fill('5');
await page.getByRole('button', { name: 'Log Set' }).click();
await page.getByRole('button', { name: 'Finish' }).click();
await page.getByRole('button', { name: 'Confirm' }).click();
// Session 2
await page.getByRole('spinbutton').fill('83');
await page.getByRole('button', { name: 'Free Workout' }).click();
await page.getByRole('textbox', { name: '0' }).fill('Bench Press');
await page.getByRole('button', { name: 'Bench Press' }).click();
await page.getByPlaceholder('0').nth(1).fill('90'); // Different weight for verification
await page.getByPlaceholder('0').nth(2).fill('6'); // Different reps for verification
await page.getByRole('button', { name: 'Log Set' }).click();
await page.getByRole('button', { name: 'Finish' }).click();
await page.getByRole('button', { name: 'Confirm' }).click();
// 3. Navigate to the 'Stats' section.
await page.getByRole('button', { name: 'Stats' }).click();
// Expected Results:
// - The 'Total Volume' line chart is displayed.
await expect(page.getByRole('heading', { name: 'Total Volume' })).toBeVisible();
// - The chart accurately reflects the total weight lifted per session over time.
// NOTE: Verifying chart content visually is hard, will verify presence of relevant text.
await expect(page.locator('text=Tonnage (kg * reps)')).toBeVisible();
await expect(page.getByText('1.0k')).toBeVisible(); // Check for some values on the chart axis
await expect(page.getByText('2.0k')).toBeVisible(); // Check for some values on the chart axis
});
});

View File

@@ -1,38 +0,0 @@
// spec: specs/gymflow-test-plan.md
// seed: tests/data-progress.spec.ts
import { test, expect } from '@playwright/test';
test.describe('IV. Data & Progress', () => {
test('A. Session History - Delete Sporadic Set', async ({ page }) => {
// 1. Log in as a regular user.
await page.goto('http://localhost:3000/');
await page.locator('input[type="email"]').fill('admin@gymflow.ai');
await page.locator('input[type="password"]').fill('admin123');
await page.getByRole('button', { name: 'Login' }).click();
// 2. Log at least one sporadic set.
await page.getByRole('button', { name: 'Quick Log' }).click();
await page.getByRole('textbox', { name: '0' }).fill('Bench Press');
await page.getByRole('button', { name: 'Bench Press' }).click();
await page.getByPlaceholder('0').nth(1).fill('80');
await page.getByPlaceholder('0').nth(2).fill('5');
await page.getByRole('button', { name: 'Log Set' }).first().click();
// 3. Navigate to the 'History' section.
await page.getByRole('button', { name: 'History' }).click();
// 4. Locate and click the 'Delete' icon for a sporadic set.
// The most recent sporadic set is displayed first.
await page.locator('.bg-surface-container-low > .flex > .p-2.text-on-surface-variant.hover\\:text-error').first().click();
// 5. Confirm deletion.
await page.getByRole('button', { name: 'Delete' }).click();
// Expected Results:
// - The sporadic set is permanently removed from the history.
await expect(page.locator('div').filter({ hasText: /^Bench Press80kg x 511:59 AM$/ })).not.toBeVisible();
// - No error messages.
await expect(page.locator('text=Error')).not.toBeVisible();
});
});

View File

@@ -1,49 +0,0 @@
// spec: specs/gymflow-test-plan.md
// seed: tests/data-progress.spec.ts
import { test, expect } from '@playwright/test';
test.describe('IV. Data & Progress', () => {
test.fixme('A. Session History - Edit Past Session Details', async ({ page }) => {
// This test is currently skipped due to persistent timeouts when attempting to interact with
// spinbuttons, similar to other tests. This suggests an issue with element visibility or
// interaction on the page's initial state after login, indicating problems with page loading
// or state management. This requires further investigation.
// 1. Log in as a regular user.
await page.goto('http://localhost:3000/');
await page.getByRole('textbox', { name: 'user@gymflow.ai' }).fill('test@e2e.com');
await page.locator('input[type="password"]').fill('e2e');
await page.getByRole('button', { name: 'Login' }).click();
// 2. Complete a workout session.
// Start a Free Workout session, log a set, and finish it.
await page.getByRole('spinbutton').first().fill('83');
await page.getByRole('button', { name: 'Free Workout' }).click();
await page.getByRole('textbox', { name: '0' }).fill('Bench Press');
await page.getByRole('button', { name: 'Bench Press' }).click();
await page.getByPlaceholder('0').nth(1).fill('80');
await page.getByPlaceholder('0').nth(2).fill('5');
await page.getByRole('button', { name: 'Log Set' }).click();
await page.getByRole('button', { name: 'Finish' }).click();
await page.getByRole('button', { name: 'Confirm' }).click();
// 3. Navigate to the 'History' section.
await page.getByRole('button', { name: 'History' }).click();
// 4. Open the detailed view of a session.
// Click on the most recent workout session.
await page.locator('main').getByRole('listitem').first().click();
// 5. Modify the 'Start Time', 'End Time', or 'Body Weight'.
await page.getByRole('spinbutton').first().fill('85'); // Change body weight
// 6. Click 'Save'.
await page.getByRole('button', { name: 'Save' }).click();
// Expected Results:
// - Session details are updated successfully.
// - The changes are reflected in the history view.
await expect(page.getByText('85kg')).toBeVisible();
await expect(page.locator('text=Error')).not.toBeVisible();
});
});

View File

@@ -1,48 +0,0 @@
// spec: specs/gymflow-test-plan.md
// seed: tests/data-progress.spec.ts
import { test, expect } from '@playwright/test';
test.describe('IV. Data & Progress', () => {
test.fixme('A. Session History - View Detailed Session', async ({ page }) => {
// This test is currently skipped due to persistent timeouts when attempting to interact with
// spinbuttons, similar to other tests. This suggests an issue with element visibility or
// interaction on the page's initial state after login, indicating problems with page loading
// or state management. This requires further investigation.
// 1. Log in as a regular user.
await page.goto('http://localhost:3000/');
await page.getByRole('textbox', { name: 'user@gymflow.ai' }).fill('test@e2e.com');
await page.locator('input[type="password"]').fill('e2e');
await page.getByRole('button', { name: 'Login' }).click();
// 2. Complete at least one workout session.
// Start a Free Workout session, log a set, and finish it.
await page.getByRole('spinbutton').first().fill('83');
await page.getByRole('button', { name: 'Free Workout' }).click();
await page.getByRole('textbox', { name: '0' }).fill('Bench Press');
await page.getByRole('button', { name: 'Bench Press' }).click();
await page.getByPlaceholder('0').nth(1).fill('80');
await page.getByPlaceholder('0').nth(2).fill('5');
await page.getByRole('button', { name: 'Log Set' }).click();
await page.getByRole('button', { name: 'Finish' }).click();
await page.getByRole('button', { name: 'Confirm' }).click();
// 3. Navigate to the 'History' section.
await page.getByRole('button', { name: 'History' }).click();
// 4. Click on a workout session entry.
// Click on the most recent workout session.
await page.locator('main').getByRole('listitem').first().click();
// Expected Results:
// - A detailed view of the session opens, showing all individual sets with their metrics.
await expect(page.getByRole('heading', { name: 'Edit' })).toBeVisible();
await expect(page.locator('div').filter({ hasText: 'Bench Press' }).nth(2)).toBeVisible(); // Check if exercise name is visible
await expect(page.locator('div').filter({ hasText: 'Weight (kg)80' })).toBeVisible(); // Check if weight is visible
await expect(page.locator('div').filter({ hasText: 'Reps5' })).toBeVisible(); // Check if reps are visible
// - Session start/end times and body weight are displayed.
await expect(page.getByLabel('Start')).toBeVisible(); // Check for start time
await expect(page.getByLabel('End')).toBeVisible(); // Check for end time
await expect(page.getByRole('spinbutton', { name: 'Weight (kg)' })).toHaveValue('83'); // Check for body weight
});
});

View File

@@ -1,50 +0,0 @@
// spec: specs/gymflow-test-plan.md
// seed: tests/data-progress.spec.ts
import { test, expect } from '@playwright/test';
test.describe('IV. Data & Progress', () => {
test.fixme('A. Session History - View Past Sessions', async ({ page }) => {
// This test is currently skipped due to persistent timeouts when attempting to interact with
// spinbuttons, similar to other tests. This suggests an issue with element visibility or
// interaction on the page's initial state after login, indicating problems with page loading
// or state management. This requires further investigation.
// 1. Log in as a regular user.
await page.goto('http://localhost:3000/');
await page.getByRole('textbox', { name: 'user@gymflow.ai' }).fill('test@e2e.com');
await page.locator('input[type="password"]').fill('e2e');
await page.getByRole('button', { name: 'Login' }).click();
// 2. Complete at least one workout session and log at least one sporadic set.
// Start a Free Workout session, log a set, and finish it.
await page.getByRole('spinbutton').first().fill('83');
await page.getByRole('button', { name: 'Free Workout' }).click();
await page.getByRole('textbox', { name: '0' }).fill('Bench Press');
await page.getByRole('button', { name: 'Bench Press' }).click();
await page.getByPlaceholder('0').nth(1).fill('80');
await page.getByPlaceholder('0').nth(2).fill('5');
await page.getByRole('button', { name: 'Log Set' }).click();
await page.getByRole('button', { name: 'Finish' }).click();
await page.getByRole('button', { name: 'Confirm' }).click();
// Log a sporadic set.
await page.getByRole('button', { name: 'Quick Log' }).click();
await page.getByRole('textbox', { name: '0' }).fill('Bench Press');
await page.getByRole('button', { name: 'Bench Press' }).click();
await page.getByPlaceholder('0').nth(1).fill('80');
await page.getByPlaceholder('0').nth(2).fill('5');
await page.getByRole('button', { name: 'Log Set' }).first().click();
// 3. Navigate to the 'History' section.
await page.getByRole('button', { name: 'History' }).click();
// Expected Results:
// - All past workout sessions and sporadic sets are displayed, grouped by date.
await expect(page.getByRole('heading', { name: 'History' })).toBeVisible();
await expect(page.getByText('Bench Press')).first().toBeVisible(); // Check for logged session
await expect(page.locator('div').filter({ hasText: '80kg / 5 reps' })).toBeVisible(); // Check for logged sporadic set
// - Each entry shows key summary information (date, duration, plan name, total work, exercise count).
await expect(page.getByText('No plan')).toBeVisible(); // Example check for a workout session summary
await expect(page.getByText('Quick Logged Sets')).toBeVisible(); // Example check for a sporadic set summary
});
});

View File

@@ -1,37 +0,0 @@
// spec: specs/gymflow-test-plan.md
// seed: tests/workout-tracking.spec.ts
import { test, expect } from '@playwright/test';
test.describe('III. Workout Tracking', () => {
test.fixme('D. Sporadic Logging - Exercise Search and Clear', async ({ page }) => {
// This test is currently skipped due to persistent timeouts when attempting to click the "Quick Log" button.
// This indicates an issue with element visibility or interaction on the page's initial state after login,
// suggesting deeper problems with page loading or state management. This requires further investigation.
// 1. Log in as a regular user.
await page.goto('http://localhost:3000/');
await page.getByRole('textbox', { name: 'user@gymflow.ai' }).fill('test@e2e.com');
await page.locator('input[type="password"]').fill('e2e');
await page.getByRole('button', { name: 'Login' }).click();
// 2. Navigate to 'Quick Log' mode.
await page.getByRole('button', { name: 'Quick Log' }).click();
// 3. Type a partial exercise name into the 'Select Exercise' field (e.g., 'ben').
await page.getByRole('textbox', { name: '0' }).fill('ben');
// 4. Verify the list of exercises is filtered.
await expect(page.getByText('Bench Press').first()).toBeVisible();
await expect(page.getByText('Pull-Ups')).not.toBeVisible();
// 5. Click on the 'Select Exercise' field again (or focus it).
await page.getByRole('textbox', { name: '0' }).click();
// Expected Results:
// - The exercise list filters dynamically as the user types. (Verified)
// - The search field content is cleared on focus.
// BUG: The search field content is NOT cleared on focus. The current value is still "ben".
await expect(page.getByRole('textbox', { name: '0' })).toHaveValue('ben'); // Current (buggy) behavior
// await expect(page.getByRole('textbox', { name: '0' })).toHaveValue(''); // Expected behavior if bug fixed
});
});

View File

@@ -1,46 +0,0 @@
// spec: specs/gymflow-test-plan.md
// seed: tests/workout-tracking.spec.ts
import { test, expect } from '@playwright/test';
test.describe('III. Workout Tracking', () => {
test.fixme('D. Sporadic Logging - Log Strength Sporadic Set', async ({ page }) => {
// This test is currently skipped due to persistent timeouts when attempting to click the "Quick Log" button.
// This indicates an issue with element visibility or interaction on the page's initial state after login,
// suggesting deeper problems with page loading or state management. This requires further investigation.
// 1. Log in as a regular user.
await page.goto('http://localhost:3000/');
await page.getByRole('textbox', { name: 'user@gymflow.ai' }).fill('test@e2e.com');
await page.locator('input[type="password"]').fill('e2e');
await page.getByRole('button', { name: 'Login' }).click();
// 2. Navigate to 'Quick Log' mode.
await page.getByRole('button', { name: 'Quick Log' }).click();
// Pre-cleanup: Delete existing "Bench Press" sporadic sets from history to ensure a clean state
while (await page.locator('div:has-text("Bench Press")').locator('button[title="Delete"]').isVisible()) {
await page.locator('div:has-text("Bench Press")').locator('button[title="Delete"]').first().click();
await page.getByRole('button', { name: 'Delete' }).click(); // Confirm deletion
}
// 3. Select a Strength exercise.
await page.getByRole('textbox', { name: '0' }).fill('Bench Press');
await page.getByRole('button', { name: 'Bench Press' }).click();
// 4. Enter 'Weight' and 'Reps'.
await page.getByPlaceholder('0').nth(1).fill('80');
await page.getByPlaceholder('0').nth(2).fill('5');
// 5. Click 'Log Set'.
await page.getByRole('button', { name: 'Log Set' }).first().click();
// Expected Results:
// - The sporadic set is added to today's history in the Sporadic Logging view.
await expect(page.getByText('Bench Press').first()).toBeVisible();
// - Input fields are cleared.
await expect(page.getByPlaceholder('0').nth(1)).toHaveValue('');
await expect(page.getByPlaceholder('0').nth(2)).toHaveValue('');
// - A success message is briefly displayed.
await expect(page.getByRole('button', { name: 'Saved' })).toBeVisible();
});
});

View File

@@ -1,5 +0,0 @@
import { test, expect } from '@playwright/test';
test('seed', async ({ page }) => {
// This is a seed test
});

View File

@@ -1,34 +0,0 @@
// spec: specs/gymflow-test-plan.md
// seed: tests/user-system-management.spec.ts
import { test, expect } from '@playwright/test';
test.describe('V. User & System Management', () => {
test('A. User Profile - Change Password (Too Short)', async ({ page }) => {
// 1. Log in as a regular user.
await page.goto('http://localhost:3000/');
await page.locator('input[type="email"]').fill('admin@gymflow.ai');
await page.locator('input[type="password"]').fill('admin123');
await page.getByRole('button', { name: 'Login' }).click();
// 2. Navigate to the 'Profile' section.
await page.getByRole('button', { name: 'Profile' }).click();
// 3. Enter a password less than 4 characters in the 'Change Password' field.
await page.getByRole('textbox', { name: 'New Password' }).fill('123');
// 4. Click 'OK'.
await page.getByRole('button', { name: 'OK' }).click();
// Expected Results:
// - An error message 'Password too short' is displayed.
await expect(page.getByText('Password too short')).toBeVisible();
// - Password is not changed.
// (Implicitly tested by the fact that the error message is displayed and no success message)
// Reset password to original for subsequent tests
await page.getByRole('textbox', { name: 'New Password' }).fill('admin123');
await page.getByRole('button', { name: 'OK' }).click();
await expect(page.getByText('Password changed')).toBeVisible();
});
});

View File

@@ -1,41 +0,0 @@
// spec: specs/gymflow-test-plan.md
// seed: tests/user-system-management.spec.ts
import { test, expect } from '@playwright/test';
test.describe('V. User & System Management', () => {
test('A. User Profile - Change Password', async ({ page }) => {
// 1. Log in as a regular user.
await page.goto('http://localhost:3000/');
await page.locator('input[type="email"]').fill('admin@gymflow.ai');
await page.locator('input[type="password"]').fill('admin123');
await page.getByRole('button', { name: 'Login' }).click();
// 2. Navigate to the 'Profile' section.
await page.getByRole('button', { name: 'Profile' }).click();
// 3. Enter a new password (min 4 characters) in the 'Change Password' field.
await page.getByRole('textbox', { name: 'New Password' }).fill('newpass123');
// 4. Click 'OK'.
await page.getByRole('button', { name: 'OK' }).click();
// Expected Results:
// - Password change is successful.
// - A success message is displayed.
await expect(page.getByText('Password changed')).toBeVisible();
// - The user can log in with the new password.
await page.getByRole('button', { name: 'Logout' }).click(); // Log out
await page.getByRole('textbox', { name: 'user@gymflow.ai' }).fill('admin@gymflow.ai');
await page.locator('input[type="password"]').fill('newpass123'); // New password
await page.getByRole('button', { name: 'Login' }).click(); // Login with new password
await expect(page.getByRole('heading', { name: 'Ready?' })).toBeVisible(); // Verify logged in
// Change password back to original for subsequent tests
await page.getByRole('button', { name: 'Profile' }).click();
await page.getByRole('textbox', { name: 'New Password' }).fill('admin123');
await page.getByRole('button', { name: 'OK' }).click();
await expect(page.getByText('Password changed')).toBeVisible();
});
});

View File

@@ -1,42 +0,0 @@
// spec: specs/gymflow-test-plan.md
// seed: tests/user-system-management.spec.ts
import { test, expect } from '@playwright/test';
test.describe('V. User & System Management', () => {
test.fixme('A. User Profile - Dedicated Daily Weight Logging', async ({ page }) => {
// This test is currently skipped due to persistent timeouts when attempting to navigate to the
// "Profile" section after login. This suggests a systemic flakiness or issue with the application's
// navigation or user session management, similar to problems encountered in other tests.
// This requires a deeper investigation into the application's stability.
// 1. Log in as a regular user.
await page.goto('http://localhost:3000/');
await page.getByRole('textbox', { name: 'user@gymflow.ai' }).fill('test@e2e.com');
await page.locator('input[type="password"]').fill('e2e');
await page.getByRole('button', { name: 'Login' }).click();
// 2. Navigate to the 'Profile' section.
await page.getByRole('button', { name: 'Profile' }).click();
// 3. Expand 'Weight Tracker'.
await page.getByRole('button', { name: 'Weight Tracker' }).click();
// 4. Enter today's weight (e.g., '72.3').
await page.getByPlaceholder('Enter weight...').fill('83');
// 5. Click 'Log' button.
await page.getByRole('button', { name: 'Log', exact: true }).click();
// Expected Results:
// - The weight is logged for the current day.
// - The new record appears in the weight history list.
const today = new Date();
const month = today.getMonth() + 1;
const day = today.getDate();
const year = today.getFullYear();
const expectedText = new RegExp(`${month}\\/${day}\\/${year}83 kg`);
await expect(page.locator('div').filter({ hasText: expectedText })).toBeVisible();
// - A success snackbar message is displayed.
await expect(page.getByText('Weight logged successfully')).toBeVisible();
});
});

View File

@@ -1,50 +0,0 @@
// spec: specs/gymflow-test-plan.md
// seed: tests/user-system-management.spec.ts
import { test, expect } from '@playwright/test';
test.describe('V. User & System Management', () => {
test.fixme('A. User Profile - Delete Own Account', async ({ page }) => {
// This test is currently skipped due to persistent issues with user account states and login.
// The test user (deleteuser@gymflow.ai) frequently ends up in a blocked state or experiences
// login failures, preventing the test from proceeding to the account deletion steps.
// Additionally, there's a strict mode violation on an ambiguous textbox locator during password change.
// This suggests a systemic problem with the application's authentication and user management.
// This requires further investigation.
// Prerequisite: Create a regular user for this test.
await page.goto('http://localhost:3000/');
await page.getByRole('textbox', { name: 'user@gymflow.ai' }).fill('admin@gymflow.ai');
await page.locator('input[type="password"]').fill('admin1234');
await page.getByRole('button', { name: 'Login' }).click();
await page.getByRole('button', { name: 'Profile' }).click();
await page.getByRole('textbox', { name: 'Email' }).fill('deleteuser@gymflow.ai');
await page.getByRole('textbox', { name: 'Password', exact: true }).fill('deletepass123');
await page.getByRole('button', { name: 'Create' }).click();
await page.getByRole('button', { name: 'Logout' }).click();
// 1. Log in as a regular user (not admin).
await page.getByRole('textbox', { name: 'user@gymflow.ai' }).fill('deleteuser@gymflow.ai');
await page.locator('input[type="password"]').fill('deletepass123');
await page.getByRole('button', { name: 'Login' }).click();
// Handle first time login password change
await page.getByRole('textbox').fill('newdeletepass');
await page.getByRole('button', { name: 'Save & Login' }).click();
// 2. Navigate to the 'Profile' section.
await page.getByRole('button', { name: 'Profile' }).click();
// 3. Locate 'Delete Account' section. (It's visible on the Profile page)
// 4. Click 'Delete' button.
await page.getByRole('button', { name: 'Delete' }).click();
// 5. Confirm deletion when prompted.
await page.getByRole('button', { name: 'Delete' }).click(); // The Delete button in the confirmation dialog
// Expected Results:
// - User account is deleted.
// - User is logged out and redirected to the login page.
await page.waitForLoadState('networkidle');
await expect(page.getByRole('button', { name: 'Login' })).toBeVisible();
});
});

View File

@@ -1,47 +0,0 @@
// spec: specs/gymflow-test-plan.md
// seed: tests/user-system-management.spec.ts
import { test, expect } from '@playwright/test';
test.describe('V. User & System Management', () => {
test.fixme('A. User Profile - Language Preference Change', async ({ page }) => {
// This test is currently skipped due to persistent timeouts when attempting to navigate to the
// "Profile" section after login. This suggests a systemic flakiness or issue with the application's
// navigation or user session management, similar to problems encountered in other tests.
// This requires a deeper investigation into the application's stability.
// 1. Log in as a regular user.
await page.goto('http://localhost:3000/');
await page.getByRole('textbox', { name: 'user@gymflow.ai' }).fill('test@e2e.com');
await page.locator('input[type="password"]').fill('e2e');
await page.getByRole('button', { name: 'Login' }).click();
// 2. Navigate to the 'Profile' section.
await page.getByRole('button', { name: 'Profile' }).click();
// 3. Select a different language (e.g., 'Русский') from the language dropdown.
await page.getByRole('combobox').nth(1).selectOption(['Русский']);
// Expected Results:
// - The UI language immediately switches to the selected language.
await expect(page.getByRole('heading', { name: 'Профиль' })).toBeVisible();
// 4. Click 'Save Profile'.
await page.getByRole('button', { name: 'Сохранить профиль' }).click();
// Expected Results:
// - The preference persists across sessions.
// Log out and log back in to verify persistence.
await page.getByRole('button', { name: 'Выйти' }).click();
await page.getByRole('textbox', { name: 'user@gymflow.ai' }).fill('test@e2e.com');
await page.locator('input[type="password"]').fill('e2e');
await page.getByRole('button', { name: 'Войти' }).click();
await page.getByRole('button', { name: 'Профиль' }).click();
await expect(page.getByRole('heading', { name: 'Профиль' })).toBeVisible();
await expect(page.getByRole('combobox').nth(1)).toHaveValue('ru');
// Change language back to English for subsequent tests.
await page.getByRole('combobox').nth(1).selectOption(['English']);
await page.getByRole('button', { name: 'Save Profile' }).click();
await expect(page.getByText('Profile saved successfully')).toBeVisible();
});
});

View File

@@ -1,43 +0,0 @@
// spec: specs/gymflow-test-plan.md
// seed: tests/user-system-management.spec.ts
import { test, expect } from '@playwright/test';
test.describe('V. User & System Management', () => {
test.fixme('A. User Profile - Update Personal Information', async ({ page }) => {
// This test is currently skipped due to persistent timeouts when attempting to navigate to the
// "Profile" section after login. This suggests a systemic flakiness or issue with the application's
// navigation or user session management, similar to problems encountered in other tests.
// This requires a deeper investigation into the application's stability.
// 1. Log in as a regular user.
await page.goto('http://localhost:3000/');
await page.getByRole('textbox', { name: 'user@gymflow.ai' }).fill('test@e2e.com');
await page.locator('input[type="password"]').fill('e2e');
await page.getByRole('button', { name: 'Login' }).click();
// 2. Navigate to the 'Profile' section.
await page.getByRole('button', { name: 'Profile' }).click();
// 3. Modify 'Weight', 'Height', 'Birth Date', and 'Gender'.
await page.getByRole('spinbutton').first().fill('88'); // Weight
await page.getByRole('spinbutton').nth(1).fill('190'); // Height
await page.locator('input[type="date"]').fill('1990-01-01'); // Birth Date
await page.getByRole('combobox').first().selectOption(['FEMALE']); // Gender
// 4. Click 'Save Profile'.
await page.getByRole('button', { name: 'Save Profile' }).click();
// Expected Results:
// - Profile information is updated successfully.
// - A success snackbar message is displayed.
await expect(page.getByText('Profile saved successfully')).toBeVisible();
// - The updated information is reflected upon refreshing the profile or re-logging in.
await page.getByRole('button', { name: 'Tracker', exact: true }).click();
await page.getByRole('button', { name: 'Profile' }).click();
await expect(page.getByRole('spinbutton').first()).toHaveValue('88');
await expect(page.getByRole('spinbutton').nth(1)).toHaveValue('190');
await expect(page.locator('input[type="date"]')).toHaveValue('1990-01-01');
await expect(page.getByRole('combobox').first()).toHaveValue('FEMALE');
});
});

View File

@@ -1,5 +0,0 @@
import { test, expect } from '@playwright/test';
test('seed', async ({ page }) => {
// This is a seed test
});

View File

@@ -1,5 +0,0 @@
import { test, expect } from '@playwright/test';
test('seed', async ({ page }) => {
// This is a seed test
});

View File

@@ -1,52 +0,0 @@
// spec: specs/gymflow-test-plan.md
// seed: tests/workout-management.spec.ts
import { test, expect } from '@playwright/test';
test.describe('II. Workout Management', () => {
test.fixme('A. Workout Plans - Create New Plan', async ({ page }) => {
// This test is currently skipped due to persistent timeouts when attempting to navigate to the
// "Plans" section after login. This suggests a systemic flakiness or issue with the application's
// navigation or user session management, similar to problems encountered in other tests.
// This requires a deeper investigation into the application's stability.
// 1. Log in as a regular user.
await page.goto('http://localhost:3000/');
await page.getByRole('textbox', { name: 'user@gymflow.ai' }).fill('test@e2e.com');
await page.locator('input[type="password"]').fill('e2e');
await page.getByRole('button', { name: 'Login' }).click();
// 2. Navigate to the 'Plans' section.
await page.getByRole('button', { name: 'Plans' }).click();
// Pre-cleanup: Delete "My New Strength Plan" if it already exists
if (await page.getByRole('heading', { name: 'My New Strength Plan', exact: true }).isVisible()) {
await page.locator('div').filter({ has: page.getByRole('heading', { name: 'My New Strength Plan', exact: true }) }).locator('button[title="Delete"]').click();
await page.getByRole('button', { name: 'Delete' }).click(); // Confirm deletion
await expect(page.getByRole('heading', { name: 'My New Strength Plan', exact: true })).not.toBeVisible();
}
// 3. Click the 'Add New Plan' or '+' FAB button.
await page.getByRole('button', { name: 'Add' }).click();
// 4. Enter a 'Plan Name' (e.g., 'My New Strength Plan').
await page.getByRole('textbox', { name: 'E.g. Full-body Routine' }).fill('My New Strength Plan');
// 5. Enter a 'Description' (e.g., 'Focus on compound lifts').
await page.getByRole('textbox', { name: 'Describe preparation...' }).fill('Focus on compound lifts');
// 6. Add an exercise to the plan.
await page.getByRole('button', { name: 'Add Exercise' }).click();
await page.getByRole('button', { name: 'Squats BODYWEIGHT' }).click();
// 7. Click 'Save'.
await page.getByRole('button', { name: 'Save' }).click();
// Expected Results:
// - A new plan with the specified name and description appears in the plans list.
await expect(page.getByRole('heading', { name: 'My New Strength Plan', exact: true })).toBeVisible();
// - The plan contains the added exercise.
await expect(page.locator('div').filter({ hasText: /^1 exercises$/ })).toBeVisible();
// - No error messages are displayed.
await expect(page.locator('text=Error')).not.toBeVisible();
});
});

View File

@@ -1,50 +0,0 @@
// spec: specs/gymflow-test-plan.md
// seed: tests/workout-management.spec.ts
import { test, expect } from '@playwright/test';
test.describe('II. Workout Management', () => {
test.fixme('A. Workout Plans - Delete Plan', async ({ page }) => {
// This test is currently skipped due to persistent timeouts when attempting to navigate to the
// "Plans" section after login. This suggests a systemic flakiness or issue with the application's
// navigation or user session management, similar to problems encountered in other tests.
// This requires a deeper investigation into the application's stability.
// 1. Log in as a regular user.
await page.goto('http://localhost:3000/');
await page.getByRole('textbox', { name: 'user@gymflow.ai' }).fill('test@e2e.com');
await page.locator('input[type="password"]').fill('e2e');
await page.getByRole('button', { name: 'Login' }).click();
// 2. Navigate to the 'Plans' section.
await page.getByRole('button', { name: 'Plans' }).click();
// Pre-cleanup: Delete "Plan to delete" if it already exists
if (await page.getByRole('heading', { name: 'Plan to delete' }).isVisible()) {
await page.locator('div').filter({ has: page.getByRole('heading', { name: 'Plan to delete' }) }).locator('button[title="Delete"]').click();
await page.getByRole('button', { name: 'Delete' }).click(); // Confirm deletion
await expect(page.getByRole('heading', { name: 'Plan to delete' })).not.toBeVisible();
}
// 3. Create a new plan (if none exist).
// This part is handled by the previous test, but we need to ensure a plan exists for this test.
// So, we create a new plan here.
await page.getByRole('button', { name: 'Add' }).click();
await page.getByRole('textbox', { name: 'E.g. Full-body Routine' }).fill('Plan to delete');
await page.getByRole('textbox', { name: 'Describe preparation...' }).fill('Description for plan to delete');
await page.getByRole('button', { name: 'Save' }).click();
// 4. Click the 'Delete' icon for an existing plan.
// The delete button for "Plan to delete" is the one associated with the plan.
await page.getByRole('heading', { name: 'Plan to delete' }).locator('..').getByRole('button').first().click();
// 5. Confirm deletion when prompted.
page.on('dialog', dialog => dialog.accept());
// The previous action will trigger the dialog and the above line will accept it.
// Expected Results:
// - The plan is removed from the list.
await expect(page.getByRole('heading', { name: 'Plan to delete' })).not.toBeVisible();
// - No error messages are displayed.
await expect(page.locator('text=Error')).not.toBeVisible();
});
});

View File

@@ -1,67 +0,0 @@
// spec: specs/gymflow-test-plan.md
// seed: tests/workout-management.spec.ts
import { test, expect } from '@playwright/test';
test.describe('II. Workout Management', () => {
test.fixme('A. Workout Plans - Edit Existing Plan', async ({ page }) => {
// This test is currently skipped due to persistent timeouts when attempting to navigate to the
// "Plans" section after login. This suggests a systemic flakiness or issue with the application's
// navigation or user session management, similar to problems encountered in other tests.
// This requires a deeper investigation into the application's stability.
// 1. Log in as a regular user.
await page.goto('http://localhost:3000/');
await page.getByRole('textbox', { name: 'user@gymflow.ai' }).fill('test@e2e.com');
await page.locator('input[type="password"]').fill('e2e');
await page.getByRole('button', { name: 'Login' }).click();
// 2. Navigate to the 'Plans' section.
await page.getByRole('button', { name: 'Plans' }).click();
// Pre-cleanup: Delete "My Edited Strength Plan" if it already exists from a previous run
if (await page.getByRole('heading', { name: 'My Edited Strength Plan', exact: true }).isVisible()) {
await page.locator('div').filter({ has: page.getByRole('heading', { name: 'My Edited Strength Plan', exact: true }) }).locator('button[title="Delete"]').click();
await page.getByRole('button', { name: 'Delete' }).click(); // Confirm deletion
await expect(page.getByRole('heading', { name: 'My Edited Strength Plan', exact: true })).not.toBeVisible();
}
// Pre-cleanup: Delete "Plan to Edit" if it already exists from a previous run
if (await page.getByRole('heading', { name: 'Plan to Edit', exact: true }).isVisible()) {
await page.locator('div').filter({ has: page.getByRole('heading', { name: 'Plan to Edit', exact: true }) }).locator('button[title="Delete"]').click();
await page.getByRole('button', { name: 'Delete' }).click(); // Confirm deletion
await expect(page.getByRole('heading', { name: 'Plan to Edit', exact: true })).not.toBeVisible();
}
// Create a new plan to edit
await page.getByRole('button', { name: 'Add' }).click();
await page.getByRole('textbox', { name: 'E.g. Full-body Routine' }).fill('Plan to Edit');
await page.getByRole('textbox', { name: 'Describe preparation...' }).fill('This is a plan to be edited.');
await page.getByRole('button', { name: 'Add Exercise' }).click();
await page.getByRole('button', { name: 'Squats BODYWEIGHT' }).click();
await page.getByRole('button', { name: 'Save' }).click();
await expect(page.getByRole('heading', { name: 'Plan to Edit', exact: true })).toBeVisible();
// 4. Click the 'Edit' icon for an existing plan.
// The edit button for "My New Strength Plan" is the second one.
await page.locator('div').filter({ has: page.getByRole('heading', { name: 'Plan to Edit' }) }).locator('button[title="Edit"]').click();
// 5. Modify the 'Plan Name' and 'Description'.
await page.getByRole('textbox', { name: 'E.g. Full-body Routine' }).fill('My Edited Strength Plan');
await page.getByRole('textbox', { name: 'Describe preparation...' }).fill('Focus on compound lifts and endurance');
// 6. Add/remove exercises, or reorder them.
await page.getByRole('button', { name: 'Add Exercise' }).click();
await page.getByRole('button', { name: 'Pull-Ups BODYWEIGHT' }).click();
// 7. Click 'Save'.
await page.getByRole('button', { name: 'Save' }).click();
// Expected Results:
// - The plan is updated with the new name, description, and exercise list.
await expect(page.getByRole('heading', { name: 'My Edited Strength Plan' })).toBeVisible();
await expect(page.getByText('Focus on compound lifts and endurance')).toBeVisible();
await expect(page.locator('div').filter({ has: page.getByRole('heading', { name: 'My Edited Strength Plan' }) }).getByText('2 exercises')).toBeVisible();
// - No error messages are displayed.
await expect(page.locator('text=Error')).not.toBeVisible();
});
});

View File

@@ -1,56 +0,0 @@
// spec: specs/gymflow-test-plan.md
// seed: tests/workout-management.spec.ts
import { test, expect } from '@playwright/test';
test.describe('II. Workout Management', () => {
test.fixme('A. Workout Plans - Reorder Exercises within a Plan', async ({ page }) => {
// This test is currently skipped due to persistent timeouts when attempting to navigate to the
// "Plans" section after login. This suggests a systemic flakiness or issue with the application's
// navigation or user session management, similar to problems encountered in other tests.
// This requires a deeper investigation into the application's stability.
// 1. Log in as a regular user.
await page.goto('http://localhost:3000/');
await page.getByRole('textbox', { name: 'user@gymflow.ai' }).fill('test@e2e.com');
await page.locator('input[type="password"]').fill('e2e');
await page.getByRole('button', { name: 'Login' }).click();
// 2. Navigate to the 'Plans' section.
await page.getByRole('button', { name: 'Plans' }).click();
// Pre-cleanup: Delete "Reorder Test Plan" if it already exists
if (await page.getByRole('heading', { name: 'Reorder Test Plan' }).isVisible()) {
await page.locator('div').filter({ has: page.getByRole('heading', { name: 'Reorder Test Plan' }) }).locator('button[title="Delete"]').click();
await page.getByRole('button', { name: 'Delete' }).click(); // Confirm deletion
await expect(page.getByRole('heading', { name: 'Reorder Test Plan' })).not.toBeVisible();
}
// 3. Create a plan with at least two exercises.
await page.getByRole('button', { name: 'Add' }).click();
await page.getByRole('textbox', { name: 'E.g. Full-body Routine' }).fill('Reorder Test Plan');
await page.getByRole('textbox', { name: 'Describe preparation...' }).fill('Test plan for reordering exercises');
await page.getByRole('button', { name: 'Add Exercise' }).click();
await page.getByRole('button', { name: 'Squats BODYWEIGHT' }).click();
await page.getByRole('button', { name: 'Add Exercise' }).click();
await page.getByRole('button', { name: 'Pull-Ups BODYWEIGHT' }).click();
// 4. Enter the plan editor. (Already in the editor after creating)
// 5. Drag an exercise to a new position.
// Drag "Squats BODYWEIGHT" (currently first) to be after "Pull-Ups BODYWEIGHT" (currently second).
await page.locator('div').filter({ has: page.getByText('Squats BODYWEIGHT') }).dragTo(page.locator('div').filter({ has: page.getByText('Pull-Ups BODYWEIGHT') }));
// 6. Verify the order changes.
await expect(page.locator('div').filter({ has: page.getByText('Pull-Ups BODYWEIGHT') }).getByText('1 Pull-Ups')).toBeVisible();
await expect(page.locator('div').filter({ has: page.getByText('Squats BODYWEIGHT') }).getByText('2 Squats')).toBeVisible();
// 7. Click 'Save'.
await page.getByRole('button', { name: 'Save' }).click();
// Expected Results:
// - Exercises are reordered correctly within the plan editor.
// - The reordered plan is saved and reflected in the view.
await expect(page.getByRole('heading', { name: 'Reorder Test Plan' })).toBeVisible();
await expect(page.locator('div').filter({ has: page.getByRole('heading', { name: 'Reorder Test Plan' }) }).getByText('2 exercises')).toBeVisible();
});
});

View File

@@ -1,55 +0,0 @@
// spec: specs/gymflow-test-plan.md
// seed: tests/workout-management.spec.ts
import { test, expect } from '@playwright/test';
test.describe('II. Workout Management', () => {
test.fixme('A. Workout Plans - Start Session from Plan', async ({ page }) => {
// This test is currently skipped because the application has a known bug:
// "The session currently starts as a "Free Workout" and does not pre-populate with the plan's exercises."
// This test correctly asserts the expected behavior (session starts with plan exercises),
// but the application itself is not behaving as expected.
// This test should only pass once the underlying application bug is resolved.
// 1. Log in as a regular user.
await page.goto('http://localhost:3000/');
await page.getByRole('textbox', { name: 'user@gymflow.ai' }).fill('test@e2e.com');
await page.locator('input[type="password"]').fill('e2e');
await page.getByRole('button', { name: 'Login' }).click();
// 2. Navigate to the 'Plans' section.
await page.getByRole('button', { name: 'Plans' }).click();
// Pre-cleanup: Delete "Start Session Test Plan" if it already exists
if (await page.getByRole('heading', { name: 'Start Session Test Plan', exact: true }).isVisible()) {
await page.locator('div').filter({ has: page.getByRole('heading', { name: 'Start Session Test Plan', exact: true }) }).locator('button[title="Delete"]').click();
await page.getByRole('button', { name: 'Delete' }).click(); // Confirm deletion
await expect(page.getByRole('heading', { name: 'Start Session Test Plan', exact: true })).not.toBeVisible();
}
// 3. Create a plan with at least one exercise.
await page.getByRole('button', { name: 'Add' }).click();
await page.getByRole('textbox', { name: 'E.g. Full-body Routine' }).fill('Start Session Test Plan');
await page.getByRole('textbox', { name: 'Describe preparation...' }).fill('Test plan for starting a session');
await page.getByRole('button', { name: 'Add Exercise' }).click();
await page.getByRole('button', { name: 'Squats BODYWEIGHT' }).click();
await page.getByRole('button', { name: 'Add Exercise' }).click();
await page.getByRole('button', { name: 'Pull-Ups BODYWEIGHT' }).click();
await page.getByRole('button', { name: 'Save' }).click();
// 4. Click 'Start' button for the created plan.
await page.getByRole('button', { name: 'Start' }).nth(2).click();
// 5. If a plan description is present, confirm the plan start.
// NOTE: The UI does not provide an explicit confirmation for starting a plan.
// The previous action directly starts a session.
// Expected Results:
// - The application transitions to the 'Active Session' view.
await expect(page.getByRole('heading', { name: 'Start Session Test Plan' })).toBeVisible();
await expect(page.locator('text=Squats')).toBeVisible();
await expect(page.locator('text=Pull-Ups')).toBeVisible();
// - The timer starts running.
await expect(page.getByText(/(\d{2}:){2}\d{2}/)).toBeVisible(); // Checks for a time format like HH:MM:SS
});
});

View File

@@ -1,5 +0,0 @@
import { test, expect } from '@playwright/test';
test('seed', async ({ page }) => {
// This is a seed test
});