375bcfb0fa
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.
147 lines
5.4 KiB
TypeScript
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();
|
|
}
|
|
}
|
|
});
|
|
});
|