import { test, expect } from '@playwright/test'; import type { Page } from '@playwright/test'; import { buildOnlineBoardPath, buildRouteParam, searchFlightByNumber, searchFlightByRoute, verifyFlightCard, generateFlight, generateFlights, getToday, getTomorrow, getYesterday, getFutureDate, getPastDate, CITIES, FIXTURES, } from '../support/test-utilities'; const today = getToday(); const tomorrow = getTomorrow(); const yesterday = getYesterday(); const futureDate = getFutureDate(7); const pastDate = getPastDate(7); const dateParam = buildRouteParam('MOW', today); const tomorrowParam = buildRouteParam('MOW', tomorrow); // ============================================================================ // Online Board - Arrival Tests (30+ tests) // ============================================================================ test.describe('Online Board - Arrival', () => { test.describe('Category 1: Basic Arrival Search', () => { test('Should search by city name (manual input) (Test 1)', async ({ page }) => { await page.goto(`/ru-ru${buildOnlineBoardPath('arrival', 'MOW', today)}`); await page.waitForLoadState('networkidle'); await expect(page).toHaveURL(/arrival\/MOW-\d{8}/); await expect(page).toHaveTitle(/Прибытие/); }); test('Should search by city from autocomplete list (Test 2)', async ({ page }) => { await page.goto(`/ru-ru${buildOnlineBoardPath('arrival', 'LED', today)}`); await page.waitForLoadState('networkidle'); await expect(page).toHaveURL(/arrival\/LED-\d{8}/); }); test('Should search with today date (Test 3)', async ({ page }) => { await page.goto(`/ru-ru${buildOnlineBoardPath('arrival', 'AER', today)}`); await page.waitForLoadState('networkidle'); await expect(page).toHaveURL(/arrival\/AER-\d{8}/); }); test('Should search with future date (Test 4)', async ({ page }) => { await page.goto(`/ru-ru${buildOnlineBoardPath('arrival', 'MOW', futureDate)}`); await page.waitForLoadState('networkidle'); await expect(page).toHaveURL(/arrival\/MOW-\d{8}/); }); test('Should search with past date and show validation (Test 5)', async ({ page }) => { await page.goto(`/ru-ru${buildOnlineBoardPath('arrival', 'MOW', pastDate)}`); await page.waitForLoadState('networkidle'); await expect(page).toHaveURL(/arrival\/MOW-\d{8}/); }); test('Should search without date and use today (Test 6)', async ({ page }) => { await page.goto(`/ru-ru/onlineboard/arrival/MOW`); await page.waitForLoadState('networkidle'); await expect(page).toHaveURL(/arrival\/MOW-\d{8}/); }); test('Should search with invalid city and show error (Test 7)', async ({ page }) => { await page.goto(`/ru-ru/onlineboard/arrival/XXX-${today.replace(/-/g, '')}`); await page.waitForLoadState('networkidle'); const errorState = page.locator('[data-testid="error-state"]'); await expect(errorState).toBeVisible(); }); test('Should search with empty city and show validation (Test 8)', async ({ page }) => { await page.goto(`/ru-ru/onlineboard/arrival/-${today.replace(/-/g, '')}`); await page.waitForLoadState('networkidle'); const errorState = page.locator('[data-testid="error-state"]'); await expect(errorState).toBeVisible(); }); }); test.describe('Category 2: Date Selection', () => { test('Should select date from calendar (Test 9)', async ({ page }) => { await page.goto(`/ru-ru${buildOnlineBoardPath('arrival', 'MOW', today)}`); await page.waitForLoadState('networkidle'); const calendarInput = page.locator('[data-testid="calendar-input"]'); await expect(calendarInput).toBeVisible(); }); test('Should select date range (Test 10)', async ({ page }) => { await page.goto(`/ru-ru${buildOnlineBoardPath('arrival', 'MOW', today)}`); await page.waitForLoadState('networkidle'); const dateRange = page.locator('[data-testid="date-range"]'); await expect(dateRange).toBeVisible(); }); test('Should verify date format DD.MM.YYYY (Test 11)', async ({ page }) => { await page.goto(`/ru-ru${buildOnlineBoardPath('arrival', 'MOW', today)}`); await page.waitForLoadState('networkidle'); const dateText = page.locator('[data-testid="board-date"]'); await expect(dateText).toBeVisible(); const dateValue = await dateText.textContent(); expect(dateValue).toMatch(/\d{2}\.\d{2}\.\d{4}/); }); test('Should verify date validation min/max dates (Test 12)', async ({ page }) => { await page.goto(`/ru-ru${buildOnlineBoardPath('arrival', 'MOW', today)}`); await page.waitForLoadState('networkidle'); const calendarInput = page.locator('[data-testid="calendar-input"]'); await expect(calendarInput).toBeEnabled(); }); test('Should select today date (Test 13)', async ({ page }) => { await page.goto(`/ru-ru${buildOnlineBoardPath('arrival', 'MOW', today)}`); await page.waitForLoadState('networkidle'); const todayTab = page.locator(`[data-testid="date-tab-${today.replace(/-/g, '')}"]`); await expect(todayTab).toBeVisible(); }); test('Should select tomorrow date (Test 14)', async ({ page }) => { await page.goto(`/ru-ru${buildOnlineBoardPath('arrival', 'MOW', tomorrow)}`); await page.waitForLoadState('networkidle'); const tomorrowTab = page.locator(`[data-testid="date-tab-${tomorrow.replace(/-/g, '')}"]`); await expect(tomorrowTab).toBeVisible(); }); }); test.describe('Category 3: Flight Results', () => { test('Should verify flight results display (Test 15)', async ({ page }) => { await page.goto(`/ru-ru${buildOnlineBoardPath('arrival', 'MOW', today)}`); await page.waitForLoadState('networkidle'); const flightCards = page.locator('[data-testid="flight-card"]'); await expect(flightCards).toHaveCount(20); }); test('Should verify flight count (Test 16)', async ({ page }) => { await page.goto(`/ru-ru${buildOnlineBoardPath('arrival', 'MOW', today)}`); await page.waitForLoadState('networkidle'); const flightCards = page.locator('[data-testid="flight-card"]'); await expect(flightCards).toHaveCount(20); }); test('Should verify flight details in results (Test 17)', async ({ page }) => { await page.goto(`/ru-ru${buildOnlineBoardPath('arrival', '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 verify empty results message (Test 18)', async ({ page }) => { await page.goto(`/ru-ru${buildOnlineBoardPath('arrival', '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('Should verify loading state (Test 19)', async ({ page }) => { await page.goto(`/ru-ru${buildOnlineBoardPath('arrival', 'MOW', today)}`); await page.waitForLoadState('networkidle'); const loadingSpinner = page.locator('[data-testid="loading-spinner"]'); await expect(loadingSpinner).toBeVisible(); }); test('Should verify error state (Test 20)', async ({ page }) => { await page.route('**/api/flights/**', (route) => { return route.abort('internetdisconnected'); }); await page.goto(`/ru-ru${buildOnlineBoardPath('arrival', 'MOW', today)}`); await page.waitForLoadState('networkidle'); const networkError = page.locator('[data-testid="network-error"]'); await expect(networkError).toBeVisible(); }); }); test.describe('Category 4: Flight Details', () => { test('Should open flight details from results (Test 21)', async ({ page }) => { await page.goto(`/ru-ru${buildOnlineBoardPath('arrival', 'MOW', today)}`); await page.waitForLoadState('networkidle'); const flightCard = page.locator('[data-testid="flight-card"]').first(); await flightCard.click(); await page.waitForLoadState('networkidle'); await expect(page).toHaveURL(/\/ru-ru\/[A-Z]{2}\s?\d+-\d{8}/); }); test('Should verify flight details content (Test 22)', async ({ page }) => { const flight = generateFlight({ direction: 'arrival', cityCode: 'MOW' }); await page.goto(`/ru-ru${buildOnlineBoardPath('arrival', 'MOW', today)}`); await page.waitForLoadState('networkidle'); await searchFlightByNumber(page, flight.flightNumber); const flightCard = page.locator('[data-testid="flight-card"]').first(); await flightCard.click(); await page.waitForLoadState('networkidle'); await expect(page.getByText(flight.flightNumber)).toBeVisible(); await expect(page.getByText(flight.airlineName)).toBeVisible(); }); test('Should verify flight route details (Test 23)', async ({ page }) => { const flight = generateFlight({ direction: 'arrival', cityCode: 'MOW' }); await page.goto(`/ru-ru${buildOnlineBoardPath('arrival', 'MOW', today)}`); await page.waitForLoadState('networkidle'); await searchFlightByNumber(page, flight.flightNumber); const flightCard = page.locator('[data-testid="flight-card"]').first(); await flightCard.click(); await page.waitForLoadState('networkidle'); await expect(page.getByText(flight.departure.cityName)).toBeVisible(); await expect(page.getByText(flight.arrival.cityName)).toBeVisible(); }); test('Should verify flight status details (Test 24)', async ({ page }) => { const flight = generateFlight({ direction: 'arrival', cityCode: 'MOW', status: 'scheduled', }); await page.goto(`/ru-ru${buildOnlineBoardPath('arrival', 'MOW', today)}`); await page.waitForLoadState('networkidle'); await searchFlightByNumber(page, flight.flightNumber); const flightCard = page.locator('[data-testid="flight-card"]').first(); await flightCard.click(); await page.waitForLoadState('networkidle'); await expect(page.getByText(flight.status)).toBeVisible(); }); test('Should close flight details (Test 25)', async ({ page }) => { await page.goto(`/ru-ru${buildOnlineBoardPath('arrival', 'MOW', today)}`); await page.waitForLoadState('networkidle'); const flightCard = page.locator('[data-testid="flight-card"]').first(); await flightCard.click(); await page.waitForLoadState('networkidle'); const closeBtn = page.locator('[data-testid="close-details-btn"]'); await closeBtn.click(); await page.waitForLoadState('networkidle'); await expect(page).toHaveURL(/arrival\/MOW-\d{8}/); }); }); test.describe('Category 5: Edge Cases', () => { test('Should search for non-existent city (Test 26)', async ({ page }) => { await page.goto(`/ru-ru/onlineboard/arrival/XXX-${today.replace(/-/g, '')}`); await page.waitForLoadState('networkidle'); const errorState = page.locator('[data-testid="error-state"]'); await expect(errorState).toBeVisible(); }); test('Should search with special characters (Test 27)', async ({ page }) => { await page.goto(`/ru-ru${buildOnlineBoardPath('arrival', 'MOW', today)}`); await page.waitForLoadState('networkidle'); const searchInput = page.locator('[data-testid="flight-search-input"]'); await searchInput.fill('SU 123!'); await searchInput.press('Enter'); await page.waitForLoadState('networkidle'); const noResults = page.locator('[data-testid="no-results"]'); await expect(noResults).toBeVisible(); }); test('Should search with very long city name (Test 28)', async ({ page }) => { const longCityName = 'Москва'.repeat(10); await page.goto(`/ru-ru${buildOnlineBoardPath('arrival', 'MOW', today)}`); await page.waitForLoadState('networkidle'); const searchInput = page.locator('[data-testid="flight-search-input"]'); await searchInput.fill(longCityName); await searchInput.press('Enter'); await page.waitForLoadState('networkidle'); const flightCards = page.locator('[data-testid="flight-card"]'); await expect(flightCards).toHaveCount(20); }); test('Should search with Unicode characters (Test 29)', async ({ page }) => { await page.goto(`/ru-ru${buildOnlineBoardPath('arrival', 'MOW', today)}`); await page.waitForLoadState('networkidle'); const searchInput = page.locator('[data-testid="flight-search-input"]'); await searchInput.fill('SU 1234 🛫'); await searchInput.press('Enter'); await page.waitForLoadState('networkidle'); const flightCards = page.locator('[data-testid="flight-card"]'); await expect(flightCards).toHaveCount(20); }); test('Should handle rapid search attempts (Test 30)', async ({ page }) => { await page.goto(`/ru-ru${buildOnlineBoardPath('arrival', 'MOW', today)}`); await page.waitForLoadState('networkidle'); const searchInput = page.locator('[data-testid="flight-search-input"]'); for (let i = 0; i < 5; i++) { await searchInput.fill(`SU ${1000 + i}`); await searchInput.press('Enter'); await page.waitForLoadState('networkidle'); } const flightCards = page.locator('[data-testid="flight-card"]'); await expect(flightCards).toHaveCount(20); }); }); test.describe('Additional Arrival Tests', () => { test('Should navigate to arrival board for different cities (Test 31)', async ({ page }) => { const cities = ['MOW', 'LED', 'AER', 'OVB', 'KRR']; for (const cityCode of cities) { await page.goto(`/ru-ru${buildOnlineBoardPath('arrival', cityCode, today)}`); await page.waitForLoadState('networkidle'); await expect(page).toHaveURL(new RegExp(`arrival/${cityCode}-\\d{8}`)); } }); test('Should display correct date in title (Test 32)', async ({ page }) => { await page.goto(`/ru-ru${buildOnlineBoardPath('arrival', 'MOW', today)}`); await page.waitForLoadState('networkidle'); const dateText = page.locator('[data-testid="board-date"]'); await expect(dateText).toBeVisible(); await expect(dateText).toContainText(today); }); test('Should filter by status (Test 33)', async ({ page }) => { await page.goto(`/ru-ru${buildOnlineBoardPath('arrival', '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 (Test 34)', async ({ page }) => { await page.goto(`/ru-ru${buildOnlineBoardPath('arrival', '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('Should display flight number (Test 35)', async ({ page }) => { await page.goto(`/ru-ru${buildOnlineBoardPath('arrival', '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 (Test 36)', async ({ page }) => { await page.goto(`/ru-ru${buildOnlineBoardPath('arrival', '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 (Test 37)', async ({ page }) => { await page.goto(`/ru-ru${buildOnlineBoardPath('arrival', 'MOW', today)}`); 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 time (Test 38)', async ({ page }) => { await page.goto(`/ru-ru${buildOnlineBoardPath('arrival', '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 (Test 39)', async ({ page }) => { const flight = generateFlight({ direction: 'arrival', cityCode: 'MOW', status: 'arrived', }); await page.goto(`/ru-ru${buildOnlineBoardPath('arrival', '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 (Test 40)', async ({ page }) => { const flight = generateFlight({ direction: 'arrival', cityCode: 'MOW', status: 'delayed', }); await page.goto(`/ru-ru${buildOnlineBoardPath('arrival', '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 (Test 41)', async ({ page }) => { await page.goto(`/ru-ru${buildOnlineBoardPath('arrival', '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 baggage belt information (Test 42)', async ({ page }) => { const flight = generateFlight({ direction: 'arrival', cityCode: 'MOW', status: 'arrived', }); await page.goto(`/ru-ru${buildOnlineBoardPath('arrival', 'MOW', today)}`); await page.waitForLoadState('networkidle'); const flightCard = page.locator('[data-testid="flight-card"]').first(); await expect(flightCard).toBeVisible(); const baggageBelt = flightCard.locator('[data-testid="baggage-belt"]'); await expect(baggageBelt).toBeVisible(); }); test('Should navigate to tomorrow date tab (Test 43)', async ({ page }) => { await page.goto(`/ru-ru${buildOnlineBoardPath('arrival', '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(/arrival\/MOW-\d{8}/); } }); test('Should handle invalid city code (Test 44)', async ({ page }) => { await page.goto(`/ru-ru/onlineboard/arrival/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 (Test 45)', async ({ page }) => { await page.route('**/api/flights/**', (route) => { return route.abort('internetdisconnected'); }); await page.goto(`/ru-ru${buildOnlineBoardPath('arrival', 'MOW', today)}`); await page.waitForLoadState('networkidle'); const networkError = page.locator('[data-testid="network-error"]'); await expect(networkError).toBeVisible(); }); test('Should have proper ARIA labels (Test 46)', async ({ page }) => { await page.goto(`/ru-ru${buildOnlineBoardPath('arrival', '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 (Test 47)', async ({ page }) => { await page.goto(`/ru-ru${buildOnlineBoardPath('arrival', '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(); }); test('Should search by flight number (Test 48)', async ({ page }) => { const flight = generateFlight({ direction: 'arrival', cityCode: 'MOW' }); await page.goto(`/ru-ru${buildOnlineBoardPath('arrival', '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 (Test 49)', async ({ page }) => { await page.goto(`/ru-ru${buildOnlineBoardPath('arrival', '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('Should search by route (Test 50)', async ({ page }) => { await page.goto(`/ru-ru${buildOnlineBoardPath('arrival', 'MOW', today)}`); await page.waitForLoadState('networkidle'); await searchFlightByRoute(page, 'Moscow', 'Sochi'); const flightCards = page.locator('[data-testid="flight-card"]'); await expect(flightCards).toHaveCount(20); }); }); });