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 { await expect(this.travellerFieldsets.first()).toBeVisible(); } async totalAmount(): Promise { 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 { // 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 { for (let i = 0; i < travellers.length; i++) { await this.fillTraveller(i, travellers[i]); } } async removeTraveller(index: number): Promise { await this.travellerFieldsets.nth(index).getByRole('button', { name: 'Remove' }).click(); } /** Confirms and waits for the confirmation screen. */ async confirmBooking(): Promise { await this.confirm.click(); await this.page.waitForURL(/\/bookings\/[0-9a-f-]+/); } }