From 23e9777c186d705465ad41d965e8ebc59de3dca2 Mon Sep 17 00:00:00 2001 From: JennyNou <167806377+JennyNou@users.noreply.github.com> Date: Tue, 10 Mar 2026 13:21:50 -0400 Subject: [PATCH] Update locators and schedule page flow to fix tests --- playwright-tests/pages/SchedulePage.ts | 89 ++++++++++++++++++-------- 1 file changed, 63 insertions(+), 26 deletions(-) diff --git a/playwright-tests/pages/SchedulePage.ts b/playwright-tests/pages/SchedulePage.ts index 0bd340dc..11645b5d 100644 --- a/playwright-tests/pages/SchedulePage.ts +++ b/playwright-tests/pages/SchedulePage.ts @@ -3,56 +3,93 @@ import { BasePage } from './BasePage'; import { IAppointmentDetails } from '@business-logic/types/CustomerDetails'; import { formatDate, formatTime } from '@impl/utils/DateUtils'; import { ServiceLocation } from '@business-logic/types/Enums'; +import { getCustomerDetails, ITestData } from 'safelite-playwright-core'; export class SchedulePage extends BasePage { readonly page: Page; issPageValue = 'schedule-page'; - readonly firstAvailableDate: Locator; + + readonly inShopButton: Locator; + readonly mobileButton: Locator; + readonly moreLocationsButton: Locator; + readonly zipCodeTextBox: Locator; + readonly findButton: Locator; + readonly selectAShopOptions: Locator; + readonly firstAppointmentButton : Locator; + readonly firstAvailableAMDate: Locator; + readonly firstAvailablePMDate: Locator; readonly firstAvailableTime: Locator; + readonly firstAvailabeAMTime: Locator; readonly modalContinueButton: Locator; readonly dropOffButton: Locator; readonly dateText: Locator; readonly viewMoreDatesLink: Locator; + readonly continueButton: Locator; + constructor(page: Page) { super(page); this.page = page; - this.firstAvailableDate = this.page.locator('.selectable-day').locator('nth=0'); - this.firstAvailableTime = this.page.locator('label').filter({ hasText: /AM|PM/ }).locator('div').locator('nth=0'); + + this.inShopButton = this.page.locator('[buttonlabel="At a Safelite shop"]'); + this.mobileButton = this.page.locator('[buttonlabel="Have Safelite come to me"]'); + // For in shop + this.moreLocationsButton = this.page.getByRole('button', { name: 'More Locations' }); + // For mobile + this.zipCodeTextBox = this.page.locator('#serviceZipCode'); + this.findButton = this.page.getByRole('button', { name: 'Find' }); + // For in-shop and drop off + this.selectAShopOptions = this.page.locator('[class="shop-question"]'); + this.firstAppointmentButton = this.page.locator('#availabilityIndicator').first(); + this.firstAvailableAMDate = this.page.locator('morning-row-cell has-appointments selected-date').first(); + this.firstAvailablePMDate = this.page.locator('afternoon-row-cell has-appointments selected-date').first(); + this.firstAvailableTime = this.page.locator('.time-slot-button').first(); + this.firstAvailabeAMTime = this.page.locator('.time-slot-button').nth(0); this.modalContinueButton = this.page.locator('#modalbtn'); - this.dropOffButton = this.page.getByText('Drop off your vehicle', { exact: true }); + this.dropOffButton = this.page.locator('[class="dropoff-label"]'); this.dateText = this.page.locator('[class="modal-header mb-2 mt-2"]'); - this.viewMoreDatesLink = this.page.getByText(/View more dates/).first(); + this.viewMoreDatesLink = this.page.getByRole('button', { name: 'More Right arrow icon' }); + + this.continueButton = this.page.locator('#stacked').locator('button:has-text("Continue")'); } - async scheduleAppointment(appointmentDetails: IAppointmentDetails) { - const formattedDate = formatDate(appointmentDetails.appointmentDate!); - const formattedTime = formatTime(appointmentDetails.appointmentDate!); - const dateInput = this.page.locator(`div[id="${formattedDate}"]`); - const timeButton = this.page.locator(`div[aria-label="${formattedTime}"]`); - if (await dateInput.isVisible()) { - await dateInput.click(); + // Select in shop and schedule + async scheduleInShop(appointmentDetails?: IAppointmentDetails){ + + if (await this.inShopButton.isVisible() && appointmentDetails?.serviceLocation !== ServiceLocation.DropOff) { + await this.inShopButton.click(); + (await this.getTimeSlot(1)).click(); + } else if (appointmentDetails?.serviceLocation === ServiceLocation.DropOff) { + await this.inShopButton.isVisible(); + await this.inShopButton.click(); + await this.dropOffButton.isVisible() ? await this.dropOffButton.click() : null; } else { - await this.viewMoreDatesLink.click(); - await dateInput.click(); + await this.selectFirstAvailableTime(); } - await timeButton.click(); - await this.modalContinueButton.click(); + await this.continueButton.click(); } - async scheduleFirstAppointment(serviceLocation: ServiceLocation) { - if (await this.firstAvailableDate.isVisible()) { - await this.firstAvailableDate.click(); + // Select mobile button, enter zip code, click find button, select first available time and continue + async scheduleMobile(appointmentDetails: IAppointmentDetails){ + await this.mobileButton.click(); + await this.zipCodeTextBox.fill(appointmentDetails.serviceAddress!.postalCode!); + await this.findButton.click(); + await this.selectFirstAvailableTime(); + await this.continueButton.click(); + } + + // Selects the first available time slot but if its not visible, click "More" first to load more dates and times + async selectFirstAvailableTime(): Promise { + if (await this.firstAvailableTime.isVisible()) { + await this.firstAvailableTime.click(); } else { await this.viewMoreDatesLink.click(); - while(await this.firstAvailableDate.isHidden()){ - await this.viewMoreDatesLink.click(); - } - await this.firstAvailableDate.click(); + await this.firstAvailableTime.waitFor({ state: 'visible' }); + await this.firstAvailableTime.click(); } + } - serviceLocation === ServiceLocation.DropOff ? await this.dropOffButton.click() : await this.firstAvailableTime.click(); - await this.modalContinueButton.click(); - return (`${await this.dateText.allInnerTexts()}`); + async getTimeSlot(index: number): Promise { + return this.page.locator('.time-slot-button').nth(index); } } \ No newline at end of file