import { test, expect } from '@playwright/test'; import type { Page } from '@playwright/test'; import { buildOnlineBoardPath, buildRouteParam, searchFlightByNumber, 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 - Departure Tests // ============================================================================ test.describe('Online Board - Departure', () => { test.describe('Page Navigation', () => { test('should navigate to departure board for Moscow', async ({ page }) => { await page.goto(`/ru-ru${buildOnlineBoardPath('departure', 'MOW', today)}`); await page.waitForLoadState('networkidle'); await expect(page).toHaveURL(/departure\/MOW-\d{8}/); await expect(page).toHaveTitle(/Отправление/); }); test('should navigate to departure board for Saint Petersburg', async ({ page }) => { await page.goto(`/ru-ru${buildOnlineBoardPath('departure', 'LED', today)}`); await page.waitForLoadState('networkidle'); await expect(page).toHaveURL(/departure\/LED-\d{8}/); }); test('should navigate to departure board for Sochi', async ({ page }) => { await page.goto(`/ru-ru${buildOnlineBoardPath('departure', 'AER', today)}`); await page.waitForLoadState('networkidle'); await expect(page).toHaveURL(/departure\/AER-\d{8}/); }); }); test.describe('Flight Display', () => { test('should display departure flights for Moscow', async ({ page }) => { await page.goto(`/ru-ru${buildOnlineBoardPath('departure', 'MOW', today)}`); await page.waitForLoadState('networkidle'); const flightCards = page.locator('[data-testid="flight-card"]'); await expect(flightCards).toHaveCount(20); }); test('should display flight details correctly', async ({ page }) => { await page.goto(`/ru-ru${buildOnlineBoardPath('departure', 'MOW', today)}`); await page.waitForLoadState('networkidle'); const flightCard = page.locator('[data-testid="flight-card"]').first(); await expect(flightCard).toBeVisible(); await expect(flightCard.getByText('Отправление')).toBeVisible(); }); }); test.describe('Flight Search', () => { test('should search flight by flight number', async ({ page }) => { const flight = generateFlight({ direction: 'departure', cityCode: 'MOW' }); await page.goto(`/ru-ru${buildOnlineBoardPath('departure', 'MOW', today)}`); await page.waitForLoadState('networkidle'); await searchFlightByNumber(page, flight.flightNumber); const searchResults = page.locator('[data-testid="flight-card"]'); await expect(searchResults).toHaveCount(1); await verifyFlightCard(page, flight); }); test('should show no results when flight not found', async ({ page }) => { await page.goto(`/ru-ru${buildOnlineBoardPath('departure', 'MOW', today)}`); await page.waitForLoadState('networkidle'); await searchFlightByNumber(page, 'SU 9999'); const noResults = page.locator('[data-testid="no-results"]'); await expect(noResults).toBeVisible(); await expect(noResults).toContainText('Нет результатов'); }); }); test.describe('Date Navigation', () => { test('should navigate to tomorrow', async ({ page }) => { await page.goto(`/ru-ru${buildOnlineBoardPath('departure', 'MOW', today)}`); 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(/departure\/MOW-\d{8}/); } }); test('should display correct date in title', async ({ page }) => { await page.goto(`/ru-ru${buildOnlineBoardPath('departure', 'MOW', today)}`); 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${buildOnlineBoardPath('departure', 'MOW', today)}`); 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${buildOnlineBoardPath('departure', 'MOW', today)}`); 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.describe('Flight Card', () => { test('should display flight number', async ({ page }) => { await page.goto(`/ru-ru${buildOnlineBoardPath('departure', 'MOW', today)}`); 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${buildOnlineBoardPath('departure', 'MOW', today)}`); 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 and arrival cities', async ({ page }) => { await page.goto(`/ru-ru${buildOnlineBoardPath('departure', 'MOW', today)}`); 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 scheduled time', async ({ page }) => { await page.goto(`/ru-ru${buildOnlineBoardPath('departure', 'MOW', today)}`); await page.waitForLoadState('networkidle'); const flightCard = page.locator('[data-testid="flight-card"]').first(); await expect(flightCard).toBeVisible(); const scheduledTime = flightCard.locator('[data-testid="scheduled-time"]'); await expect(scheduledTime).toBeVisible(); }); test('should display actual time when available', async ({ page }) => { const flight = generateFlight({ direction: 'departure', cityCode: 'MOW', status: 'departed', }); await page.goto(`/ru-ru${buildOnlineBoardPath('departure', 'MOW', today)}`); await page.waitForLoadState('networkidle'); const flightCard = page.locator('[data-testid="flight-card"]').first(); await expect(flightCard).toBeVisible(); const actualTime = flightCard.locator('[data-testid="actual-time"]'); await expect(actualTime).toBeVisible(); }); test('should display delay information', async ({ page }) => { const flight = generateFlight({ direction: 'departure', cityCode: 'MOW', status: 'delayed', }); await page.goto(`/ru-ru${buildOnlineBoardPath('departure', 'MOW', today)}`); await page.waitForLoadState('networkidle'); const flightCard = page.locator('[data-testid="flight-card"]').first(); await expect(flightCard).toBeVisible(); const delayInfo = flightCard.locator('[data-testid="delay-info"]'); await expect(delayInfo).toBeVisible(); }); test('should display terminal information', async ({ page }) => { await page.goto(`/ru-ru${buildOnlineBoardPath('departure', 'MOW', today)}`); await page.waitForLoadState('networkidle'); const flightCard = page.locator('[data-testid="flight-card"]').first(); await expect(flightCard).toBeVisible(); const terminal = flightCard.locator('[data-testid="terminal"]'); await expect(terminal).toBeVisible(); }); test('should display boarding gate information', async ({ page }) => { const flight = generateFlight({ direction: 'departure', cityCode: 'MOW', status: 'boarding', }); await page.goto(`/ru-ru${buildOnlineBoardPath('departure', 'MOW', today)}`); await page.waitForLoadState('networkidle'); const flightCard = page.locator('[data-testid="flight-card"]').first(); await expect(flightCard).toBeVisible(); const boardingGate = flightCard.locator('[data-testid="boarding-gate"]'); await expect(boardingGate).toBeVisible(); }); }); test.describe('Error Handling', () => { test('should handle invalid city code', async ({ page }) => { await page.goto(`/ru-ru/onlineboard/departure/XXX-${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${buildOnlineBoardPath('departure', 'MOW', today)}`); 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${buildOnlineBoardPath('departure', 'MOW', today)}`); 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${buildOnlineBoardPath('departure', 'MOW', today)}`); 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(); }); }); });