Files
gnezim 712d32ac72 Add popular requests behavioral cross-app tests
Adds POPULAR_REQUESTS_PANEL and POPULAR_REQUEST_ITEM selectors with
Angular overrides, and 6 behavioral tests covering panel visibility,
item count, flight/route click navigation, schedule page presence,
and keyboard accessibility.
2026-04-16 17:44:04 +03:00

194 lines
7.7 KiB
TypeScript

/**
* Canonical data-testid selector map for cross-app e2e tests.
*
* Both Angular and React apps must implement these testids.
* Where Angular uses a different testid, add an entry to ANGULAR_OVERRIDES.
*/
export const S = {
// Navigation & Layout
NAV_ONLINEBOARD_TAB: 'nav-onlineboard-tab',
NAV_SCHEDULE_TAB: 'nav-schedule-tab',
NAV_FLIGHTS_MAP_TAB: 'nav-flights-map-tab',
LAYOUT_BREADCRUMBS: 'layout-breadcrumbs',
LAYOUT_FEEDBACK_BUTTON: 'layout-feedback-button',
LAYOUT_SCROLL_TOP_BUTTON: 'layout-scroll-top-button',
LAYOUT_LOCALE_SWITCHER: 'layout-locale-switcher',
LAYOUT_LOCALE_OPTION: 'layout-locale-option',
// Online Board - Filter
FILTER_ACCORDION: 'filter-accordion',
FILTER_FLIGHT_TAB: 'filter-flight-tab',
FILTER_ROUTE_TAB: 'filter-route-tab',
FILTER_FLIGHT_NUMBER_INPUT: 'filter-flight-number-input',
FILTER_FLIGHT_NUMBER_CLEAR: 'filter-flight-number-clear',
FILTER_FLIGHT_NUMBER_CALENDAR: 'filter-flight-number-calendar',
FILTER_FLIGHT_NUMBER_SEARCH: 'filter-flight-number-search',
FILTER_ROUTE_DEPARTURE_INPUT: 'filter-route-departure-input',
FILTER_ROUTE_ARRIVAL_INPUT: 'filter-route-arrival-input',
FILTER_ROUTE_SWAP_BUTTON: 'filter-route-swap-button',
FILTER_ROUTE_CALENDAR: 'filter-route-calendar',
FILTER_ROUTE_TIME_SELECTOR: 'filter-route-time-selector',
FILTER_ROUTE_SEARCH: 'filter-route-search',
// Online Board - Results
BOARD_DAY_TABS: 'board-day-tabs',
BOARD_DAY_TAB: 'board-day-tab',
BOARD_TIME_SELECTOR: 'board-time-selector',
BOARD_SEARCH_RESULT: 'board-search-result',
BOARD_FLIGHT_RESULT: 'board-flight-result',
BOARD_FLIGHT_NUMBER: 'board-flight-number',
BOARD_FLIGHT_STATUS: 'board-flight-status',
BOARD_FLIGHT_EXPAND: 'board-flight-expand',
BOARD_LOADER: 'board-loader',
BOARD_EMPTY_LIST: 'board-empty-list',
BOARD_CANCEL_BUTTON: 'board-cancel-button',
// Flight Details
DETAILS_FLIGHT_NUMBER: 'details-flight-number',
DETAILS_DEPARTURE_STATION: 'details-departure-station',
DETAILS_ARRIVAL_STATION: 'details-arrival-station',
DETAILS_DEPARTURE_TIME: 'details-departure-time',
DETAILS_ARRIVAL_TIME: 'details-arrival-time',
DETAILS_STATUS: 'details-status',
DETAILS_DURATION: 'details-duration',
DETAILS_OPERATOR_LOGO: 'details-operator-logo',
DETAILS_AIRCRAFT_MODEL: 'details-aircraft-model',
DETAILS_PRINT_BUTTON: 'details-print-button',
DETAILS_SHARE_BUTTON: 'details-share-button',
DETAILS_BUY_TICKET_BUTTON: 'details-buy-ticket-button',
DETAILS_REGISTRATION_BUTTON: 'details-registration-button',
DETAILS_FLIGHT_STATUS_BUTTON: 'details-flight-status-button',
DETAILS_TRANSFER_SECTION: 'details-transfer-section',
DETAILS_FULL_ROUTE: 'details-full-route',
DETAILS_TERMINAL_LINK: 'details-terminal-link',
// Landing Page
LANDING_SECTION: 'landing-section',
LANDING_POPULAR_REQUEST: 'landing-popular-request',
LANDING_SEARCH_HISTORY: 'landing-search-history',
LANDING_SEARCH_HISTORY_ITEM: 'landing-search-history-item',
// Popular Requests
POPULAR_REQUESTS_PANEL: 'popular-requests-panel',
POPULAR_REQUEST_ITEM: 'popular-request-item',
// Schedule - Filter
SCHEDULE_DEPARTURE_INPUT: 'schedule-departure-input',
SCHEDULE_ARRIVAL_INPUT: 'schedule-arrival-input',
SCHEDULE_SWAP_BUTTON: 'schedule-swap-button',
SCHEDULE_CALENDAR: 'schedule-calendar',
SCHEDULE_RETURN_CALENDAR: 'schedule-return-calendar',
SCHEDULE_TIME_SELECTOR: 'schedule-time-selector',
SCHEDULE_RETURN_TIME_SELECTOR: 'schedule-return-time-selector',
SCHEDULE_DIRECT_ONLY_CHECKBOX: 'schedule-direct-only-checkbox',
SCHEDULE_RETURN_CHECKBOX: 'schedule-return-checkbox',
SCHEDULE_SEARCH_BUTTON: 'schedule-search-button',
// Schedule - Results
SCHEDULE_WEEK_TABS: 'schedule-week-tabs',
SCHEDULE_WEEK_TAB: 'schedule-week-tab',
SCHEDULE_WEEK_PREV: 'schedule-week-prev',
SCHEDULE_WEEK_NEXT: 'schedule-week-next',
SCHEDULE_DIRECTION_SWITCH: 'schedule-direction-switch',
SCHEDULE_SORT_DROPDOWN: 'schedule-sort-dropdown',
SCHEDULE_FLIGHT_DAY: 'schedule-flight-day',
SCHEDULE_FLIGHT_ITEM: 'schedule-flight-item',
SCHEDULE_LOADER: 'schedule-loader',
// Schedule - Details
SCHEDULE_DETAILS_BACK_BUTTON: 'schedule-details-back-button',
SCHEDULE_DETAILS_DAY_TABS: 'schedule-details-day-tabs',
SCHEDULE_DETAILS_FLIGHT_MINI: 'schedule-details-flight-mini',
SCHEDULE_DETAILS_TRANSFER: 'schedule-details-transfer',
// Flights Map
MAP_CONTAINER: 'map-container',
MAP_DEPARTURE_INPUT: 'map-departure-input',
MAP_ARRIVAL_INPUT: 'map-arrival-input',
MAP_SWAP_BUTTON: 'map-swap-button',
MAP_CALENDAR: 'map-calendar',
MAP_DOMESTIC_TOGGLE: 'map-domestic-toggle',
MAP_INTERNATIONAL_TOGGLE: 'map-international-toggle',
MAP_CONNECTING_TOGGLE: 'map-connecting-toggle',
MAP_MARKER: 'map-marker',
MAP_MARKER_CLUSTER: 'map-marker-cluster',
// Shared Components
CITY_AUTOCOMPLETE_INPUT: 'city-autocomplete-input',
CITY_AUTOCOMPLETE_POPUP: 'city-autocomplete-popup',
CITY_AUTOCOMPLETE_CLEAR: 'city-autocomplete-clear',
CITY_AUTOCOMPLETE_OPTION: 'city-autocomplete-option',
CITY_CODE_DISPLAY: 'city-code-display',
TIME_SELECTOR_FROM: 'time-selector-from',
TIME_SELECTOR_TO: 'time-selector-to',
TIME_SELECTOR_TRACK: 'time-selector-track',
CALENDAR_INPUT: 'calendar-input',
CALENDAR_CLEAR: 'calendar-clear',
// Error Pages
ERROR_PAGE_404: 'error-page-404',
ERROR_PAGE_GENERIC: 'error-page-generic',
ERROR_PAGE_HOME_LINK: 'error-page-home-link',
} as const;
export type SelectorKey = keyof typeof S;
/**
* Angular app uses different testid names in some places.
* This map translates canonical names to Angular-specific ones.
*/
const ANGULAR_OVERRIDES: Partial<Record<string, string>> = {
[S.NAV_ONLINEBOARD_TAB]: 'onlineboard-tab',
[S.NAV_SCHEDULE_TAB]: 'schedule-tab',
[S.NAV_FLIGHTS_MAP_TAB]: 'flights-map-tab',
[S.FILTER_FLIGHT_TAB]: 'flight-filter',
[S.FILTER_ROUTE_TAB]: 'route-filter',
[S.FILTER_FLIGHT_NUMBER_INPUT]: 'flight-number-input',
[S.FILTER_FLIGHT_NUMBER_CLEAR]: 'flight-number-clear-button',
[S.FILTER_FLIGHT_NUMBER_CALENDAR]: 'flight-number-calendar',
[S.FILTER_FLIGHT_NUMBER_SEARCH]: 'flight-number-search-button',
[S.FILTER_ROUTE_DEPARTURE_INPUT]: 'route-departure-city-input',
[S.FILTER_ROUTE_ARRIVAL_INPUT]: 'route-arrival-city-input',
[S.FILTER_ROUTE_CALENDAR]: 'route-calendar-input',
[S.FILTER_ROUTE_SEARCH]: 'route-search-button',
[S.SCHEDULE_DEPARTURE_INPUT]: 'schedule-departure-city-input',
[S.SCHEDULE_ARRIVAL_INPUT]: 'schedule-arrival-city-input',
[S.SCHEDULE_SEARCH_BUTTON]: 'schedule-search-button',
[S.MAP_DEPARTURE_INPUT]: 'route-departure-city-input',
[S.MAP_ARRIVAL_INPUT]: 'route-arrival-city-input',
[S.MAP_CALENDAR]: 'route-calendar-input',
[S.POPULAR_REQUESTS_PANEL]: 'popular-requests',
[S.POPULAR_REQUEST_ITEM]: 'popular-request',
[S.BOARD_LOADER]: 'loader',
[S.BOARD_SEARCH_RESULT]: 'board-search-result',
[S.BOARD_FLIGHT_RESULT]: 'flight-result',
[S.BOARD_FLIGHT_NUMBER]: 'flight-carrier-number',
[S.DETAILS_FLIGHT_NUMBER]: 'flight-details-number',
[S.CITY_AUTOCOMPLETE_INPUT]: 'city-autocomplete-input',
[S.CITY_AUTOCOMPLETE_CLEAR]: 'autocomplete-clear-input',
[S.CITY_AUTOCOMPLETE_POPUP]: 'autocomplete-popup-button',
[S.CITY_CODE_DISPLAY]: 'city-code',
[S.CALENDAR_INPUT]: 'calendar-input',
};
/**
* Get the data-testid selector string for a given app.
* Returns `[data-testid="..."]` ready for use with page.locator().
*/
export function tid(name: string, app: 'angular' | 'react'): string {
const testid = app === 'angular' && ANGULAR_OVERRIDES[name] ? ANGULAR_OVERRIDES[name] : name;
return `[data-testid="${testid}"]`;
}
/**
* Shorthand: get locator from page using canonical testid.
*/
export function byTestId(
page: { locator: (s: string) => unknown },
name: string,
app: 'angular' | 'react',
) {
return page.locator(tid(name, app));
}