Corrects an issue where the service location wasn't being selected properly in certain scenarios. Specifically, it ensures the 'Enter Service Address' button is clicked only when the address text box is not visible. It also removes the unnecessary 'saveAddressButton' click.
171 lines
No EOL
7.7 KiB
TypeScript
171 lines
No EOL
7.7 KiB
TypeScript
import { expect, type Locator, type Page } from '@playwright/test';
|
|
import { BasePage } from './BasePage';
|
|
import { IAppointmentDetails } from '@business-logic/types/CustomerDetails';
|
|
import { AppointmentTimeslot, AppointmentType } from '@business-logic/types/Enums';
|
|
import { AddressForm } from './forms/AddressForm';
|
|
import { faker } from '@faker-js/faker';
|
|
import { step } from '@business-logic/types/Step';
|
|
import { ITestData } from '@business-logic/types/ITestData';
|
|
|
|
export class ServiceLocationPage extends BasePage {
|
|
readonly page: Page;
|
|
|
|
readonly addressForm: AddressForm;
|
|
|
|
// Initial selection
|
|
readonly inShopButton: Locator;
|
|
readonly mobileButton: Locator;
|
|
readonly dropOffButton: Locator;
|
|
readonly RecalWarningMessage1: Locator;
|
|
readonly RecalWarningMessage2: Locator;
|
|
readonly militaryWarningMessage: Locator;
|
|
|
|
// For in-shop and drop off
|
|
readonly selectAShopOptions: Locator;
|
|
readonly firstAppointmentButton: Locator;
|
|
readonly changeZipButton: Locator;
|
|
readonly updateZipTextBox: Locator;
|
|
readonly saveZipButton: Locator;
|
|
|
|
// For mobile
|
|
readonly enterServiceAddressButton: Locator;
|
|
readonly serviceAddressTextBox: Locator;
|
|
readonly aptNumberTextBox: Locator;
|
|
readonly cityTextBox: Locator;
|
|
readonly stateDropDown: Locator;
|
|
readonly zipCodeTextBox: Locator;
|
|
readonly vehicleProtectedYesButton: Locator;
|
|
readonly vehicleProtectedNoButton: Locator;
|
|
readonly repeatedClicksModalCloseButton: Locator;
|
|
|
|
url = process.env['BASE_URL']! + '/fmg/?fmgPage=service-location';
|
|
|
|
constructor(page: Page) {
|
|
super(page);
|
|
this.page = page;
|
|
|
|
this.addressForm = new AddressForm(page);
|
|
|
|
// Initial selection
|
|
this.inShopButton = this.page.getByText(/In-shop/);
|
|
this.mobileButton = this.page.getByText(/Mobile/).nth(0);
|
|
this.dropOffButton = this.page.getByText(/Drop-off/);
|
|
this.RecalWarningMessage1 = this.page.getByText(/We're not able to provide mobile service/);
|
|
this.RecalWarningMessage2 = this.page.getByText(/advanced safety system recalibration needs to be done in our shop./);
|
|
this.militaryWarningMessage = this.page.locator('[class*="widget-name-AlertMilitaryBaseZipWidget"]');
|
|
|
|
// For in-shop and drop off
|
|
this.selectAShopOptions = this.page.locator('[class="shop-question"]');
|
|
this.firstAppointmentButton = this.page.locator('fieldset:has(legend#chooseShop)').locator('label').first();
|
|
this.changeZipButton = this.page.locator('a:has(span.sr-only:has-text("edit zip code"))');
|
|
this.updateZipTextBox = this.page.locator('#serviceZipCode');
|
|
this.saveZipButton = this.page.getByText('Save ZIP code', { exact: true });
|
|
|
|
|
|
// For mobile
|
|
this.enterServiceAddressButton = this.page.getByRole('link', { name: 'Enter your service address' });
|
|
this.serviceAddressTextBox = this.page.getByRole('textbox', { name: 'Street Address' });
|
|
this.aptNumberTextBox = this.page.getByRole('textbox', { name: 'Apt. number'});
|
|
this.cityTextBox = this.page.getByRole('textbox', { name: 'City' });
|
|
this.stateDropDown = this.page.getByRole('combobox', { name: 'State' });
|
|
this.zipCodeTextBox = this.page.getByRole('textbox', { name: 'Zip code' });
|
|
this.vehicleProtectedYesButton = this.page.locator('label').filter({ hasText: 'Yes' }).locator('div');
|
|
this.vehicleProtectedNoButton = this.page.locator('label').filter({ hasText: 'No' }).locator('div');
|
|
this.repeatedClicksModalCloseButton = this.page.locator('.QSISlider').locator('img[src*=\'close\']');
|
|
}
|
|
|
|
async selectLocation(testData: Partial<ITestData>) {
|
|
const { appointmentDetails, customerDetails } = testData;
|
|
|
|
switch(appointmentDetails?.serviceLocation) {
|
|
case AppointmentType.Mobile:
|
|
await this.scheduleMobile(testData);
|
|
break;
|
|
case AppointmentType.InShop:
|
|
await this.scheduleInShop(appointmentDetails);
|
|
break;
|
|
case AppointmentType.DropOff:
|
|
await this.scheduleDropOff(appointmentDetails);
|
|
break;
|
|
}
|
|
}
|
|
|
|
async scheduleInShop(appointmentDetails?: IAppointmentDetails) {
|
|
await this.inShopButton.click();
|
|
if (appointmentDetails && appointmentDetails.shopAddress) {
|
|
const zipCodeMatch = appointmentDetails.shopAddress.match(/\b\d{5}$/);
|
|
if (zipCodeMatch) {
|
|
const zipCode = zipCodeMatch[0];
|
|
// Enter the ZIP code into the updateZipTextBox
|
|
await this.changeZipButton.click();
|
|
await this.page.waitForTimeout(500);
|
|
await this.updateZipTextBox.fill(zipCode);
|
|
await this.saveZipButton.click();
|
|
}
|
|
await this.inShopButton.click();
|
|
await this.selectAShopOptions.locator(`[buttonbodycopy="${appointmentDetails.shopAddress}"]`).scrollIntoViewIfNeeded().then(() => this.selectAShopOptions.locator(`[buttonbodycopy="${appointmentDetails.shopAddress}"]`).click());
|
|
} else {
|
|
await this.firstAppointmentButton.scrollIntoViewIfNeeded().then(async () => {
|
|
await this.firstAppointmentButton.click();
|
|
if (appointmentDetails) {
|
|
appointmentDetails.shopAddress = await this.firstAppointmentButton.locator('.row-two').innerText();
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
async scheduleMobile(testData: Partial<ITestData>) {
|
|
const { appointmentDetails, customerDetails } = testData;
|
|
if (appointmentDetails?.serviceAddress) {
|
|
await this.mobileButton.click();
|
|
if (!(await this.serviceAddressTextBox.isVisible())) {
|
|
await this.enterServiceAddressButton.click();
|
|
}
|
|
await this.addressForm.populateAddress({ address: appointmentDetails.serviceAddress! });
|
|
if (await this.repeatedClicksModalCloseButton.isVisible()) {
|
|
await this.repeatedClicksModalCloseButton.click();
|
|
}
|
|
if (faker.datatype.boolean()) {
|
|
await this.vehicleProtectedYesButton.check();
|
|
} else {
|
|
await this.vehicleProtectedNoButton.check();
|
|
}
|
|
if (appointmentDetails.appointmentTimeSlot == AppointmentTimeslot.EarlyBird)
|
|
{
|
|
await this.mockScheduleResponseForEarlyBird(customerDetails!);
|
|
}
|
|
} else {
|
|
console.error('ServiceLocationPage >> Please supply an address')
|
|
}
|
|
}
|
|
|
|
async scheduleDropOff(appointmentDetails?: IAppointmentDetails){
|
|
await this.dropOffButton.click();
|
|
if (appointmentDetails && appointmentDetails.shopAddress) {
|
|
await this.selectAShopOptions.locator(`[buttonbodycopy="${appointmentDetails.shopAddress}"]`).check();
|
|
} else {
|
|
// await this.firstAppointmentButton.click();
|
|
// await this.clickWithRetry(this.firstAppointmentButton, this.page);
|
|
await this.firstAppointmentButton.scrollIntoViewIfNeeded().then(async () => {
|
|
await this.firstAppointmentButton.click();
|
|
if (appointmentDetails) {
|
|
appointmentDetails.shopAddress = await this.firstAppointmentButton.locator('.row-two').innerText();
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
async validateRecalWarning(){
|
|
await expect(this.RecalWarningMessage1).toBeVisible();
|
|
await expect(this.RecalWarningMessage2).toBeVisible();
|
|
|
|
}
|
|
|
|
@step("ServiceLocationPage >> Select service location: ")
|
|
async handleServiceLocationPage(testData: Partial<ITestData>) {
|
|
|
|
await this.validateProgressBar("60");
|
|
await this.selectLocation(testData);
|
|
await this.nextPage();
|
|
}
|
|
} |