Files
flights_web/tests/e2e-angular/ru-ru/empty-state.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

212 lines
6.6 KiB
TypeScript

import { test, expect } from '@playwright/test';
test.describe('Empty State UI (US-91)', () => {
test('should display empty state when flight board search returns no results', async ({
page,
}) => {
// Navigate to a city that should have search results (MOW)
await page.goto('/ru-ru/');
// Wait for page to load
await page.waitForLoadState('networkidle');
// Intercept and mock the API to return no flights
await page.route('**/api/**', (route) => {
const url = route.request().url();
if (url.includes('flights')) {
route.abort();
} else {
route.continue();
}
});
// The empty state should display when no flights are returned
// Note: This is a partial implementation - real test would need actual API mock
await page.goto('/ru-ru/onlineboard?city=MOW');
// Wait for loading to complete
await page.waitForLoadState('networkidle');
// Check if page loaded properly
const isVisible = await page.isVisible('body');
expect(isVisible).toBe(true);
});
test('should display empty state in schedule search when no flights found', async ({ page }) => {
// Navigate to schedule page
await page.goto('/ru-ru/schedule');
// Wait for the page to fully load
await page.waitForLoadState('networkidle');
// The schedule page should load without errors
const titleVisible = await page.isVisible('h1');
expect(titleVisible).toBe(true);
});
test('should have proper accessibility features in empty state', async ({ page }) => {
// Navigate to a page that displays empty state
await page.goto('/ru-ru/onlineboard?city=MOW');
// Wait for loading
await page.waitForLoadState('networkidle');
// Check for proper semantic HTML (article role)
const emptyStateContainer = page.locator('article[role="article"]').first();
// If empty state is displayed, verify accessibility
if (await emptyStateContainer.isVisible()) {
// Check that it has aria-label
const ariaLabel = await emptyStateContainer.getAttribute('aria-label');
expect(ariaLabel).toBeTruthy();
// Check for proper heading hierarchy
const heading = page.locator('article h2').first();
if (await heading.isVisible()) {
expect(await heading.textContent()).toBeTruthy();
}
}
});
test('should not have console errors when empty state is displayed', async ({ page }) => {
const errors: string[] = [];
const warnings: string[] = [];
page.on('console', (msg) => {
if (msg.type() === 'error') {
errors.push(msg.text());
}
if (msg.type() === 'warning') {
warnings.push(msg.text());
}
});
// Navigate to page
await page.goto('/ru-ru/onlineboard?city=MOW');
await page.waitForLoadState('networkidle');
// Critical errors should not occur
const criticalErrors = errors.filter(
(e) => !e.includes('Unexpected token') && !e.includes('Failed to fetch'),
);
expect(criticalErrors.length).toBe(0);
});
test('should render empty state with correct locale (ru-ru)', async ({ page }) => {
// Navigate to page with Russian locale
await page.goto('/ru-ru/onlineboard?city=MOW');
// Wait for loading
await page.waitForLoadState('networkidle');
// Check if page is in Russian locale
const htmlLang = await page.getAttribute('html', 'lang');
expect(['ru', 'ru-RU', 'ru-ru']).toContain(htmlLang);
});
test('should have proper button semantics if actions are available', async ({ page }) => {
// Navigate to schedule page
await page.goto('/ru-ru/schedule');
// Wait for load
await page.waitForLoadState('networkidle');
// If empty state has action buttons, verify they're proper buttons
const buttons = page.locator('article button').all();
const allButtons = await buttons;
for (const button of allButtons) {
// Each button should have proper role
const role = await button.getAttribute('role');
const ariaLabel = await button.getAttribute('aria-label');
// Buttons should be semantically correct
expect(await button.tagName()).toBe('BUTTON');
}
});
test('should display empty state with responsive design on mobile', async ({ page }) => {
// Set mobile viewport
await page.setViewportSize({ width: 375, height: 667 });
// Navigate to page
await page.goto('/ru-ru/onlineboard?city=MOW');
// Wait for load
await page.waitForLoadState('networkidle');
// Check if content is visible
const isVisible = await page.isVisible('body');
expect(isVisible).toBe(true);
// Verify no horizontal scroll is needed (check viewport)
const bodyWidth = await page.evaluate(() => document.documentElement.clientWidth);
expect(bodyWidth).toBeLessThanOrEqual(375);
});
test('should display empty state with responsive design on desktop', async ({ page }) => {
// Set desktop viewport
await page.setViewportSize({ width: 1920, height: 1080 });
// Navigate to page
await page.goto('/ru-ru/onlineboard?city=MOW');
// Wait for load
await page.waitForLoadState('networkidle');
// Check if content is visible
const isVisible = await page.isVisible('body');
expect(isVisible).toBe(true);
});
test('should meet WCAG 2.1 minimum touch target size (44px)', async ({ page }) => {
// Navigate to schedule page
await page.goto('/ru-ru/schedule');
// Wait for load
await page.waitForLoadState('networkidle');
// Get all buttons in empty state
const buttons = page.locator('article button');
const count = await buttons.count();
for (let i = 0; i < count; i++) {
const button = buttons.nth(i);
// Get button dimensions
const box = await button.boundingBox();
if (box) {
// Check that button meets minimum touch target size (44x44px)
expect(box.width).toBeGreaterThanOrEqual(44);
expect(box.height).toBeGreaterThanOrEqual(44);
}
}
});
test('should not have layout shifts when empty state is displayed', async ({ page }) => {
// Listen for layout shifts (Cumulative Layout Shift metric)
let hasLayoutShift = false;
page.on('framenavigated', () => {
hasLayoutShift = false;
});
// Navigate to page
await page.goto('/ru-ru/onlineboard?city=MOW');
// Wait for stabilization
await page.waitForLoadState('networkidle');
// Give time for layout to settle
await page.waitForTimeout(1000);
// Verify page is stable
const isStable = await page.evaluate(() => {
return !document.querySelector('[data-testid*="loading"]');
});
expect(isStable || !hasLayoutShift).toBeTruthy();
});
});