import { test, expect } from '@playwright/test'; const VIEWPORTS = [ { name: 'mobile', width: 375, height: 667 }, { name: 'tablet', width: 768, height: 1024 }, { name: 'desktop', width: 1920, height: 1080 }, ]; const PAGES = ['/ru-ru/onlineboard', '/ru-ru/schedule', '/ru-ru/flights-map']; test.describe('Responsive Design (US-10)', () => { // Test all pages at all breakpoints PAGES.forEach((page) => { VIEWPORTS.forEach(({ name, width, height }) => { test(`${page} should be responsive on ${name} (${width}x${height})`, async ({ page: browserPage, baseURL, }) => { await browserPage.setViewportSize({ width, height }); await browserPage.goto(`${baseURL}${page}`); // Wait for page to load await browserPage.waitForLoadState('networkidle'); // Check for layout shift or overflow const bodyWidth = await browserPage.evaluate(() => document.body.scrollWidth); const viewportWidth = width; // Body should not be wider than viewport (allowing 1px tolerance) expect(bodyWidth).toBeLessThanOrEqual(viewportWidth + 1); }); }); }); test('should display navigation bar on mobile', async ({ page, baseURL }) => { await page.setViewportSize({ width: 375, height: 667 }); await page.goto(`${baseURL}/ru-ru/onlineboard`); const tabNavigation = page.locator('[data-testid="nav"]'); await expect(tabNavigation).toBeVisible(); }); test('should display hamburger menu on mobile if needed', async ({ page, baseURL }) => { await page.setViewportSize({ width: 375, height: 667 }); await page.goto(`${baseURL}/ru-ru/onlineboard`); const menu = page.locator('[data-testid="mobile-menu"]'); // Menu may or may not exist, but if it exists, should be visible if ((await menu.count()) > 0) { await expect(menu).toBeVisible(); } }); test('should stack layout vertically on mobile', async ({ page, baseURL }) => { await page.setViewportSize({ width: 375, height: 667 }); await page.goto(`${baseURL}/ru-ru/onlineboard`); const layout = page.locator('[data-testid="dashboard-layout"]'); const style = await layout.evaluate((el) => window.getComputedStyle(el).display); expect(['block', 'flex']).toContain(style); }); test('should use two-column layout on tablet', async ({ page, baseURL }) => { await page.setViewportSize({ width: 768, height: 1024 }); await page.goto(`${baseURL}/ru-ru/onlineboard`); const layout = page.locator('[data-testid="dashboard-layout"]'); await expect(layout).toBeVisible(); }); test('should use full-width layout on desktop', async ({ page, baseURL }) => { await page.setViewportSize({ width: 1920, height: 1080 }); await page.goto(`${baseURL}/ru-ru/onlineboard`); const layout = page.locator('[data-testid="dashboard-layout"]'); await expect(layout).toBeVisible(); }); test('should handle text wrapping on mobile', async ({ page, baseURL }) => { await page.setViewportSize({ width: 375, height: 667 }); await page.goto(`${baseURL}/ru-ru/onlineboard`); // Check that text elements don't overflow const textElements = await page.locator('h1, h2, p').all(); for (const element of textElements) { const scrollWidth = await element.evaluate((el) => el.scrollWidth); const clientWidth = await element.evaluate((el) => el.clientWidth); expect(scrollWidth).toBeLessThanOrEqual(clientWidth + 1); } }); test('should scale images properly on mobile', async ({ page, baseURL }) => { await page.setViewportSize({ width: 375, height: 667 }); await page.goto(`${baseURL}/ru-ru/onlineboard`); const images = await page.locator('img').all(); for (const img of images) { const scrollWidth = await img.evaluate((el) => el.scrollWidth); const clientWidth = await img.evaluate((el) => el.clientWidth); expect(scrollWidth).toBeLessThanOrEqual(clientWidth + 1); } }); test('should maintain usability at all viewport sizes', async ({ page, baseURL }) => { for (const { width, height } of VIEWPORTS) { await page.setViewportSize({ width, height }); await page.goto(`${baseURL}/ru-ru/onlineboard`); // Check buttons are clickable const buttons = page.locator('button'); const count = await buttons.count(); for (let i = 0; i < Math.min(count, 3); i++) { const button = buttons.nth(i); const box = await button.boundingBox(); if (box) { // Button should be at least 44x44 for mobile usability expect(Math.min(box.width, box.height)).toBeGreaterThanOrEqual(32); } } } }); test('should handle long content on mobile', async ({ page, baseURL }) => { await page.setViewportSize({ width: 375, height: 667 }); await page.goto(`${baseURL}/ru-ru/schedule`); const content = page.locator('[data-testid="main-content"]'); if ((await content.count()) > 0) { await expect(content).toBeVisible(); } }); test('should display search panel properly on all sizes', async ({ page, baseURL }) => { for (const { width, height } of VIEWPORTS) { await page.setViewportSize({ width, height }); await page.goto(`${baseURL}/ru-ru/onlineboard`); const searchPanel = page.locator('[data-testid="filter-accordion"]'); if ((await searchPanel.count()) > 0) { await expect(searchPanel).toBeVisible(); } } }); });