docs: add comprehensive e2e test suite design specification
This commit is contained in:
@@ -0,0 +1,781 @@
|
||||
# E2E Test Suite Design: Aeroflot Flights Web (Angular → React)
|
||||
|
||||
**Date:** 2026-04-04
|
||||
**Status:** Design Approved
|
||||
**Scope:** 200-300 comprehensive e2e tests covering all UI elements and interactions
|
||||
|
||||
---
|
||||
|
||||
## 1. Overview
|
||||
|
||||
This document specifies a comprehensive end-to-end test suite for the Aeroflot Flights Web application, covering both the current Angular implementation (ClientApp/) and the new React implementation (react-app/). The tests verify feature parity between the two versions and ensure all UI elements, interactions, and edge cases function correctly.
|
||||
|
||||
**Approach:** Write all tests against Angular first, validate 100% pass rate, then adapt and run against React (with both mocked and real APIs).
|
||||
|
||||
**Total Test Count:** 200-300 tests
|
||||
**Execution Time:** 8-15 minutes per suite (mocked API), 10-20 minutes (real API)
|
||||
|
||||
---
|
||||
|
||||
## 2. Test Architecture & File Organization
|
||||
|
||||
### 2.1 Directory Structure
|
||||
|
||||
```
|
||||
ClientApp/cypress/
|
||||
├── integration/
|
||||
│ ├── features/
|
||||
│ │ ├── online-board.cy.ts (~60-70 tests)
|
||||
│ │ ├── schedule.cy.ts (~50-60 tests)
|
||||
│ │ ├── flights-map.cy.ts (~30-40 tests)
|
||||
│ │ ├── popular-requests.cy.ts (~20-30 tests)
|
||||
│ │ ├── i18n.cy.ts (~15-20 tests)
|
||||
│ │ └── error-states.cy.ts (~25-30 tests)
|
||||
│ └── responsive.cy.ts (~30-40 tests)
|
||||
├── support/
|
||||
│ ├── commands.ts (custom Cypress commands)
|
||||
│ ├── page-objects/
|
||||
│ │ ├── online-board.po.ts
|
||||
│ │ ├── schedule.po.ts
|
||||
│ │ ├── flights-map.po.ts
|
||||
│ │ ├── common.po.ts
|
||||
│ │ └── index.ts
|
||||
│ ├── fixtures.ts (mock data, test cities, flights)
|
||||
│ └── index.ts
|
||||
└── tsconfig.json
|
||||
|
||||
react-app/cypress/
|
||||
├── integration/
|
||||
│ ├── features/
|
||||
│ │ ├── online-board.cy.ts (adapted from Angular)
|
||||
│ │ ├── schedule.cy.ts
|
||||
│ │ ├── flights-map.cy.ts
|
||||
│ │ ├── popular-requests.cy.ts
|
||||
│ │ ├── i18n.cy.ts
|
||||
│ │ └── error-states.cy.ts
|
||||
│ └── responsive.cy.ts
|
||||
├── support/
|
||||
│ ├── commands.ts (same as Angular)
|
||||
│ ├── page-objects/ (may differ from Angular if DOM differs)
|
||||
│ └── fixtures.ts (same as Angular)
|
||||
└── tsconfig.json
|
||||
```
|
||||
|
||||
### 2.2 Test Organization
|
||||
|
||||
Each spec file is organized as:
|
||||
|
||||
```typescript
|
||||
// Example: online-board.cy.ts
|
||||
describe('Online Board Feature', () => {
|
||||
describe('Arrival Tab', () => {
|
||||
describe('City Input', () => {
|
||||
it('should accept manual city entry');
|
||||
it('should show validation error for empty input');
|
||||
it('should handle special characters gracefully');
|
||||
// ... more tests
|
||||
});
|
||||
|
||||
describe('Date Picker', () => {
|
||||
it('should accept valid future dates');
|
||||
it('should reject past dates');
|
||||
// ... more tests
|
||||
});
|
||||
|
||||
describe('Search & Results', () => {
|
||||
it('should display flight results after successful search');
|
||||
it('should show loading state during API call');
|
||||
// ... more tests
|
||||
});
|
||||
});
|
||||
|
||||
describe('Departure Tab', () => {
|
||||
// ... similar structure
|
||||
});
|
||||
|
||||
// ... more features
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. Test Scope by Feature
|
||||
|
||||
### 3.1 Online Board (~60-70 tests)
|
||||
|
||||
**Arrival Tab (~20 tests):**
|
||||
- City input: manual entry, dropdown selection, validation errors, empty input, special characters
|
||||
- Date picker: valid dates, future dates, past dates, invalid formats, today, edge dates
|
||||
- Search button: valid search, missing fields, network error, loading state, disabled state
|
||||
- Results display: flight list rendering, correct count, flight details modal, pagination
|
||||
|
||||
**Departure Tab (~20 tests):**
|
||||
- Same test coverage as Arrival (mirror feature)
|
||||
|
||||
**Flight Search/Filter (~15 tests):**
|
||||
- Flight number input: valid format (e.g., "SU 123"), invalid format, special characters, clear button
|
||||
- Autocomplete behavior: suggestions appear, filtering works, arrow key navigation, tab navigation
|
||||
- Form submission with partial filters
|
||||
|
||||
**Flight Details Panel (~10 tests):**
|
||||
- Modal opens on flight click, displays all correct flight info
|
||||
- Modal closes on X button, escape key, outside click
|
||||
- Links (airline, gate, terminal) navigate correctly
|
||||
- Back button returns to results with filters preserved
|
||||
|
||||
### 3.2 Schedule (~50-60 tests)
|
||||
|
||||
**Search Page (~25 tests):**
|
||||
- Origin autocomplete: manual entry, dropdown, validation
|
||||
- Destination autocomplete: same as origin
|
||||
- Date range picker: start date, end date, single day, full range, invalid ranges
|
||||
- Passenger count: input, increment/decrement, max/min bounds
|
||||
- Form submission: valid, incomplete, network error, empty results
|
||||
|
||||
**Flight Details Page (~20 tests):**
|
||||
- Flight info displays: departure, arrival, duration, airline, flight number
|
||||
- Timing details: gate, terminal, check-in time, boarding time
|
||||
- Seat map: renders, interactive, can select seat
|
||||
- Price info: base price, taxes, total, currency formatting
|
||||
- Navigation: previous flight, next flight, back to search
|
||||
|
||||
**Filters & Sorting (~10-15 tests):**
|
||||
- Time range filter: apply, clear, validate boundaries
|
||||
- Airline filter: select multiple, deselect all, apply
|
||||
- Price range filter: min/max sliders, apply
|
||||
- Sorting: by departure time, duration, price (ascending/descending)
|
||||
|
||||
### 3.3 Flights Map (~30-40 tests)
|
||||
|
||||
**Map Rendering (~15 tests):**
|
||||
- Map loads and is interactive
|
||||
- Flight destination markers display
|
||||
- Marker clustering at certain zoom levels
|
||||
- Pan and zoom work correctly
|
||||
- Geolocation button works (if enabled)
|
||||
|
||||
**Destination List (~15 tests):**
|
||||
- List items render with destination name, flight count
|
||||
- Click destination: highlights on map, center map on marker
|
||||
- Search/filter in list: filters by city name
|
||||
- Empty state when no destinations
|
||||
|
||||
**Map Interactions (~10 tests):**
|
||||
- Click marker: shows popup with flight info
|
||||
- Click destination in list: highlights on map, centers view
|
||||
- Hover effects on markers and list items
|
||||
- Popup contains: destination name, flight count, quick link to search
|
||||
|
||||
### 3.4 Popular Requests Widget (~20-30 tests)
|
||||
|
||||
- Widget renders on initial page load
|
||||
- Displays all popular request items (mock data)
|
||||
- Click item: navigates to search with correct parameters
|
||||
- API fallback to mock data works
|
||||
- Empty state handling (no popular requests)
|
||||
- Widget positioning and styling correct
|
||||
|
||||
### 3.5 Internationalization (i18n) (~15-20 tests)
|
||||
|
||||
- Language switcher visible and functional (all 9 languages: ru, en, es, fr, it, ja, ko, zh, de)
|
||||
- Switching language: page updates all text, no hard-coded strings visible
|
||||
- Language persistence: localStorage remembers selection
|
||||
- Date formats match locale (e.g., DD.MM.YYYY for ru, MM/DD/YYYY for en)
|
||||
- Number formatting matches locale (decimal separator, thousands separator)
|
||||
- Text truncation on narrow screens doesn't break layout
|
||||
- All UI elements have translations (no missing keys)
|
||||
|
||||
### 3.6 Error States (~25-30 tests)
|
||||
|
||||
- Network errors: 404 (not found), 500 (server error), 503 (service unavailable)
|
||||
- Timeout handling: API call exceeds timeout threshold
|
||||
- Empty results: no flights found for search
|
||||
- Validation errors: required fields missing, invalid input format
|
||||
- Loading states: loader visible, correct messaging
|
||||
- Recovery: retry button works, clears error after successful retry
|
||||
- SignalR connection failures: connection lost message, auto-reconnect attempt, manual reconnect button
|
||||
|
||||
### 3.7 Responsive/Mobile (~30-40 tests)
|
||||
|
||||
**Mobile Viewport (375x667 - iPhone SE):**
|
||||
- All text is readable (no overflow, proper line breaks)
|
||||
- Touch targets are at least 44x44px
|
||||
- Forms are usable (inputs accessible, not hidden behind keyboard)
|
||||
- Navigation: hamburger menu or drawer opens/closes
|
||||
- Accordion sections: collapse/expand works on tap
|
||||
- Carousel/swipes: work with touch events
|
||||
|
||||
**Tablet Viewport (768x1024 - iPad):**
|
||||
- Layout is optimized for tablet (not stretched, not too narrow)
|
||||
- Multi-column layouts work correctly
|
||||
- Touch interactions work
|
||||
|
||||
**Desktop Viewport (1920x1080 - Large screen):**
|
||||
- Layout scales correctly
|
||||
- No horizontal scrolling
|
||||
- All content is accessible without zooming
|
||||
|
||||
---
|
||||
|
||||
## 4. Test Categories & Patterns
|
||||
|
||||
### 4.1 Happy Path Tests (~30-40% of total: 60-120 tests)
|
||||
|
||||
User performs the intended action and succeeds. Example:
|
||||
|
||||
```typescript
|
||||
it('should search flights by arrival city and date', () => {
|
||||
cy.selectArrivalCity('Москва');
|
||||
cy.setArrivalDate('15.04.2026');
|
||||
cy.clickSearchButton();
|
||||
cy.getFlightResults().should('have.length.greaterThan', 0);
|
||||
cy.getFirstFlightResult().should('be.visible');
|
||||
});
|
||||
```
|
||||
|
||||
### 4.2 Edge Case Tests (~20-25% of total: 40-75 tests)
|
||||
|
||||
Boundary conditions, extreme inputs, special characters. Examples:
|
||||
|
||||
```typescript
|
||||
it('should handle special characters in flight number', () => {
|
||||
cy.typeFlightNumber('SU-123@#$%');
|
||||
cy.shouldShowValidationError('Invalid format');
|
||||
});
|
||||
|
||||
it('should allow searching 1 year in the future', () => {
|
||||
cy.setDepartureDate(moment().add(365, 'days').format('DD.MM.YYYY'));
|
||||
cy.clickSearch();
|
||||
cy.shouldLoadResults();
|
||||
});
|
||||
|
||||
it('should handle empty autocomplete results', () => {
|
||||
cy.typeArrivalCity('ZZZZZZ');
|
||||
cy.shouldShowEmptyState('No cities found');
|
||||
});
|
||||
```
|
||||
|
||||
### 4.3 Error Handling Tests (~15-20% of total: 30-60 tests)
|
||||
|
||||
Network failures, invalid responses, timeouts, server errors. Examples:
|
||||
|
||||
```typescript
|
||||
it('should show error message on 500 API failure', () => {
|
||||
cy.intercept('GET', '**/api/flights/**', { statusCode: 500 });
|
||||
cy.clickSearch();
|
||||
cy.getErrorMessage().should('contain', 'Server error');
|
||||
});
|
||||
|
||||
it('should handle network timeout gracefully', () => {
|
||||
cy.intercept('GET', '**/api/flights/**', { delay: 10000 });
|
||||
cy.clickSearch();
|
||||
cy.getLoader().should('be.visible');
|
||||
cy.getRetryButton().should('be.visible');
|
||||
});
|
||||
|
||||
it('should recover from SignalR connection loss', () => {
|
||||
cy.window().then(win => {
|
||||
win.signalRConnection.stop();
|
||||
});
|
||||
cy.getConnectionStatusBanner().should('be.visible');
|
||||
cy.getReconnectButton().click();
|
||||
cy.getConnectionStatusBanner().should('not.exist');
|
||||
});
|
||||
```
|
||||
|
||||
### 4.4 State Management Tests (~10-15% of total: 20-45 tests)
|
||||
|
||||
Form state persistence, navigation state, localStorage/sessionStorage. Examples:
|
||||
|
||||
```typescript
|
||||
it('should preserve search filters when navigating back', () => {
|
||||
cy.selectArrivalCity('Москва');
|
||||
cy.setDate('15.04.2026');
|
||||
cy.clickFlightResult(0);
|
||||
cy.goBack();
|
||||
cy.getArrivalCityInput().should('have.value', 'Москва');
|
||||
cy.getDateInput().should('have.value', '15.04.2026');
|
||||
});
|
||||
|
||||
it('should remember language selection after page reload', () => {
|
||||
cy.selectLanguage('en');
|
||||
cy.reload();
|
||||
cy.getCurrentLanguage().should('equal', 'en');
|
||||
});
|
||||
```
|
||||
|
||||
### 4.5 Accessibility & Interaction Tests (~10-15% of total: 20-45 tests)
|
||||
|
||||
Keyboard navigation, screen reader support, ARIA attributes, touch interactions. Examples:
|
||||
|
||||
```typescript
|
||||
it('should navigate autocomplete with arrow keys', () => {
|
||||
cy.typeInAutocomplete('Мос');
|
||||
cy.get('body').type('{downarrow}');
|
||||
cy.getFirstAutocompleteOption().should('have.focus');
|
||||
cy.get('body').type('{enter}');
|
||||
cy.shouldSelectOption('Москва');
|
||||
});
|
||||
|
||||
it('should be keyboard navigable without mouse', () => {
|
||||
cy.get('body').type('{tab}{tab}'); // Focus search button
|
||||
cy.focused().should('have.attr', 'data-testid', 'search-button');
|
||||
cy.get('body').type('{enter}');
|
||||
cy.shouldLoadResults();
|
||||
});
|
||||
|
||||
it('should be swipeable on mobile (right swipe)', () => {
|
||||
cy.viewport('iphone-x');
|
||||
cy.swipeRight();
|
||||
cy.getDateInput().should('have.value', moment().subtract(1, 'day').format('DD.MM.YYYY'));
|
||||
});
|
||||
```
|
||||
|
||||
### 4.6 Localization Tests (~5-10% of total: 10-30 tests)
|
||||
|
||||
Language switching, date formats, number formatting. Examples:
|
||||
|
||||
```typescript
|
||||
it('should display correct date format for Russian locale', () => {
|
||||
cy.selectLanguage('ru');
|
||||
cy.setDate('15.04.2026');
|
||||
cy.getDateDisplay().should('contain', '15 апреля 2026');
|
||||
});
|
||||
|
||||
it('should format currency for German locale', () => {
|
||||
cy.selectLanguage('de');
|
||||
cy.getFlightPrice().should('contain', '€');
|
||||
});
|
||||
|
||||
it('should format numbers with correct decimal separator', () => {
|
||||
cy.selectLanguage('de');
|
||||
cy.getPrice().should('contain', ','); // German decimal separator
|
||||
cy.selectLanguage('en');
|
||||
cy.getPrice().should('contain', '.'); // English decimal separator
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. Data, Fixtures & Mocking Strategy
|
||||
|
||||
### 5.1 Fixture Architecture
|
||||
|
||||
```typescript
|
||||
// cypress/support/fixtures.ts (shared between Angular & React)
|
||||
|
||||
export const CITIES = {
|
||||
arrival: [
|
||||
{ name: 'Москва', code: 'SVO', lat: 55.7558, lng: 37.62 },
|
||||
{ name: 'Санкт-Петербург', code: 'LED', lat: 59.8011, lng: 30.2625 },
|
||||
{ name: 'Анапа', code: 'AAQ', lat: 44.8972, lng: 37.3369 },
|
||||
{ name: 'Екатеринбург', code: 'SVX', lat: 56.7431, lng: 60.8022 },
|
||||
// ... 9+ cities total
|
||||
],
|
||||
departure: [
|
||||
{ name: 'Москва', code: 'VKO', lat: 55.5917, lng: 37.2750 },
|
||||
// ...
|
||||
]
|
||||
};
|
||||
|
||||
export const MOCK_FLIGHTS = {
|
||||
arrival: [
|
||||
{
|
||||
id: 'SU123',
|
||||
airline: 'Aeroflot',
|
||||
number: 'SU 123',
|
||||
departure: '10:15',
|
||||
arrival: '11:45',
|
||||
duration: '1h 30m',
|
||||
status: 'landed',
|
||||
gate: 'A5',
|
||||
terminal: '1'
|
||||
},
|
||||
// ... 10+ flights for variety
|
||||
],
|
||||
departure: [ /* ... */ ]
|
||||
};
|
||||
|
||||
export const TEST_USERS = {
|
||||
default: { email: 'test@example.com' },
|
||||
};
|
||||
```
|
||||
|
||||
### 5.2 Intercept Strategy (Approach C: Real + Mocked)
|
||||
|
||||
**Test Suite 1: Mocked API** (deterministic, fast, runs in CI)
|
||||
|
||||
```typescript
|
||||
beforeEach(() => {
|
||||
cy.intercept('GET', '**/api/flights/v1.1/**', {
|
||||
statusCode: 200,
|
||||
body: MOCK_FLIGHTS.arrival
|
||||
}).as('getFlights');
|
||||
|
||||
cy.intercept('GET', '**/api/cities/**', {
|
||||
statusCode: 200,
|
||||
body: CITIES.arrival
|
||||
}).as('getCities');
|
||||
|
||||
cy.visit('http://localhost:4200'); // Angular
|
||||
// OR cy.visit('http://localhost:3000'); // React
|
||||
});
|
||||
```
|
||||
|
||||
**Test Suite 2: Real API** (integration test, validates actual backend)
|
||||
|
||||
```typescript
|
||||
beforeEach(() => {
|
||||
// No intercepts — hits real backend
|
||||
cy.visit('https://test.aeroflot.ru');
|
||||
});
|
||||
```
|
||||
|
||||
### 5.3 State Reset (Approach A: Full Reset per Test)
|
||||
|
||||
```typescript
|
||||
beforeEach(() => {
|
||||
// Clear all browser state
|
||||
cy.clearAllLocalStorage();
|
||||
cy.clearAllSessionStorage();
|
||||
cy.clearCookies();
|
||||
|
||||
// Close any open WebSocket connections (SignalR)
|
||||
cy.window().then(win => {
|
||||
if (win.signalRConnection) {
|
||||
win.signalRConnection.stop().catch(() => {});
|
||||
}
|
||||
});
|
||||
|
||||
// Reset to baseline URL
|
||||
cy.visit('/');
|
||||
cy.wait(500); // Allow page to fully load
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
// Optional: take screenshot on failure
|
||||
// (Cypress does this automatically by default)
|
||||
});
|
||||
```
|
||||
|
||||
### 5.4 Common Cypress Commands
|
||||
|
||||
```typescript
|
||||
// cypress/support/commands.ts
|
||||
|
||||
Cypress.Commands.add('selectArrivalCity', (cityName: string) => {
|
||||
cy.get('[data-testid="arrival-city-input"]').type(cityName);
|
||||
cy.get(`[data-testid="city-option-${cityName}"]`).click();
|
||||
});
|
||||
|
||||
Cypress.Commands.add('setArrivalDate', (date: string) => {
|
||||
cy.get('[data-testid="arrival-date-input"]').clear().type(date);
|
||||
});
|
||||
|
||||
Cypress.Commands.add('clickSearchButton', () => {
|
||||
cy.get('[data-testid="search-button"]').click();
|
||||
cy.get('[data-testid="loader"]').should('be.visible');
|
||||
cy.get('[data-testid="loader"]').should('not.exist');
|
||||
});
|
||||
|
||||
Cypress.Commands.add('getFlightResults', () => {
|
||||
return cy.get('[data-testid="flight-result"]');
|
||||
});
|
||||
|
||||
Cypress.Commands.add('shouldShowValidationError', (message: string) => {
|
||||
cy.get('[data-testid="error-message"]').should('contain', message);
|
||||
});
|
||||
|
||||
Cypress.Commands.add('swipeRight', () => {
|
||||
cy.get('body').trigger('touchstart', { touches: [{ clientX: 0, clientY: 100 }] });
|
||||
cy.get('body').trigger('touchmove', { touches: [{ clientX: 100, clientY: 100 }] });
|
||||
cy.get('body').trigger('touchend');
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. Execution Strategy & Tooling
|
||||
|
||||
### 6.1 Cypress Configuration
|
||||
|
||||
```typescript
|
||||
// cypress.config.ts (both Angular & React)
|
||||
import { defineConfig } from 'cypress';
|
||||
|
||||
export default defineConfig({
|
||||
e2e: {
|
||||
baseUrl: process.env.BASE_URL || 'http://localhost:4200',
|
||||
viewportWidth: 1280,
|
||||
viewportHeight: 720,
|
||||
defaultCommandTimeout: 5000,
|
||||
requestTimeout: 10000,
|
||||
responseTimeout: 10000,
|
||||
pageLoadTimeout: 30000,
|
||||
chromeWebSecurity: false, // for Module Federation
|
||||
video: true,
|
||||
videoUploadOnPasses: false,
|
||||
screenshotOnRunFailure: true,
|
||||
|
||||
specPattern: 'cypress/integration/**/*.cy.ts',
|
||||
supportFile: 'cypress/support/index.ts',
|
||||
|
||||
setupNodeEvents(on, config) {
|
||||
// Example: video recording configuration
|
||||
return config;
|
||||
},
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
### 6.2 NPM Scripts
|
||||
|
||||
Add to both `ClientApp/package.json` and `react-app/package.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"cypress:open": "cypress open",
|
||||
"cypress:run": "cypress run",
|
||||
"cypress:run:all": "cypress run --spec 'cypress/integration/**/*.cy.ts'",
|
||||
"cypress:run:feature": "cypress run --spec 'cypress/integration/features/*.cy.ts'",
|
||||
"cypress:run:responsive": "cypress run --spec 'cypress/integration/responsive.cy.ts'",
|
||||
"cypress:report": "npm run cypress:run && npx mochawesome-report-generator",
|
||||
"test:e2e": "npm run cypress:run -- --env API_MODE=mocked",
|
||||
"test:e2e:real": "npm run cypress:run -- --env API_MODE=real BASE_URL=https://test.aeroflot.ru"
|
||||
}
|
||||
```
|
||||
|
||||
### 6.3 Execution Flow
|
||||
|
||||
**Phase 1: Write Angular Tests** (2-3 hours)
|
||||
- Create all spec files with describe/it structure
|
||||
- Implement helper functions in `cypress/support/commands.ts`
|
||||
- Implement Page Object Models in `cypress/support/page-objects/`
|
||||
- Run incrementally: `npm run cypress:open`
|
||||
- Validate all tests pass: `npm run cypress:run:all`
|
||||
|
||||
**Phase 2: Validate Full Angular Suite** (30 mins)
|
||||
- Full headless run with video/screenshots: `npm run cypress:run:all`
|
||||
- Generate HTML report: `npm run cypress:report`
|
||||
- Fix any flaky tests
|
||||
|
||||
**Phase 3: Adapt to React** (2-3 hours)
|
||||
- Copy spec files to `react-app/cypress/integration/`
|
||||
- Update selectors in page-objects if React DOM differs
|
||||
- Update `cypress.config.ts` baseUrl to `:3000`
|
||||
- Run against React with mocked API: `cd react-app && npm run test:e2e`
|
||||
- Fix failures (likely selector or navigation changes)
|
||||
|
||||
**Phase 4: Run React Suite with Real API** (1-2 hours)
|
||||
- Run full suite against staging: `npm run test:e2e:real`
|
||||
- Validate all tests pass
|
||||
- Fix any integration issues (timing, data, network)
|
||||
|
||||
### 6.4 CI/CD Integration
|
||||
|
||||
```yaml
|
||||
# .github/workflows/e2e-tests.yml
|
||||
name: E2E Tests
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
test-angular:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 30
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: '18'
|
||||
- run: cd ClientApp && npm ci
|
||||
- run: npm start > /dev/null 2>&1 &
|
||||
- run: npx wait-on http://localhost:4200 --timeout 30000
|
||||
- run: npm run cypress:run:all
|
||||
- uses: actions/upload-artifact@v3
|
||||
if: always()
|
||||
with:
|
||||
name: cypress-videos-angular
|
||||
path: ClientApp/cypress/videos
|
||||
|
||||
test-react:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 30
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: '18'
|
||||
- run: cd react-app && npm ci
|
||||
- run: npm start > /dev/null 2>&1 &
|
||||
- run: npx wait-on http://localhost:3000 --timeout 30000
|
||||
- run: npm run test:e2e
|
||||
- uses: actions/upload-artifact@v3
|
||||
if: always()
|
||||
with:
|
||||
name: cypress-videos-react
|
||||
path: react-app/cypress/videos
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. Success Criteria & Validation
|
||||
|
||||
### 7.1 Definition of Done
|
||||
|
||||
**Angular Tests:**
|
||||
- ✅ All 200-300 tests written and organized by feature
|
||||
- ✅ All tests pass against Angular app (100% pass rate)
|
||||
- ✅ No test takes >10 seconds (performance gate)
|
||||
- ✅ All test categories represented: happy path, edge case, error handling, state, accessibility, i18n, responsive
|
||||
- ✅ Code coverage: 80%+ for tested components
|
||||
|
||||
**React Tests:**
|
||||
- ✅ All Angular tests adapted to React (selector/navigation updates only)
|
||||
- ✅ All tests pass against React app with mocked API (100% pass rate)
|
||||
- ✅ All tests pass against React app with real API (staging backend)
|
||||
- ✅ No test takes >10 seconds
|
||||
- ✅ Feature parity verified: React UI behaves identically to Angular
|
||||
|
||||
### 7.2 Metrics to Track
|
||||
|
||||
| Metric | Target |
|
||||
|--------|--------|
|
||||
| Total Tests (Angular) | 200-300 |
|
||||
| Total Tests (React) | 200-300 (same) |
|
||||
| Pass Rate (Angular) | 100% |
|
||||
| Pass Rate (React, mocked) | 100% |
|
||||
| Pass Rate (React, real API) | 100% |
|
||||
| Avg Test Duration | 2-3 seconds |
|
||||
| Total Suite Time (mocked) | 8-15 minutes |
|
||||
| Total Suite Time (real API) | 10-20 minutes |
|
||||
| Code Coverage (tested components) | 80%+ |
|
||||
| Flaky Test Count | 0 |
|
||||
|
||||
### 7.3 Stopping Condition
|
||||
|
||||
Work continues until:
|
||||
- ✅ All 200-300 tests pass on Angular
|
||||
- ✅ All 200-300 tests pass on React (mocked API)
|
||||
- ✅ All 200-300 tests pass on React (real API)
|
||||
- ✅ No test takes >10 seconds
|
||||
- ✅ Re-running test suite 3x produces consistent results (no flaky tests)
|
||||
- ✅ Angular and React behavior is identical for all covered features
|
||||
|
||||
---
|
||||
|
||||
## 8. Implementation Notes
|
||||
|
||||
### 8.1 DOM Structure Assumptions
|
||||
|
||||
Tests assume the following data-testid attributes exist on UI elements (both Angular and React must implement these):
|
||||
|
||||
```
|
||||
Online Board:
|
||||
- data-testid="arrival-city-input"
|
||||
- data-testid="arrival-date-input"
|
||||
- data-testid="search-button"
|
||||
- data-testid="flight-result"
|
||||
- data-testid="loader"
|
||||
- data-testid="error-message"
|
||||
- data-testid="flight-details-modal"
|
||||
|
||||
Schedule:
|
||||
- data-testid="origin-input"
|
||||
- data-testid="destination-input"
|
||||
- data-testid="date-range-picker"
|
||||
- data-testid="passenger-count"
|
||||
- data-testid="search-button"
|
||||
|
||||
And so on...
|
||||
```
|
||||
|
||||
If either implementation uses different selectors, Page Object Models will be updated to translate.
|
||||
|
||||
### 8.2 Test Data Lifecycle
|
||||
|
||||
- **Setup:** Full state reset before each test (localStorage, cookies, connections)
|
||||
- **Execution:** Test runs against isolated mocked data
|
||||
- **Teardown:** Browser state cleared automatically
|
||||
|
||||
No test data persists between tests.
|
||||
|
||||
### 8.3 Handling Flaky Tests
|
||||
|
||||
If a test is flaky:
|
||||
1. Add explicit waits for async operations
|
||||
2. Retry the specific assertion (Cypress built-in)
|
||||
3. Check for race conditions in test logic
|
||||
4. If unsolvable, mark as skipped with comment explaining issue
|
||||
|
||||
### 8.4 Performance Constraints
|
||||
|
||||
- Each test: <10 seconds (includes setup, execution, teardown)
|
||||
- Full suite: <30 minutes (8-15 min for mocked, 10-20 min for real API)
|
||||
- If a test exceeds 10 seconds, it's split or optimized
|
||||
|
||||
---
|
||||
|
||||
## 9. Risks & Mitigation
|
||||
|
||||
| Risk | Probability | Impact | Mitigation |
|
||||
|------|-------------|--------|-----------|
|
||||
| React selectors differ from Angular | High | Medium | Page Object Model abstraction; update POM for React |
|
||||
| Flaky network-dependent tests | Medium | High | Use mocked API for primary suite; real API as secondary |
|
||||
| Test explosion (200-300 is large) | Medium | High | Phased execution; monitor suite time; parallelize if needed |
|
||||
| Timing issues (async operations) | Medium | Medium | Explicit waits, retry logic, proper Cypress commands |
|
||||
| Mobile tests on CI | Medium | Low | Use Cypress viewport, skip on CI if needed, test locally |
|
||||
|
||||
---
|
||||
|
||||
## 10. Timeline & Ownership
|
||||
|
||||
| Phase | Estimate | Owner |
|
||||
|-------|----------|-------|
|
||||
| 1. Write Angular Tests | 2-3 hours | Claude Code |
|
||||
| 2. Validate Angular | 30 mins | Claude Code |
|
||||
| 3. Adapt to React | 2-3 hours | Claude Code |
|
||||
| 4. Validate React (mocked) | 1 hour | Claude Code |
|
||||
| 5. Validate React (real API) | 1-2 hours | Claude Code |
|
||||
| **Total** | **7-10 hours** | |
|
||||
|
||||
Work continues until **all tests pass** on both versions.
|
||||
|
||||
---
|
||||
|
||||
## Appendix: Reference
|
||||
|
||||
### A.1 Cypress Best Practices Used
|
||||
|
||||
- ✅ Page Object Model for selector abstraction
|
||||
- ✅ Custom commands for common actions
|
||||
- ✅ Explicit waits over implicit
|
||||
- ✅ Data attributes (data-testid) for element selection
|
||||
- ✅ Full state reset between tests
|
||||
- ✅ Feature-based organization
|
||||
- ✅ Mocking + real API testing
|
||||
|
||||
### A.2 Languages Supported (i18n)
|
||||
|
||||
1. Russian (ru)
|
||||
2. English (en)
|
||||
3. Spanish (es)
|
||||
4. French (fr)
|
||||
5. Italian (it)
|
||||
6. Japanese (ja)
|
||||
7. Korean (ko)
|
||||
8. Chinese (zh)
|
||||
9. German (de)
|
||||
|
||||
All 9 languages must have passing tests.
|
||||
|
||||
### A.3 Key Features Tested
|
||||
|
||||
1. Online Board (departure/arrival tabs, search, filters, flight details)
|
||||
2. Schedule (search page, flight details, filters, sorting)
|
||||
3. Flights Map (map rendering, markers, destination list, interactions)
|
||||
4. Popular Requests (widget load, navigation, fallback)
|
||||
5. Internationalization (language switching, formatting, persistence)
|
||||
6. Error States (network failures, validation, loading states, recovery)
|
||||
7. Responsive Design (mobile, tablet, desktop viewports)
|
||||
|
||||
Reference in New Issue
Block a user