# 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 ```bash 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) ```bash 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 ```bash npm run cypress:run ``` This runs all tests in headless mode and generates a test report. ### Run Specific Test Suite ```bash npx cypress run --spec "cypress/integration/search-history/*.spec.ts" ``` ### Run Tests with Specific Browser ```bash 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. ```typescript 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. ```typescript 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. ```typescript // 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 ```bash npm run backstop:reference ``` This creates baseline screenshots using the Angular version (`backstop/backstop-angular.json`). ### Run Visual Tests ```bash 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 ```html ``` 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 ```typescript it('should filter search results when filter is applied', () => { // test code }) ``` 4. **Test user workflows**: Write tests that simulate real user interactions ```typescript 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 ```typescript 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 ```typescript cy.intercept('GET', '/api/flights/*', { fixture: 'flights.json' }) ``` ## Validation Script Run the full validation suite (includes e2e tests): ```bash 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: ```bash npm run cypress:run # Headless test execution ``` Ensure the React development server is running on port 3000 before executing tests. ## Additional Resources - [Cypress Documentation](https://docs.cypress.io) - [BackstopJS Documentation](https://garris.github.io/BackstopJS/) - [Testing Best Practices](https://docs.cypress.io/guides/references/best-practices)