Files
..

E2E Testing Infrastructure

This directory contains end-to-end testing infrastructure for the Aeroflot Flights web application, including Cypress tests and visual regression testing with BackstopJS.

Directory Structure

e2e/
├── cypress/
│   ├── integration/          # E2E test files organized by feature
│   │   ├── accessibility/    # Accessibility tests
│   │   ├── components/       # Component-level tests
│   │   ├── error-handling/   # Error handling tests
│   │   ├── flight-details/   # Flight details page tests
│   │   ├── flights-map/      # Flight map tests
│   │   ├── i18n/            # Internationalization tests
│   │   ├── integration/      # Cross-feature integration tests
│   │   ├── navigation/       # Navigation flow tests
│   │   ├── online-board/     # Online board tests
│   │   ├── performance/      # Performance tests
│   │   ├── responsive/       # Responsive design tests
│   │   ├── schedule/         # Schedule tests
│   │   └── search-history/   # Search history tests
│   └── support/
│       ├── index.ts          # Global test setup and hooks
│       └── commands.ts       # Custom Cypress commands
├── backstop/                 # Visual regression testing config
├── cypress.config.ts         # Cypress configuration
├── package.json              # E2E dependencies
├── tsconfig.json             # TypeScript configuration
└── scripts/                  # Test utility scripts

Test File Naming

All test files must follow the naming pattern: *.spec.ts

Example test files:

  • cypress/integration/search-history/search-history-filtering.spec.ts
  • cypress/integration/flight-details/flight-details-display.spec.ts

Setup

Install Dependencies

npm install

Environment Configuration

The test suite uses the following configuration from cypress.config.ts:

  • Base URL: http://localhost:3000 (React development server)
  • Viewport: 1440x900 (desktop)
  • Timeouts: 10 seconds for requests, responses, and commands
  • Screenshots: Enabled on test failure
  • Videos: Disabled (can be enabled in cypress.config.ts if needed)

Running Tests

Open Cypress Test Runner (Interactive Mode)

npm run cypress:open

This opens the Cypress test runner UI where you can:

  • View and run individual tests
  • Debug with browser DevTools
  • See real-time test execution
  • Inspect elements and network calls

Run Tests Headlessly

npm run cypress:run

This runs all tests in headless mode and generates a test report.

Run Specific Test Suite

npx cypress run --spec "cypress/integration/search-history/*.spec.ts"

Run Tests with Specific Browser

npx cypress run --browser chrome
npx cypress run --browser firefox
npx cypress run --browser edge

Custom Commands

getByTestId(id: string, timeout?: number)

Select elements by test ID attribute for more reliable element selection.

cy.getByTestId('search-button').click()
cy.getByTestId('flight-results', 5000).should('exist')

forbidGeolocation()

Mock the geolocation API to return an error, useful for testing geolocation-denied scenarios.

cy.forbidGeolocation()
// Now geolocation calls will fail

Test Hooks

afterEach Hook

Automatically clears browser localStorage after each test to ensure test isolation and prevent state leakage between tests.

// Automatically runs after every test
afterEach(() => {
  cy.window().then(win => {
    win.localStorage.clear()
  })
})

Visual Regression Testing (BackstopJS)

The e2e folder includes BackstopJS for visual regression testing.

Create Reference Screenshots

npm run backstop:reference

This creates baseline screenshots using the Angular version (backstop/backstop-angular.json).

Run Visual Tests

npm run backstop:test

This compares current React version screenshots against the Angular baseline (backstop/backstop-react.json).

Test Best Practices

  1. Use data-testid attributes: Always add data-testid to elements you want to test

    <button data-testid="search-button">Search</button>
    
  2. Avoid brittle selectors: Don't rely on class names or IDs that change frequently

  3. Use meaningful test names: Describe what the test verifies

    it('should filter search results when filter is applied', () => {
      // test code
    })
    
  4. Test user workflows: Write tests that simulate real user interactions

    cy.getByTestId('destination-input').type('Moscow')
    cy.getByTestId('search-button').click()
    cy.getByTestId('flight-results').should('be.visible')
    
  5. Keep tests independent: Each test should be able to run in any order

    • Use afterEach to clean up state (already configured)
    • Don't depend on data from other tests
  6. Handle async operations: Use proper timeouts and waits

    cy.getByTestId('loading-spinner', 10000).should('not.exist')
    cy.getByTestId('results-list').should('have.length.greaterThan', 0)
    
  7. Mock API responses when appropriate: Use Cypress intercept for predictable tests

    cy.intercept('GET', '/api/flights/*', { fixture: 'flights.json' })
    

Validation Script

Run the full validation suite (includes e2e tests):

npm run validate

Troubleshooting

Tests timing out

  • Increase timeout values in cypress.config.ts
  • Check if the application is running on http://localhost:3000
  • Verify network connectivity to backend API

Element not found errors

  • Ensure data-testid attributes exist in the React components
  • Wait for elements to be visible: cy.getByTestId('element').should('be.visible')
  • Check browser console for JavaScript errors

localStorage not clearing between tests

  • The afterEach hook should handle this automatically
  • Verify the hook is not being overridden in individual test files

CI/CD Integration

For CI/CD pipelines, use:

npm run cypress:run  # Headless test execution

Ensure the React development server is running on port 3000 before executing tests.

Additional Resources