domain project / travel
Travel & Booking
Test strategies for flight/hotel search, availability engines, booking flows, pricing engines, and loyalty programmes.
demo: OpenFlights Demo
Flight & hotel searchReal-time availabilityBooking & paymentItinerary managementDynamic pricingLoyalty & rewards
Domain Overview
Travel & booking platforms are time-sensitive and price-volatile — availability and pricing can change between search and payment. Testing must cover real-time inventory, complex multi-leg itineraries, third-party GDS integrations, and regulated passenger data handling.
Typical stack: React / Angular frontend, fare aggregator APIs (Amadeus, Sabre), payment gateway, PNR record system, email/SMS notification service.
Key Test Areas
| Area | What to test | Risk |
|---|---|---|
| Search | Origin/destination combos, date ranges, no-results state, invalid airport codes | Zero results or wrong results shown |
| Availability | Seats/rooms in real time, seat-map rendering, sold-out handling | Oversell, customer frustration |
| Pricing | Base fare + taxes + fees = total displayed, currency formatting | Price mismatch, regulatory breach |
| Booking | Passenger details form, seat selection, ancillary add-ons, payment | Booking failure, wrong seat assigned |
| Itinerary | View, modify dates, cancel, refund calculation | Customer stranded, wrong refund |
| Loyalty | Points earn on booking, redemption at checkout, balance display | Points lost, programme distrust |
Test Pyramid for Travel & Booking
Unit (60%): Fare calculation, tax rules, points earn formula, date validation
Integration (30%): Search API, availability feed, GDS booking call, loyalty ledger
E2E (10%): Search → select → passenger details → seat → payment → confirmation
Critical E2E tests (must pass before every deploy):
- Round-trip flight search returns results and shows correct total price
- Complete booking flow with passenger details and card payment
- Cancel booking, verify refund amount matches policy
- Loyalty points credited after booking completion
- Date picker rejects past departure dates
Common Failure Scenarios
1. Price changes between search and checkout → customer sees different total
Test: mock search API, then change mock price before checkout, assert price-lock warning shown
2. Seat availability race condition → two users select same seat
Test: concurrent seat selection API calls, assert only one succeeds
3. Baggage fee not included in total shown → customer surprise at checkout
Test: add checked bag, verify total = base + taxes + baggage fee
4. Date picker allows past dates → booking fails server-side
Test: keyboard-navigate calendar to yesterday, assert date is disabled or error shown
5. Multi-city booking drops third leg → incomplete itinerary confirmed
Test: add three legs, submit, verify confirmation email lists all three segments
Playwright Patterns for Travel & Booking
// Mock flight search API and verify price display
test('search results display correct price from API', async ({ page }) => {
await page.route('**/api/flights/search', route => {
route.fulfill({
status: 200,
contentType: 'application/json',
body: JSON.stringify({
results: [{ id: 'FL123', total: 284.50, currency: 'USD', breakdown: { base: 240, taxes: 44.50 } }]
})
});
});
await page.goto('/flights');
await page.getByLabel('From').fill('LHR');
await page.getByLabel('To').fill('JFK');
await page.getByRole('button', { name: 'Search' }).click();
await expect(page.getByTestId('flight-total')).toHaveText('$284.50');
});
// Calendar date picker keyboard navigation
test('date picker supports keyboard navigation', async ({ page }) => {
await page.goto('/flights');
await page.getByLabel('Departure date').click();
// Navigate forward one month with ArrowRight, select with Enter
await page.keyboard.press('ArrowRight');
await page.keyboard.press('Enter');
await expect(page.getByLabel('Departure date')).not.toHaveValue('');
});