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.tscypress/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
-
Use data-testid attributes: Always add
data-testidto elements you want to test<button data-testid="search-button">Search</button> -
Avoid brittle selectors: Don't rely on class names or IDs that change frequently
-
Use meaningful test names: Describe what the test verifies
it('should filter search results when filter is applied', () => { // test code }) -
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') -
Keep tests independent: Each test should be able to run in any order
- Use
afterEachto clean up state (already configured) - Don't depend on data from other tests
- Use
-
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) -
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-testidattributes 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
afterEachhook 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.