Files
TS_Proto/e2e/pages/checkout.page.ts
T
nilesh.pandClaude Opus 4.8 4d3eb18a6c Initial commit: TravelHub multi-tenant flight booking platform
Angular + Go + PostgreSQL sample with strict per-tenant isolation.

- Backend: Go API (basic auth, tenant-scoped repository layer, pgx pool)
- Frontend: Angular 22 SPA (search, checkout, bookings, dashboard)
- Database: schema, seed data and demo bookings migrations
- Tests: 311 across Go (integration), Angular (unit) and Playwright (e2e),
  plus a generated evidence report with PDF export
- Security: whitebox VAPT report under security/

Secrets (.env, tokens, DB credentials) are git-ignored.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-13 11:38:01 +05:30

77 lines
2.7 KiB
TypeScript

import { expect, Locator, Page } from '@playwright/test';
export interface Traveller {
firstName: string;
lastName: string;
dateOfBirth?: string;
passportNumber?: string;
}
/** The booking form. */
export class CheckoutPage {
readonly travellerFieldsets: Locator;
readonly addTraveller: Locator;
readonly contactEmail: Locator;
readonly contactPhone: Locator;
readonly confirm: Locator;
readonly total: Locator;
readonly error: Locator;
readonly seatsLeft: Locator;
constructor(private readonly page: Page) {
this.travellerFieldsets = page.locator('.pax');
this.addTraveller = page.getByRole('button', { name: '+ Add traveller' });
this.contactEmail = page.locator('#contactEmail');
this.contactPhone = page.locator('#contactPhone');
this.confirm = page.getByRole('button', { name: /Confirm booking|Confirming/ });
this.total = page.locator('.fare-row.total strong');
this.error = page.locator('.alert-error');
this.seatsLeft = page.locator('.sum-list div', { hasText: 'Seats left' }).locator('dd');
}
async waitUntilReady(): Promise<void> {
await expect(this.travellerFieldsets.first()).toBeVisible();
}
async totalAmount(): Promise<number> {
const text = await this.total.innerText();
return Number(text.replace(/[^0-9.]/g, ''));
}
/** Fills one traveller block, adding a row first if necessary. */
async fillTraveller(index: number, traveller: Traveller): Promise<void> {
// Wait for each added row to render before deciding whether another is
// needed -- re-counting immediately races Angular and adds one too many.
let count = await this.travellerFieldsets.count();
while (count <= index) {
await this.addTraveller.click();
count += 1;
await expect(this.travellerFieldsets).toHaveCount(count);
}
await this.page.locator(`#first-${index}`).fill(traveller.firstName);
await this.page.locator(`#last-${index}`).fill(traveller.lastName);
if (traveller.dateOfBirth) {
await this.page.locator(`#dob-${index}`).fill(traveller.dateOfBirth);
}
if (traveller.passportNumber) {
await this.page.locator(`#passport-${index}`).fill(traveller.passportNumber);
}
}
async fillTravellers(travellers: Traveller[]): Promise<void> {
for (let i = 0; i < travellers.length; i++) {
await this.fillTraveller(i, travellers[i]);
}
}
async removeTraveller(index: number): Promise<void> {
await this.travellerFieldsets.nth(index).getByRole('button', { name: 'Remove' }).click();
}
/** Confirms and waits for the confirmation screen. */
async confirmBooking(): Promise<void> {
await this.confirm.click();
await this.page.waitForURL(/\/bookings\/[0-9a-f-]+/);
}
}