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.
311 lines
12 KiB
TypeScript
311 lines
12 KiB
TypeScript
import { test, expect } from '@playwright/test';
|
|
import type { Page } from '@playwright/test';
|
|
import {
|
|
buildOnlineBoardPath,
|
|
buildRouteParam,
|
|
searchFlightByRoute,
|
|
verifyFlightCard,
|
|
generateFlight,
|
|
generateFlights,
|
|
getToday,
|
|
getTomorrow,
|
|
CITIES,
|
|
} from '../support/test-utilities';
|
|
|
|
const today = getToday();
|
|
const tomorrow = getTomorrow();
|
|
const dateParam = buildRouteParam('MOW', today);
|
|
const tomorrowParam = buildRouteParam('MOW', tomorrow);
|
|
|
|
// ============================================================================
|
|
// Online Board - Route Tests
|
|
// ============================================================================
|
|
|
|
test.describe('Online Board - Route', () => {
|
|
test.describe('Page Navigation', () => {
|
|
test('should navigate to route board for Moscow to Sochi', async ({ page }) => {
|
|
await page.goto(`/ru-ru/onlineboard/route/MOW-AER-${today.replace(/-/g, '')}`);
|
|
await page.waitForLoadState('networkidle');
|
|
|
|
await expect(page).toHaveURL(/route\/MOW-AER-\d{8}/);
|
|
await expect(page).toHaveTitle(/Москва - Сочи/);
|
|
});
|
|
|
|
test('should navigate to route board for Saint Petersburg to Moscow', async ({ page }) => {
|
|
await page.goto(`/ru-ru/onlineboard/route/LED-MOW-${today.replace(/-/g, '')}`);
|
|
await page.waitForLoadState('networkidle');
|
|
|
|
await expect(page).toHaveURL(/route\/LED-MOW-\d{8}/);
|
|
});
|
|
|
|
test('should navigate to route board for Novosibirsk to Moscow', async ({ page }) => {
|
|
await page.goto(`/ru-ru/onlineboard/route/OVB-MOW-${today.replace(/-/g, '')}`);
|
|
await page.waitForLoadState('networkidle');
|
|
|
|
await expect(page).toHaveURL(/route\/OVB-MOW-\d{8}/);
|
|
});
|
|
});
|
|
|
|
test.describe('Route Search', () => {
|
|
test('should search route by departure and arrival cities', async ({ page }) => {
|
|
await page.goto(`/ru-ru${buildOnlineBoardPath('departure', 'MOW', today)}`);
|
|
await page.waitForLoadState('networkidle');
|
|
|
|
await searchFlightByRoute(page, 'Moscow', 'Sochi');
|
|
|
|
const searchResults = page.locator('[data-testid="flight-card"]');
|
|
await expect(searchResults).toHaveCount(20);
|
|
});
|
|
|
|
test('should show no results when route not found', async ({ page }) => {
|
|
await page.goto(`/ru-ru${buildOnlineBoardPath('departure', 'MOW', today)}`);
|
|
await page.waitForLoadState('networkidle');
|
|
|
|
await searchFlightByRoute(page, 'Moscow', 'Unknown City');
|
|
|
|
const noResults = page.locator('[data-testid="no-results"]');
|
|
await expect(noResults).toBeVisible();
|
|
await expect(noResults).toContainText('Нет результатов');
|
|
});
|
|
|
|
test('should validate departure city', async ({ page }) => {
|
|
await page.goto(`/ru-ru${buildOnlineBoardPath('departure', 'MOW', today)}`);
|
|
await page.waitForLoadState('networkidle');
|
|
|
|
await searchFlightByRoute(page, '', 'Sochi');
|
|
|
|
const error = page.locator('[data-testid="validation-error"]');
|
|
await expect(error).toBeVisible();
|
|
});
|
|
|
|
test('should validate arrival city', async ({ page }) => {
|
|
await page.goto(`/ru-ru${buildOnlineBoardPath('departure', 'MOW', today)}`);
|
|
await page.waitForLoadState('networkidle');
|
|
|
|
await searchFlightByRoute(page, 'Moscow', '');
|
|
|
|
const error = page.locator('[data-testid="validation-error"]');
|
|
await expect(error).toBeVisible();
|
|
});
|
|
});
|
|
|
|
test.describe('Flight Display', () => {
|
|
test('should display flights for selected route', async ({ page }) => {
|
|
await page.goto(`/ru-ru/onlineboard/route/MOW-AER-${today.replace(/-/g, '')}`);
|
|
await page.waitForLoadState('networkidle');
|
|
|
|
const flightCards = page.locator('[data-testid="flight-card"]');
|
|
await expect(flightCards).toHaveCount(20);
|
|
});
|
|
|
|
test('should display route information', async ({ page }) => {
|
|
await page.goto(`/ru-ru/onlineboard/route/MOW-AER-${today.replace(/-/g, '')}`);
|
|
await page.waitForLoadState('networkidle');
|
|
|
|
const routeInfo = page.locator('[data-testid="route-info"]');
|
|
await expect(routeInfo).toBeVisible();
|
|
|
|
await expect(routeInfo).toContainText('Москва');
|
|
await expect(routeInfo).toContainText('Сочи');
|
|
});
|
|
|
|
test('should display flight count', async ({ page }) => {
|
|
await page.goto(`/ru-ru/onlineboard/route/MOW-AER-${today.replace(/-/g, '')}`);
|
|
await page.waitForLoadState('networkidle');
|
|
|
|
const flightCount = page.locator('[data-testid="flight-count"]');
|
|
await expect(flightCount).toBeVisible();
|
|
});
|
|
});
|
|
|
|
test.describe('Date Navigation', () => {
|
|
test('should navigate to tomorrow', async ({ page }) => {
|
|
await page.goto(`/ru-ru/onlineboard/route/MOW-AER-${today.replace(/-/g, '')}`);
|
|
await page.waitForLoadState('networkidle');
|
|
|
|
const dateTab = page.locator(`[data-testid="date-tab-${tomorrow.replace(/-/g, '')}"]`);
|
|
if ((await dateTab.count()) > 0) {
|
|
await dateTab.click();
|
|
await page.waitForLoadState('networkidle');
|
|
|
|
await expect(page).toHaveURL(/route\/MOW-AER-\d{8}/);
|
|
}
|
|
});
|
|
|
|
test('should display correct date in title', async ({ page }) => {
|
|
await page.goto(`/ru-ru/onlineboard/route/MOW-AER-${today.replace(/-/g, '')}`);
|
|
await page.waitForLoadState('networkidle');
|
|
|
|
const dateText = page.locator('[data-testid="board-date"]');
|
|
await expect(dateText).toBeVisible();
|
|
});
|
|
});
|
|
|
|
test.describe('Filtering', () => {
|
|
test('should filter by status', async ({ page }) => {
|
|
await page.goto(`/ru-ru/onlineboard/route/MOW-AER-${today.replace(/-/g, '')}`);
|
|
await page.waitForLoadState('networkidle');
|
|
|
|
const statusFilter = page.locator('[data-testid="status-filter"]');
|
|
await statusFilter.click();
|
|
|
|
const scheduledOption = page.locator('[data-testid="filter-option-scheduled"]');
|
|
await scheduledOption.click();
|
|
|
|
const filteredFlights = page.locator('[data-testid="flight-card"]');
|
|
await expect(filteredFlights).toHaveCount(20);
|
|
});
|
|
|
|
test('should filter by airline', async ({ page }) => {
|
|
await page.goto(`/ru-ru/onlineboard/route/MOW-AER-${today.replace(/-/g, '')}`);
|
|
await page.waitForLoadState('networkidle');
|
|
|
|
const airlineFilter = page.locator('[data-testid="airline-filter"]');
|
|
await airlineFilter.click();
|
|
|
|
const aeroflotOption = page.locator('[data-testid="filter-option-SU"]');
|
|
await aeroflotOption.click();
|
|
|
|
const filteredFlights = page.locator('[data-testid="flight-card"]');
|
|
await expect(filteredFlights).toHaveCount(20);
|
|
});
|
|
|
|
test('should filter by time range', async ({ page }) => {
|
|
await page.goto(`/ru-ru/onlineboard/route/MOW-AER-${today.replace(/-/g, '')}`);
|
|
await page.waitForLoadState('networkidle');
|
|
|
|
const timeFilter = page.locator('[data-testid="time-filter"]');
|
|
await timeFilter.click();
|
|
|
|
const timeOption = page.locator('[data-testid="filter-option-morning"]');
|
|
await timeOption.click();
|
|
|
|
const filteredFlights = page.locator('[data-testid="flight-card"]');
|
|
await expect(filteredFlights).toHaveCount(20);
|
|
});
|
|
});
|
|
|
|
test.describe('Flight Card', () => {
|
|
test('should display flight number', async ({ page }) => {
|
|
await page.goto(`/ru-ru/onlineboard/route/MOW-AER-${today.replace(/-/g, '')}`);
|
|
await page.waitForLoadState('networkidle');
|
|
|
|
const flightCard = page.locator('[data-testid="flight-card"]').first();
|
|
await expect(flightCard).toBeVisible();
|
|
|
|
const flightNumber = flightCard.locator('[data-testid="flight-number"]');
|
|
await expect(flightNumber).toBeVisible();
|
|
});
|
|
|
|
test('should display airline name', async ({ page }) => {
|
|
await page.goto(`/ru-ru/onlineboard/route/MOW-AER-${today.replace(/-/g, '')}`);
|
|
await page.waitForLoadState('networkidle');
|
|
|
|
const flightCard = page.locator('[data-testid="flight-card"]').first();
|
|
await expect(flightCard).toBeVisible();
|
|
|
|
const airlineName = flightCard.locator('[data-testid="airline-name"]');
|
|
await expect(airlineName).toBeVisible();
|
|
});
|
|
|
|
test('should display departure city', async ({ page }) => {
|
|
await page.goto(`/ru-ru/onlineboard/route/MOW-AER-${today.replace(/-/g, '')}`);
|
|
await page.waitForLoadState('networkidle');
|
|
|
|
const flightCard = page.locator('[data-testid="flight-card"]').first();
|
|
await expect(flightCard).toBeVisible();
|
|
|
|
const departureCity = flightCard.locator('[data-testid="departure-city"]');
|
|
await expect(departureCity).toBeVisible();
|
|
});
|
|
|
|
test('should display arrival city', async ({ page }) => {
|
|
await page.goto(`/ru-ru/onlineboard/route/MOW-AER-${today.replace(/-/g, '')}`);
|
|
await page.waitForLoadState('networkidle');
|
|
|
|
const flightCard = page.locator('[data-testid="flight-card"]').first();
|
|
await expect(flightCard).toBeVisible();
|
|
|
|
const arrivalCity = flightCard.locator('[data-testid="arrival-city"]');
|
|
await expect(arrivalCity).toBeVisible();
|
|
});
|
|
|
|
test('should display scheduled departure time', async ({ page }) => {
|
|
await page.goto(`/ru-ru/onlineboard/route/MOW-AER-${today.replace(/-/g, '')}`);
|
|
await page.waitForLoadState('networkidle');
|
|
|
|
const flightCard = page.locator('[data-testid="flight-card"]').first();
|
|
await expect(flightCard).toBeVisible();
|
|
|
|
const depTime = flightCard.locator('[data-testid="scheduled-departure-time"]');
|
|
await expect(depTime).toBeVisible();
|
|
});
|
|
|
|
test('should display scheduled arrival time', async ({ page }) => {
|
|
await page.goto(`/ru-ru/onlineboard/route/MOW-AER-${today.replace(/-/g, '')}`);
|
|
await page.waitForLoadState('networkidle');
|
|
|
|
const flightCard = page.locator('[data-testid="flight-card"]').first();
|
|
await expect(flightCard).toBeVisible();
|
|
|
|
const arrTime = flightCard.locator('[data-testid="scheduled-arrival-time"]');
|
|
await expect(arrTime).toBeVisible();
|
|
});
|
|
|
|
test('should display flight duration', async ({ page }) => {
|
|
await page.goto(`/ru-ru/onlineboard/route/MOW-AER-${today.replace(/-/g, '')}`);
|
|
await page.waitForLoadState('networkidle');
|
|
|
|
const flightCard = page.locator('[data-testid="flight-card"]').first();
|
|
await expect(flightCard).toBeVisible();
|
|
|
|
const duration = flightCard.locator('[data-testid="flight-duration"]');
|
|
await expect(duration).toBeVisible();
|
|
});
|
|
});
|
|
|
|
test.describe('Error Handling', () => {
|
|
test('should handle invalid route parameters', async ({ page }) => {
|
|
await page.goto(`/ru-ru/onlineboard/route/XXX-YYY-${today.replace(/-/g, '')}`);
|
|
await page.waitForLoadState('networkidle');
|
|
|
|
const errorState = page.locator('[data-testid="error-state"]');
|
|
await expect(errorState).toBeVisible();
|
|
});
|
|
|
|
test('should handle network error', async ({ page }) => {
|
|
await page.route('**/api/flights/**', (route) => {
|
|
return route.abort('internetdisconnected');
|
|
});
|
|
|
|
await page.goto(`/ru-ru/onlineboard/route/MOW-AER-${today.replace(/-/g, '')}`);
|
|
await page.waitForLoadState('networkidle');
|
|
|
|
const networkError = page.locator('[data-testid="network-error"]');
|
|
await expect(networkError).toBeVisible();
|
|
});
|
|
});
|
|
|
|
test.describe('Accessibility', () => {
|
|
test('should have proper ARIA labels', async ({ page }) => {
|
|
await page.goto(`/ru-ru/onlineboard/route/MOW-AER-${today.replace(/-/g, '')}`);
|
|
await page.waitForLoadState('networkidle');
|
|
|
|
const flightCard = page.locator('[data-testid="flight-card"]').first();
|
|
await expect(flightCard).toHaveAttribute('role', 'article');
|
|
});
|
|
|
|
test('should be keyboard navigable', async ({ page }) => {
|
|
await page.goto(`/ru-ru/onlineboard/route/MOW-AER-${today.replace(/-/g, '')}`);
|
|
await page.waitForLoadState('networkidle');
|
|
|
|
await page.keyboard.press('Tab');
|
|
await page.keyboard.press('Tab');
|
|
await page.keyboard.press('Tab');
|
|
|
|
const focusedElement = page.locator(':focus');
|
|
await expect(focusedElement).toBeVisible();
|
|
});
|
|
});
|
|
});
|