Files
flights_web/tests/e2e-angular/responsive.spec.ts
T
gnezim 375bcfb0fa Add e2e test suite from flights-front with Angular API mocks
Copies Playwright e2e tests (58 specs, 300+ tests) designed for cross-app
testing. Adapts API mocks to match real Aeroflot dictionary format (title
objects with multilingual keys), adds board/schedule/days endpoint mocks,
and provides Angular-specific Playwright config on port 4203.
2026-04-15 23:07:44 +03:00

147 lines
5.4 KiB
TypeScript

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();
}
}
});
});