// spec: specs/gymflow-test-plan.md import { test, expect } from './fixtures'; test.describe('VI. User Interface & Experience', () => { test('6.1. A. Adaptive GUI - Mobile Navigation (Width < 768px)', async ({ page, createUniqueUser }) => { // Note: Use 6.1 numbering as per plan section 6. const user = await createUniqueUser(); await page.goto('/'); await page.getByLabel('Email').fill(user.email); await page.getByLabel('Password').fill(user.password); await page.getByRole('button', { name: 'Login' }).click(); // Handle First Time Password Change try { await expect(page.getByRole('heading', { name: /Change Password/i }).or(page.getByText('Free Workout'))).toBeVisible({ timeout: 5000 }); if (await page.getByRole('heading', { name: /Change Password/i }).isVisible()) { await page.getByLabel('New Password').fill('StrongNewPass123!'); await page.getByRole('button', { name: /Save|Change/i }).click(); } } catch (e) { } await expect(page.getByText('Free Workout')).toBeVisible(); // 2. Resize the browser window to a mobile width (e.g., 375px). await page.setViewportSize({ width: 375, height: 667 }); await expect(page.getByText('Free Workout')).toBeVisible(); // 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('navigation', { name: /Bottom|Mobile/i })).toBeVisible(); // Or check for specific mobile nav items if role 'navigation' isn't named. // Assuming 'Tracker', 'Plans', etc. are visible. await expect(page.getByRole('button', { name: /Tracker/i })).toBeVisible(); // 4. Verify the desktop navigation rail is hidden. await expect(page.getByRole('navigation', { name: /Desktop|Side/i })).toBeHidden(); }); test('6.2. A. Adaptive GUI - Desktop Navigation (Width >= 768px)', async ({ page, createUniqueUser }) => { const user = await createUniqueUser(); await page.goto('/'); await page.getByLabel('Email').fill(user.email); await page.getByLabel('Password').fill(user.password); await page.getByRole('button', { name: 'Login' }).click(); try { await expect(page.getByRole('heading', { name: /Change Password/i }).or(page.getByText('Free Workout'))).toBeVisible({ timeout: 5000 }); if (await page.getByRole('heading', { name: /Change Password/i }).isVisible()) { await page.getByLabel('New Password').fill('StrongNewPass123!'); await page.getByRole('button', { name: /Save|Change/i }).click(); } } catch (e) { } await expect(page.getByText('Free Workout')).toBeVisible(); // 1. Resize the browser window to a desktop width (e.g., 1280px). await page.setViewportSize({ width: 1280, height: 800 }); // 2. Verify the vertical navigation rail is visible and functional. await expect(page.getByRole('navigation', { name: /Desktop|Side/i })).toBeVisible(); await expect(page.getByRole('button', { name: 'Tracker' })).toBeVisible(); // Check an item // 3. Verify the mobile bottom navigation bar is hidden. await expect(page.getByRole('navigation', { name: /Bottom|Mobile/i })).toBeHidden(); }); test('6.3. A. Adaptive GUI - Responsive Charts in Stats', async ({ page, createUniqueUser }) => { // Using content from adaptive-gui-responsive-charts-in-stats.spec.ts const user = await createUniqueUser(); await page.goto('/'); await page.getByLabel('Email').fill(user.email); await page.getByLabel('Password').fill(user.password); await page.getByRole('button', { name: 'Login' }).click(); try { await expect(page.getByRole('heading', { name: /Change Password/i }).or(page.getByText('Free Workout'))).toBeVisible({ timeout: 5000 }); if (await page.getByRole('heading', { name: /Change Password/i }).isVisible()) { await page.getByLabel('New Password').fill('StrongNewPass123!'); await page.getByRole('button', { name: /Save|Change/i }).click(); } } catch (e) { } await expect(page.getByText('Free Workout')).toBeVisible(); const checkNoHorizontalScroll = async () => { const scrollWidth = await page.evaluate(() => document.documentElement.scrollWidth); const clientWidth = await page.evaluate(() => document.documentElement.clientWidth); expect(scrollWidth).toBeLessThanOrEqual(clientWidth); }; // 1. Navigate to the 'Stats' section. await page.getByRole('button', { name: 'Stats' }).click(); // Define a range of widths to test responsiveness const widths = [1280, 1024, 768, 600, 480, 375]; const heights = [800, 768, 667]; for (const width of widths) { for (const height of heights) { await page.setViewportSize({ width, height }); // Give time for resize observation/rendering await page.waitForTimeout(200); // Check for no overflow await checkNoHorizontalScroll(); // Check if "Not enough data" is shown const noData = await page.getByText(/Not enough data/i).isVisible(); if (noData) { await expect(page.getByText(/Not enough data/i)).toBeVisible(); // Skip chart assertions if no data } else { // Verify chart containers are visible await expect(page.getByRole('heading', { name: /Total Volume/i }).or(page.getByText('Total Volume'))).toBeVisible(); await expect(page.getByRole('heading', { name: /Set Count/i }).or(page.getByText('Set Count'))).toBeVisible(); await expect(page.getByRole('heading', { name: /Body Weight/i }).or(page.getByText('Body Weight'))).toBeVisible(); // Check for presence of SVG or Canvas elements typically used for charts await expect(page.locator('svg').first()).toBeVisible(); } } } }); test('6.4. A. Adaptive GUI - Fluid Layout Responsiveness', async ({ page, createUniqueUser }) => { const user = await createUniqueUser(); await page.goto('/'); await page.getByLabel('Email').fill(user.email); await page.getByLabel('Password').fill(user.password); await page.getByRole('button', { name: 'Login' }).click(); // Handle First Time Password Change if it appears try { await expect(page.getByRole('heading', { name: /Change Password/i }).or(page.getByText('Free Workout'))).toBeVisible({ timeout: 5000 }); if (await page.getByRole('heading', { name: /Change Password/i }).isVisible()) { await page.getByLabel('New Password').fill('StrongNewPass123!'); await page.getByRole('button', { name: /Save|Change/i }).click(); } } catch (e) { // Ignore timeout } await expect(page.getByText('Free Workout')).toBeVisible(); // Helper to check for horizontal scrollbar (indicates overflow) const checkNoHorizontalScroll = async () => { const scrollWidth = await page.evaluate(() => document.documentElement.scrollWidth); const clientWidth = await page.evaluate(() => document.documentElement.clientWidth); expect(scrollWidth).toBeLessThanOrEqual(clientWidth); }; // Define a range of widths to test responsiveness const widths = [1280, 1024, 768, 600, 480, 375]; const heights = [800, 768, 667]; // Corresponding heights for (const width of widths) { for (const height of heights) { await page.setViewportSize({ width, height }); await checkNoHorizontalScroll(); // 1. Navigate through various sections and check responsiveness await page.getByRole('button', { name: 'Plans' }).click(); await checkNoHorizontalScroll(); await page.getByRole('button', { name: 'Profile' }).click(); await checkNoHorizontalScroll(); await page.getByRole('button', { name: 'History' }).click(); await checkNoHorizontalScroll(); await page.getByRole('button', { name: 'Stats' }).click(); await checkNoHorizontalScroll(); await page.getByRole('button', { name: 'AI Coach' }).click(); await checkNoHorizontalScroll(); await page.getByRole('button', { name: 'Tracker' }).click(); // Go back to default view await checkNoHorizontalScroll(); } } }); });