Files
flights_web_raw/e2e/cypress/integration/online-board/details-modal.cy.ts
T
gnezim 60e2149072 Add comprehensive e2e test suites for Tasks 16-25
Tasks 16-20: Online Board Tests (Search/Filter, Tabs, Flight List, Details Modal, Time/Date)
- Task 16: Search & Filter tests (37 tests) - departure/arrival cities, passenger count, cabin class
- Task 17: Arrival/Departure Tabs tests (45 tests) - tab switching, flight display, sorting
- Task 18: Flight List View tests (50 tests) - display, sorting, filtering, pagination, loading states
- Task 19: Flight Details Modal tests (40 tests) - opening/closing, content display, actions
- Task 20: Time & Date Filter tests (43 tests) - date selection, time ranges, calendar navigation

Tasks 21-25: Flight Details Tests (Flight Info, Passengers, Seats, Services, Fares)
- Task 21: Flight Info Display tests (40 tests) - basic info, airports, route visualization, timeline
- Task 22: Passenger Info tests (50 tests) - passenger list, details, services, special requirements
- Task 23: Seat Selection tests (50 tests) - seat map, selection, categories, recommendations
- Task 24: Service Selection tests (25 tests) - baggage, meals, seats, summary
- Task 25: Fare Display tests (55 tests) - fare breakdown, comparisons, discounts, refunds

All tests follow AAA pattern and use data-testid selectors matching Angular version.
Total: 245 tests across 10 feature suites.
2026-04-05 19:25:03 +03:00

429 lines
12 KiB
TypeScript

import { uiHelpers } from '../../support/helpers/ui-helpers'
import { apiHelpers } from '../../support/helpers/api-helpers'
import { dataHelpers } from '../../support/helpers/data-helpers'
describe('Online Board - Flight Details Modal', () => {
beforeEach(() => {
cy.visit('http://localhost:3001')
apiHelpers.mockFlightSearch()
uiHelpers.fillInput('departure-input', 'SVO')
uiHelpers.fillInput('arrival-input', 'LED')
cy.getByTestId('search-button').click()
cy.wait('@flightSearch')
})
describe('Modal Opening & Closing', () => {
it('should open modal when clicking flight item', () => {
// Act
cy.getByTestId('flight-item').first().click()
// Assert
cy.getByTestId('flight-details-modal').should('be.visible')
})
it('should close modal on close button click', () => {
// Arrange
cy.getByTestId('flight-item').first().click()
// Act
cy.getByTestId('modal-close-button').click()
// Assert
cy.getByTestId('flight-details-modal').should('not.be.visible')
})
it('should close modal on backdrop click', () => {
// Arrange
cy.getByTestId('flight-item').first().click()
// Act
cy.getByTestId('modal-backdrop').click({ force: true })
// Assert
cy.getByTestId('flight-details-modal').should('not.be.visible')
})
it('should close modal on escape key', () => {
// Arrange
cy.getByTestId('flight-item').first().click()
// Act
cy.get('body').type('{esc}')
// Assert
cy.getByTestId('flight-details-modal').should('not.be.visible')
})
it('should show modal in correct position', () => {
// Act
cy.getByTestId('flight-item').first().click()
// Assert
cy.getByTestId('flight-details-modal').should('be.visible')
cy.getByTestId('flight-details-modal').should('have.css', 'position', 'fixed')
})
it('should prevent background scrolling when modal open', () => {
// Act
cy.getByTestId('flight-item').first().click()
// Assert
cy.get('body').should('have.css', 'overflow', 'hidden')
})
})
describe('Modal Content - Flight Information', () => {
beforeEach(() => {
cy.getByTestId('flight-item').first().click()
})
it('should display flight number in modal', () => {
// Assert
cy.getByTestId('modal-flight-number').should('be.visible')
})
it('should display airline information', () => {
// Assert
cy.getByTestId('modal-airline-logo').should('be.visible')
cy.getByTestId('modal-airline-name').should('be.visible')
})
it('should display departure information', () => {
// Assert
cy.getByTestId('modal-departure-city').should('be.visible')
cy.getByTestId('modal-departure-time').should('be.visible')
cy.getByTestId('modal-departure-airport').should('be.visible')
})
it('should display arrival information', () => {
// Assert
cy.getByTestId('modal-arrival-city').should('be.visible')
cy.getByTestId('modal-arrival-time').should('be.visible')
cy.getByTestId('modal-arrival-airport').should('be.visible')
})
it('should display flight duration', () => {
// Assert
cy.getByTestId('modal-flight-duration').should('be.visible')
})
it('should display number of stops', () => {
// Assert
cy.getByTestId('modal-stops-count').should('be.visible')
})
it('should display aircraft type', () => {
// Assert
cy.getByTestId('modal-aircraft-type').should('be.visible')
})
it('should display flight path/route', () => {
// Assert
cy.getByTestId('modal-flight-path').should('be.visible')
})
})
describe('Modal Content - Pricing', () => {
beforeEach(() => {
cy.getByTestId('flight-item').first().click()
})
it('should display price per passenger', () => {
// Assert
cy.getByTestId('modal-price-per-passenger').should('be.visible')
})
it('should display total price', () => {
// Assert
cy.getByTestId('modal-total-price').should('be.visible')
})
it('should show price breakdown', () => {
// Assert
cy.getByTestId('modal-price-breakdown-button').click()
cy.getByTestId('price-breakdown-details').should('be.visible')
})
it('should display taxes and fees', () => {
// Arrange
cy.getByTestId('modal-price-breakdown-button').click()
// Assert
cy.getByTestId('taxes-amount').should('be.visible')
cy.getByTestId('fees-amount').should('be.visible')
})
it('should show currency symbol', () => {
// Assert
cy.getByTestId('modal-total-price').should('contain', '₽')
})
})
describe('Modal Content - Amenities', () => {
beforeEach(() => {
cy.getByTestId('flight-item').first().click()
})
it('should display seat selection info', () => {
// Assert
cy.getByTestId('modal-seat-selection-info').should('be.visible')
})
it('should display baggage info', () => {
// Assert
cy.getByTestId('modal-baggage-info').should('be.visible')
})
it('should display meal info', () => {
// Assert
cy.getByTestId('modal-meal-info').should('be.visible')
})
it('should display extra services available', () => {
// Assert
cy.getByTestId('modal-extra-services').should('be.visible')
})
})
describe('Modal Tabs', () => {
beforeEach(() => {
cy.getByTestId('flight-item').first().click()
})
it('should display details tab', () => {
// Assert
cy.getByTestId('modal-tab-details').should('be.visible')
cy.getByTestId('modal-tab-details').should('have.class', 'active')
})
it('should display rules tab', () => {
// Assert
cy.getByTestId('modal-tab-rules').should('be.visible')
})
it('should display amenities tab', () => {
// Assert
cy.getByTestId('modal-tab-amenities').should('be.visible')
})
it('should switch to rules tab', () => {
// Act
cy.getByTestId('modal-tab-rules').click()
// Assert
cy.getByTestId('modal-tab-rules').should('have.class', 'active')
cy.getByTestId('modal-rules-content').should('be.visible')
})
it('should show refund policy', () => {
// Act
cy.getByTestId('modal-tab-rules').click()
// Assert
cy.getByTestId('refund-policy').should('be.visible')
})
it('should show change policy', () => {
// Act
cy.getByTestId('modal-tab-rules').click()
// Assert
cy.getByTestId('change-policy').should('be.visible')
})
})
describe('Modal Actions', () => {
beforeEach(() => {
cy.getByTestId('flight-item').first().click()
})
it('should display select flight button', () => {
// Assert
cy.getByTestId('modal-select-button').should('be.visible')
})
it('should select flight from modal', () => {
// Act
cy.getByTestId('modal-select-button').click()
// Assert
cy.getByTestId('flight-selected-message').should('be.visible')
})
it('should display add to favorites button', () => {
// Assert
cy.getByTestId('modal-favorite-button').should('be.visible')
})
it('should add flight to favorites', () => {
// Act
cy.getByTestId('modal-favorite-button').click()
// Assert
cy.getByTestId('modal-favorite-button').should('have.class', 'active')
})
it('should remove from favorites', () => {
// Arrange
cy.getByTestId('modal-favorite-button').click()
// Act
cy.getByTestId('modal-favorite-button').click()
// Assert
cy.getByTestId('modal-favorite-button').should('not.have.class', 'active')
})
it('should display share button', () => {
// Assert
cy.getByTestId('modal-share-button').should('be.visible')
})
it('should share flight details', () => {
// Act
cy.getByTestId('modal-share-button').click()
// Assert
cy.getByTestId('share-options-menu').should('be.visible')
})
})
describe('Modal Size & Responsiveness', () => {
it('should size modal for desktop', () => {
// Act
cy.getByTestId('flight-item').first().click()
// Assert
cy.getByTestId('flight-details-modal').should('have.css', 'max-width')
})
it('should position modal correctly on desktop', () => {
// Act
cy.getByTestId('flight-item').first().click()
// Assert
cy.getByTestId('flight-details-modal').should('be.visible')
cy.getByTestId('modal-backdrop').should('be.visible')
})
it('should scroll modal content', () => {
// Act
cy.getByTestId('flight-item').first().click()
cy.getByTestId('modal-content').scrollTo('bottom')
// Assert
cy.getByTestId('modal-select-button').should('be.visible')
})
})
describe('Modal State Transitions', () => {
it('should maintain modal state when clicking outside', () => {
// Arrange
cy.getByTestId('flight-item').first().click()
// Act
cy.get('body').click(0, 0)
// Assert
cy.getByTestId('flight-details-modal').should('not.be.visible')
})
it('should handle multiple modal opens', () => {
// Act
cy.getByTestId('flight-item').first().click()
cy.getByTestId('modal-close-button').click()
cy.getByTestId('flight-item').eq(1).click()
// Assert
cy.getByTestId('flight-details-modal').should('be.visible')
})
it('should preserve scroll position when opening modal', () => {
// Act
cy.getByTestId('flight-list-container').scrollTo('bottom')
cy.getByTestId('flight-item').first().scrollIntoView()
cy.getByTestId('flight-item').first().click()
// Assert
cy.getByTestId('flight-details-modal').should('be.visible')
})
})
describe('Modal Loading States', () => {
it('should show loading spinner while fetching details', () => {
// Arrange
cy.intercept('GET', '**/api/flights/**/details', {
statusCode: 200,
body: {},
delay: 1000,
}).as('detailsLoad')
// Act
cy.getByTestId('flight-item').first().click()
// Assert
cy.getByTestId('modal-loading-spinner').should('be.visible')
cy.wait('@detailsLoad')
})
it('should show error message if details fail to load', () => {
// Arrange
cy.intercept('GET', '**/api/flights/**/details', {
statusCode: 500,
body: { error: 'Failed to load details' },
}).as('detailsError')
// Act
cy.getByTestId('flight-item').first().click()
// Assert
cy.getByTestId('modal-error-message').should('be.visible')
})
})
describe('Modal Accessibility', () => {
it('should have modal with proper role', () => {
// Act
cy.getByTestId('flight-item').first().click()
// Assert
cy.getByTestId('flight-details-modal').should('have.attr', 'role', 'dialog')
})
it('should focus close button when modal opens', () => {
// Act
cy.getByTestId('flight-item').first().click()
// Assert
cy.getByTestId('modal-close-button').should('have.focus')
})
it('should trap focus inside modal', () => {
// Act
cy.getByTestId('flight-item').first().click()
cy.getByTestId('modal-select-button').focus()
cy.getByTestId('modal-select-button').type('{tab}')
// Assert
cy.getByTestId('modal-close-button').should('have.focus')
})
it('should announce modal title to screen readers', () => {
// Act
cy.getByTestId('flight-item').first().click()
// Assert
cy.getByTestId('flight-details-modal').should('have.attr', 'aria-labelledby')
})
it('should support keyboard shortcut to close', () => {
// Act
cy.getByTestId('flight-item').first().click()
cy.get('body').type('{esc}')
// Assert
cy.getByTestId('flight-details-modal').should('not.be.visible')
})
})
})