Payment method page validation changes
This commit is contained in:
parent
6fe56a56f2
commit
4344c19a30
8 changed files with 287 additions and 124 deletions
|
|
@ -9,6 +9,8 @@ export interface ICustomerDetails {
|
|||
notes: string,
|
||||
address: IAddress,
|
||||
apptDate?: string,
|
||||
apptTime?: string,
|
||||
apptDuration?: string,
|
||||
packagePrice?: string
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { expect, type Locator, type Page } from '@playwright/test';
|
||||
import { BasePage } from './BasePage';
|
||||
import { IPaymentDetails } from '@business-logic/types/CustomerDetails';
|
||||
import { PaymentMethod, PaymentType, ServicePackage, VehicleDamage } from '@business-logic/types/Enums';
|
||||
import { AppointmentType, PaymentMethod, PaymentType, ServicePackage, VehicleDamage } from '@business-logic/types/Enums';
|
||||
import { PaymentPage } from './PaymentPage';
|
||||
import { AfterpayPage } from './AfterpayPage';
|
||||
import { PaypalPage } from './PaypalPage';
|
||||
|
|
@ -17,6 +17,7 @@ export class PaymentMethodPage extends BasePage {
|
|||
readonly payInFourButton: Locator;
|
||||
readonly amountDueTextField: Locator;
|
||||
readonly amountDueDropDown: Locator;
|
||||
readonly appointmentDetailsSection: Locator;
|
||||
readonly appointmentDetailsDropdown: Locator;
|
||||
readonly subtotalAmountTextField: Locator;
|
||||
readonly submitButton: Locator;
|
||||
|
|
@ -48,6 +49,7 @@ export class PaymentMethodPage extends BasePage {
|
|||
this.payAtServiceButton = this.page.locator('[buttonlabel="Pay at my appointment"]'); //this.page.getByText('Pay at time of service');
|
||||
this.amountDueTextField = this.page.getByLabel('expand cart').locator('.amount-due');
|
||||
this.amountDueDropDown = this.page.getByLabel('expand cart');
|
||||
this.appointmentDetailsSection = this.page.locator('div .appt-details-snapshot');
|
||||
this.appointmentDetailsDropdown = this.page.getByLabel('expand appointment details');
|
||||
this.payWithInsuranceButton = this.page.locator('div').filter({ hasText: /^Pay with insurance$/ }).nth(1);
|
||||
this.subtotalAmountTextField = this.page.locator('.sub-total span').nth(1);
|
||||
|
|
@ -88,110 +90,27 @@ export class PaymentMethodPage extends BasePage {
|
|||
|
||||
// Wait for review table to be visible to ensure page is loaded
|
||||
await this.appointmentDetailsDropdown.waitFor({state: "visible"});
|
||||
await this.appointmentDetailsDropdown.click(); // Expand cart to see all details
|
||||
await this.appointmentDetailsDropdown.click();
|
||||
|
||||
let expectedAppointmentDetails = new Map<string, string[]>();
|
||||
expectedAppointmentDetails = await this.getExpectedVehicleDetails(testData, expectedAppointmentDetails);
|
||||
expectedAppointmentDetails = await this.getExpectedVehicleDamage(testData, expectedAppointmentDetails);
|
||||
expectedAppointmentDetails = await this.expectedServicePackageDetails(testData, expectedAppointmentDetails);
|
||||
expectedAppointmentDetails = await this.getExpectedServiceLocation(testData, expectedAppointmentDetails);
|
||||
expectedAppointmentDetails = await this.getExpectedAppointmentDate(testData, expectedAppointmentDetails);
|
||||
expectedAppointmentDetails = await this.getExpectedCustomerDetails(testData, expectedAppointmentDetails);
|
||||
|
||||
let actualAppointmentDetails = await this.getActualAppointmentDetails();
|
||||
|
||||
for (const key in expectedAppointmentDetails) {
|
||||
expect.soft(actualAppointmentDetails[key]?.map(item => item.toLowerCase()))
|
||||
.toEqual(expectedAppointmentDetails[key].map(item => item.toLowerCase()));
|
||||
}
|
||||
|
||||
// Expand cart to see all details
|
||||
await this.amountDueDropDown.click();
|
||||
await this.reviewTable.waitFor({ state: "visible" });
|
||||
|
||||
// Helper method to get content lines from a section
|
||||
const getSectionContent = async (section: Locator) => {
|
||||
// First make sure section exists
|
||||
if (await section.count() === 0) return [];
|
||||
|
||||
// Find all content lines within this section
|
||||
const contentLines = await section.locator('div.small.review-block-content').allInnerTexts();
|
||||
return contentLines;
|
||||
};
|
||||
|
||||
// Validate vehicle information
|
||||
const vehicleContent = await getSectionContent(this.vehicleSection);
|
||||
if (vehicleContent.length > 0) {
|
||||
const vehicleText = vehicleContent[0];
|
||||
expect.soft(vehicleText).toContain(`${vehicleDetails?.year} ${vehicleDetails?.make} ${vehicleDetails?.model}`);
|
||||
}
|
||||
|
||||
// Validate damage type
|
||||
|
||||
// TODO: Work out logic on how to verify vehicle Damage in payment details with vehicleDamage
|
||||
|
||||
// const damageContent = await getSectionContent(this.damageSection);
|
||||
// if (vehicleDamage && damageContent.length > 0) {
|
||||
// const damageText = damageContent[0];
|
||||
|
||||
// // For each damage type in the array, check if its display text is in the damage content
|
||||
// for (const damage of vehicleDamage) {
|
||||
// const expectedDamageText = this.getDamageDisplayText(damage);
|
||||
|
||||
// // If this is a single damage item, it should match exactly
|
||||
// if (vehicleDamage.length === 1) {
|
||||
// expect.soft(damageText).toContain(expectedDamageText);
|
||||
// } else {
|
||||
// // For multiple damages, check if any of the damage content lines contain this damage type
|
||||
// const damageFound = damageContent.some(content =>
|
||||
// content.includes(expectedDamageText)
|
||||
// );
|
||||
// expect.soft(damageFound).toBeTruthy();
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// Validate service details based on package
|
||||
const serviceContent = await getSectionContent(this.serviceDetailsSection);
|
||||
if (servicePackage && serviceContent.length > 0) {
|
||||
//TODO: Add service package validation
|
||||
// move over logic from Kishan's code
|
||||
|
||||
// Additional validations for Standard and Premium packages
|
||||
if (servicePackage === ServicePackage.Premium || servicePackage === ServicePackage.Standard) {
|
||||
await expect.soft(this.wiperBladesText).toBeVisible();
|
||||
}
|
||||
|
||||
if (servicePackage === ServicePackage.Premium) {
|
||||
await expect.soft(this.rainDefenseText).toBeVisible();
|
||||
}
|
||||
}
|
||||
|
||||
// Validate service location
|
||||
const locationContent = await getSectionContent(this.serviceLocationSection);
|
||||
if (appointmentDetails?.serviceLocation && locationContent.length > 0) {
|
||||
// Find the title element of the service location section
|
||||
const serviceLocationTitle = this.serviceLocationSection.locator('span').first();
|
||||
const serviceLocationValue = await serviceLocationTitle.innerText();
|
||||
|
||||
// Check for mobile/inshop service wording
|
||||
if (appointmentDetails.serviceLocation.toString().includes('Mobile')) {
|
||||
expect.soft(serviceLocationValue).toContain("We're coming to you");
|
||||
} else if (appointmentDetails.serviceLocation.toString().includes('InShop')) {
|
||||
expect.soft(serviceLocationValue).toContain("Bring to shop");
|
||||
}
|
||||
|
||||
// Validate address if available
|
||||
if (appointmentDetails.serviceAddress && locationContent.length > 0) {
|
||||
const addressText = locationContent[0].toLowerCase();
|
||||
expect.soft(addressText).toContain(appointmentDetails.serviceAddress.street.toLowerCase());
|
||||
}
|
||||
}
|
||||
|
||||
// Validate appointment date/time
|
||||
const appointmentContent = await getSectionContent(this.appointmentDateSection);
|
||||
if (customerDetails?.apptDate && appointmentContent.length > 0) {
|
||||
const appointmentText = appointmentContent[0];
|
||||
expect.soft(appointmentText).toContain(customerDetails.apptDate);
|
||||
}
|
||||
|
||||
// Validate contact details
|
||||
const contactContent = await getSectionContent(this.contactDetailsSection);
|
||||
if (customerDetails && contactContent.length > 0) {
|
||||
const fullName = `${customerDetails.firstName} ${customerDetails.lastName}`;
|
||||
const email = customerDetails.email;
|
||||
const phone = customerDetails.phoneNumber;
|
||||
|
||||
// Check if contact details are present
|
||||
const contactTextJoined = contactContent.join(' ');
|
||||
expect.soft(contactTextJoined).toContain(fullName);
|
||||
expect.soft(contactTextJoined).toContain(email);
|
||||
expect.soft(contactTextJoined).toContain(phone);
|
||||
}
|
||||
|
||||
// Cart Validation
|
||||
// Get pricing information from cart panel
|
||||
if (await this.subtotalText.isVisible()) {
|
||||
|
|
@ -339,4 +258,210 @@ l
|
|||
}
|
||||
}
|
||||
|
||||
async getActualAppointmentDetails(): Promise<any> {
|
||||
let actualAppointmentDetails = new Map<string, string[]>();
|
||||
let appointmentDetailsSubSections = await this.appointmentDetailsSection.locator('div .py-3').all();
|
||||
|
||||
for (let element of appointmentDetailsSubSections) {
|
||||
let label = await element.locator('div .text-block').innerText();
|
||||
//added to trim the text to remove any leading or trailing spaces (example: "expert installation " to "expert installation")
|
||||
let value = (await element.locator('.review-block-content').allInnerTexts() as string[]).map(item => item.trim());
|
||||
actualAppointmentDetails[label] = value;
|
||||
}
|
||||
return actualAppointmentDetails;
|
||||
}
|
||||
|
||||
async getExpectedVehicleDetails(testdata: Partial<ITestData>, expectedServicePackageDetails: Map<string, string[]>): Promise<any> {
|
||||
const { vehicleDetails } = testdata;
|
||||
expectedServicePackageDetails["Vehicle"] = [vehicleDetails?.year + " " + vehicleDetails?.make + " " + vehicleDetails?.model];
|
||||
return expectedServicePackageDetails;
|
||||
}
|
||||
|
||||
async getExpectedVehicleDamage(testdata: Partial<ITestData>, expectedServicePackageDetails: Map<string, string[]>): Promise<any> {
|
||||
|
||||
const {vehicleDamage} = testdata;
|
||||
|
||||
let vehicleDamageText: string[] = [];
|
||||
if (vehicleDamage?.find((item: VehicleDamage) => item == VehicleDamage.WindshieldOneChip)) {
|
||||
vehicleDamageText.push("Windshield repair - 1 chip");
|
||||
}
|
||||
|
||||
else if (vehicleDamage?.find((item: VehicleDamage) => item == VehicleDamage.WindshieldTwoChips)) {
|
||||
vehicleDamageText.push("Windshield repair - 2 chips");
|
||||
}
|
||||
|
||||
else if (vehicleDamage?.find((item: VehicleDamage) => item == VehicleDamage.WindshieldThreeChips)) {
|
||||
vehicleDamageText.push("Windshield repair - 3 chips");
|
||||
}
|
||||
|
||||
if (vehicleDamage?.find((item: VehicleDamage) => item == VehicleDamage.WindshieldCrack)) {
|
||||
vehicleDamageText.push("Windshield crack");
|
||||
}
|
||||
|
||||
if (vehicleDamage?.find((item: VehicleDamage) => item == VehicleDamage.DriverVentGlass)) {
|
||||
vehicleDamageText.includes("Side door - Driver side") ? vehicleDamageText[vehicleDamageText.length - 1 ] += "\nVent glass" : vehicleDamageText.push("Side door - Driver side", "Vent glass");
|
||||
}
|
||||
|
||||
if (vehicleDamage?.find((item: VehicleDamage) => item == VehicleDamage.DriverFrontDoor)) {
|
||||
vehicleDamageText.includes("Side door - Driver side") ? vehicleDamageText[vehicleDamageText.length - 1 ] += "\nFront door" : vehicleDamageText.push("Side door - Driver side", "Front door");
|
||||
}
|
||||
|
||||
if (vehicleDamage?.find((item: VehicleDamage) => item == VehicleDamage.DriverRearDoor)) {
|
||||
vehicleDamageText.includes("Side door - Driver side") ? vehicleDamageText[vehicleDamageText.length - 1 ] += "\nBack door" : vehicleDamageText.push("Side door - Driver side", "Back door");
|
||||
}
|
||||
|
||||
if (vehicleDamage?.find((item: VehicleDamage) => item == VehicleDamage.DriverQuarterPanel)) {
|
||||
vehicleDamageText.includes("Side door - Driver side") ? vehicleDamageText[vehicleDamageText.length - 1 ] += "\nQuarter panel" : vehicleDamageText.push("Side door - Driver side", "Quarter panel");
|
||||
}
|
||||
|
||||
if (vehicleDamage?.find((item: VehicleDamage) => item == VehicleDamage.PassengerVentGlass)) {
|
||||
vehicleDamageText.includes("Side door - Passenger side") ? vehicleDamageText[vehicleDamageText.length - 1 ] += "\nVent glass" : vehicleDamageText.push("Side door - Passenger side", "Vent glass");
|
||||
}
|
||||
|
||||
if (vehicleDamage?.find((item: VehicleDamage) => item == VehicleDamage.PassengerFrontDoor)) {
|
||||
vehicleDamageText.includes("Side door - Passenger side") ? vehicleDamageText[vehicleDamageText.length - 1 ] += "\nFront door" : vehicleDamageText.push("Side door - Passenger side", "Front door");
|
||||
}
|
||||
|
||||
if (vehicleDamage?.find((item: VehicleDamage) => item == VehicleDamage.PassengerRearDoor)) {
|
||||
vehicleDamageText.includes("Side door - Passenger side") ? vehicleDamageText[vehicleDamageText.length - 1 ] += "\nBack door" : vehicleDamageText.push("Side door - Passenger side", "Back door");
|
||||
}
|
||||
|
||||
if (vehicleDamage?.find((item: VehicleDamage) => item == VehicleDamage.PassengerQuarterPanel)) {
|
||||
vehicleDamageText.includes("Side door - Passenger side") ? vehicleDamageText[vehicleDamageText.length - 1 ] += "\nQuarter panel" : vehicleDamageText.push("Side door - Passenger side", "Quarter panel");
|
||||
}
|
||||
|
||||
if (vehicleDamage?.find((item: VehicleDamage) => item == VehicleDamage.RearWindow || item == VehicleDamage.RearSliding)) {
|
||||
vehicleDamageText.push("Rear window");
|
||||
}
|
||||
|
||||
expectedServicePackageDetails["Damage"] = vehicleDamageText;
|
||||
return expectedServicePackageDetails;
|
||||
}
|
||||
|
||||
async expectedServicePackageDetails(testData: Partial<ITestData>, expectedServicePackageDetails: Map<string, string[]>): Promise<any> {
|
||||
const {servicePackage} = testData;
|
||||
|
||||
let localStorage= JSON.parse(await this.page.evaluate('localStorage.getItem(\'vuex\')'));
|
||||
let isRepair = localStorage.order.damage.isRepair as boolean;
|
||||
let isInsurance = localStorage.order.payment.isInsurance as boolean;
|
||||
let hasNonWindshieldGlass: boolean = false;
|
||||
if (!isRepair) {
|
||||
hasNonWindshieldGlass = localStorage.order.lineItems.glassParts.find((item: any) => item.partType !== "WINDSHIELD") ? true : false;
|
||||
}
|
||||
let isCaliforniaState = localStorage.order.serviceLocation.state as string == 'CA' ? true : false;
|
||||
let recalRequired = !isRepair && (isInsurance || isCaliforniaState) &&
|
||||
localStorage.order.lineItems.glassParts.find((item: any) => item["requiresRecalibration"].value === true) ? true : false;
|
||||
let stringForRepair: string[] = ["Expert windshield repair", "Exclusive resin sealant", "Nationwide lifetime guarantee"];
|
||||
let stringIfRecal = isRepair
|
||||
? ""
|
||||
: recalRequired
|
||||
? " and recalibration"
|
||||
: "";
|
||||
let stringForReplace: string[] = [hasNonWindshieldGlass ? "New replacement glass" : "New replacement windshield", "Expert installation" + `${stringIfRecal}`, "Nationwide lifetime warranty"];
|
||||
switch (servicePackage)
|
||||
{
|
||||
case ServicePackage.GlassOnly:
|
||||
expectedServicePackageDetails["Glass service only"] = isRepair
|
||||
? stringForRepair
|
||||
: stringForReplace;
|
||||
break;
|
||||
case ServicePackage.Standard:
|
||||
stringForRepair.push("New wiper blades");
|
||||
stringForReplace.push("New wiper blades");
|
||||
expectedServicePackageDetails["Standard service"] = isRepair
|
||||
? stringForRepair
|
||||
: stringForReplace;
|
||||
break;
|
||||
case ServicePackage.Premium:
|
||||
stringForRepair.push("New wiper blades", "Rain Defense™");
|
||||
stringForReplace.push("New wiper blades", "Rain Defense™");
|
||||
expectedServicePackageDetails["Premium service"] = isRepair
|
||||
? stringForRepair
|
||||
: stringForReplace;
|
||||
break;
|
||||
}
|
||||
return expectedServicePackageDetails;
|
||||
}
|
||||
|
||||
async getExpectedServiceLocation(testData: Partial<ITestData>, expectedServicePackageDetails: Map<string, string[]>): Promise<any> {
|
||||
const { appointmentDetails } = testData;
|
||||
let serviceLocationTitle = appointmentDetails?.serviceLocation == AppointmentType.Mobile
|
||||
? "We're coming to you"
|
||||
: "You're going to a Safelite shop";
|
||||
let serviceLocation: string[] = [];
|
||||
|
||||
serviceLocation.push(
|
||||
appointmentDetails?.serviceLocation == AppointmentType.Mobile
|
||||
? appointmentDetails?.serviceAddress
|
||||
? appointmentDetails.serviceAddress.street + ", " + appointmentDetails.serviceAddress.city + ", " + appointmentDetails.serviceAddress.state + " " + appointmentDetails.serviceAddress.postalCode
|
||||
: ""
|
||||
: appointmentDetails?.shopAddress
|
||||
? appointmentDetails.shopAddress
|
||||
: ""
|
||||
);
|
||||
|
||||
expectedServicePackageDetails[serviceLocationTitle] = serviceLocation;
|
||||
return expectedServicePackageDetails;
|
||||
}
|
||||
|
||||
async getExpectedAppointmentDate(testData: Partial<ITestData>, expectedServicePackageDetails: Map<string, string[]>): Promise<any> {
|
||||
const { customerDetails, appointmentDetails } = testData;
|
||||
let appointmentDateText: string[] = [];
|
||||
const isMobileAppointment = appointmentDetails?.serviceLocation == AppointmentType.Mobile
|
||||
if (isMobileAppointment) {
|
||||
let localStorage= JSON.parse(await this.page.evaluate('localStorage.getItem(\'vuex\')'));
|
||||
let jobMinMinutes = localStorage.order.schedule.jobMinMinutes as number;
|
||||
let jobMaxMinutes = localStorage.order.schedule.jobMaxMinutes as number;
|
||||
|
||||
if (jobMinMinutes < 60) {
|
||||
customerDetails!.apptDuration = `${jobMinMinutes} - ${jobMaxMinutes} minutes`;
|
||||
} else {
|
||||
const minHours = Math.floor(jobMinMinutes / 60);
|
||||
const maxHours = Math.floor(jobMaxMinutes / 60);
|
||||
customerDetails!.apptDuration = `${minHours} - ${maxHours} hours`;
|
||||
}
|
||||
}
|
||||
|
||||
appointmentDateText.push(
|
||||
customerDetails?.apptDate ? await this.getFormattedAppointmentDate(customerDetails.apptDate) + " " + customerDetails?.apptTime?.replace("-", "—") : "",
|
||||
customerDetails?.apptDuration ? "Estimated appointment length: " + customerDetails.apptDuration : ""
|
||||
);
|
||||
|
||||
expectedServicePackageDetails["Appointment date + time"] = appointmentDateText;
|
||||
return expectedServicePackageDetails;
|
||||
}
|
||||
|
||||
async getExpectedCustomerDetails(testData: Partial<ITestData>, expectedServicePackageDetails: Map<string, string[]>): Promise<any> {
|
||||
const { customerDetails } = testData;
|
||||
let customerDetailsText: string[] = [];
|
||||
|
||||
customerDetailsText.push(
|
||||
customerDetails?.firstName.toUpperCase() + " " + customerDetails?.lastName.toUpperCase(),
|
||||
customerDetails?.email ? customerDetails?.email.toUpperCase() : "",
|
||||
customerDetails?.phoneNumber ? customerDetails?.phoneNumber : "",
|
||||
"Opted out of text message updates"
|
||||
);
|
||||
|
||||
expectedServicePackageDetails["Contact details"] = customerDetailsText;
|
||||
return expectedServicePackageDetails;
|
||||
}
|
||||
|
||||
async getFormattedAppointmentDate(appointmentDate: string) {
|
||||
const currentYear = new Date().getFullYear();
|
||||
|
||||
// Parse the original date
|
||||
let parsedAppointmentDate = new Date(`${appointmentDate}, ${currentYear}`);
|
||||
|
||||
let currentDate = new Date();
|
||||
currentDate.setDate(currentDate.getDate() - 2);
|
||||
|
||||
// If the original date is not in the future, adjust the year
|
||||
if (parsedAppointmentDate < currentDate) {
|
||||
parsedAppointmentDate.setFullYear(parsedAppointmentDate.getFullYear() + 1);
|
||||
}
|
||||
|
||||
// Format the new date as a string
|
||||
let updatedAppointmentDate = parsedAppointmentDate.toLocaleDateString('en-US', { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' });
|
||||
return updatedAppointmentDate;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,8 +1,9 @@
|
|||
import { expect, type Locator, type Page } from '@playwright/test';
|
||||
import { BasePage } from './BasePage';
|
||||
import { IAppointmentDetails } from '@business-logic/types/CustomerDetails';
|
||||
import { IAppointmentDetails, ICustomerDetails } from '@business-logic/types/CustomerDetails';
|
||||
import { formatDate, formatTime } from '@impl/utils/DateUtils';
|
||||
import { AppointmentType, ServiceLocation } from '@business-logic/types/Enums';
|
||||
import { time } from 'console';
|
||||
|
||||
export class SchedulePage extends BasePage {
|
||||
readonly page: Page;
|
||||
|
|
@ -13,6 +14,8 @@ export class SchedulePage extends BasePage {
|
|||
readonly dropOffButton: Locator;
|
||||
readonly dateText: Locator;
|
||||
readonly viewMoreDatesLink: Locator;
|
||||
readonly appointmentDuration: Locator;
|
||||
readonly timeSlots: Locator;
|
||||
|
||||
constructor(page: Page) {
|
||||
super(page);
|
||||
|
|
@ -23,6 +26,8 @@ export class SchedulePage extends BasePage {
|
|||
this.dropOffButton = this.page.getByText('Drop off your vehicle', { exact: true });
|
||||
this.dateText = this.page.locator('label.modal-title');
|
||||
this.viewMoreDatesLink = this.page.getByText(/View more dates/).first();
|
||||
this.appointmentDuration = this.page.locator('.duration-text-block');
|
||||
this.timeSlots = this.page.locator('fieldset:has(legend[id *= \'chooseTimeSlot\']) label');
|
||||
}
|
||||
|
||||
async scheduleAppointment(appointmentDetails: IAppointmentDetails) {
|
||||
|
|
@ -40,20 +45,40 @@ export class SchedulePage extends BasePage {
|
|||
await this.modalContinueButton.click();
|
||||
}
|
||||
|
||||
async scheduleFirstAppointment(serviceLocation: AppointmentType) {
|
||||
if (await this.firstAvailableDate.isVisible()) {
|
||||
await this.firstAvailableDate.click();
|
||||
} else {
|
||||
async scheduleFirstAppointment(customerDetails: ICustomerDetails) {
|
||||
while (!(await this.firstAvailableDate.isVisible())) {
|
||||
await this.viewMoreDatesLink.click();
|
||||
while(await this.firstAvailableDate.isHidden()){
|
||||
await this.viewMoreDatesLink.click();
|
||||
}
|
||||
await this.firstAvailableDate.click();
|
||||
}
|
||||
await this.firstAvailableDate.click();
|
||||
|
||||
serviceLocation === AppointmentType.DropOff ? await this.dropOffButton.click() : await this.firstAvailableTime.click();
|
||||
const apptDate = `${await this.dateText.allInnerTexts()}`
|
||||
// const timeSlots = this.timeSlots;
|
||||
const timeSlotCount = await this.timeSlots.count();
|
||||
const randomIndex = Math.floor(Math.random() * timeSlotCount);
|
||||
const timeSlot = this.timeSlots.nth(randomIndex);
|
||||
await timeSlot.click().then(async () => {
|
||||
customerDetails.apptTime = await this.getFormattedTimeSlot(timeSlot);
|
||||
});
|
||||
// appointmentmentDetails.serviceLocation === AppointmentType.DropOff ? await this.dropOffButton.click() : await this.firstAvailableTime.click();
|
||||
customerDetails.apptDate = `${await this.dateText.allInnerTexts()}`
|
||||
customerDetails.apptDuration = (await this.appointmentDuration.innerText()).replace("Duration: ", "");
|
||||
await this.modalContinueButton.click();
|
||||
return (apptDate);
|
||||
}
|
||||
}
|
||||
|
||||
async getFormattedTimeSlot(timeSlot: Locator) {
|
||||
const selectedTimeSlot = await timeSlot.innerText();
|
||||
let formattedTimeSlot: string = "";
|
||||
if (selectedTimeSlot.toLowerCase().includes("drop off"))
|
||||
{
|
||||
formattedTimeSlot = selectedTimeSlot.includes("overnight") ? "drop off by 5:30 pm on the night of your scheduled appointment. Pick-up time dependent on shop schedule" : "drop off before 9:30 AM";
|
||||
}
|
||||
else if (selectedTimeSlot.includes("-") || selectedTimeSlot.toLowerCase().includes("Earlybird"))
|
||||
{
|
||||
formattedTimeSlot = selectedTimeSlot.includes("Earlybird") ? "arriving between 8:00 AM - 12:00 PM" : `arriving between ${selectedTimeSlot}`;
|
||||
}
|
||||
else
|
||||
{
|
||||
formattedTimeSlot = `at ${selectedTimeSlot}`;
|
||||
}
|
||||
return formattedTimeSlot;
|
||||
}
|
||||
}
|
||||
|
|
@ -55,7 +55,7 @@ export class ServiceLocationPage extends BasePage {
|
|||
|
||||
// For in-shop and drop off
|
||||
this.selectAShopOptions = this.page.locator('[class="shop-question"]');
|
||||
this.firstAppointmentButton = this.page.locator('div').filter({ hasText: /Appts/}).first();
|
||||
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 });
|
||||
|
|
@ -103,9 +103,14 @@ export class ServiceLocationPage extends BasePage {
|
|||
await this.saveZipButton.click();
|
||||
}
|
||||
await this.inShopButton.click();
|
||||
await this.selectAShopOptions.locator(`[buttonbodycopy="${appointmentDetails.shopAddress}"]`).check();
|
||||
await this.selectAShopOptions.locator(`[buttonbodycopy="${appointmentDetails.shopAddress}"]`).scrollIntoViewIfNeeded().then(() => this.selectAShopOptions.locator(`[buttonbodycopy="${appointmentDetails.shopAddress}"]`).click());
|
||||
} else {
|
||||
await this.firstAppointmentButton.click();
|
||||
await this.firstAppointmentButton.scrollIntoViewIfNeeded().then(async () => {
|
||||
await this.firstAppointmentButton.click();
|
||||
if (appointmentDetails) {
|
||||
appointmentDetails.shopAddress = await this.firstAppointmentButton.locator('.row-two').innerText();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -115,7 +120,7 @@ export class ServiceLocationPage extends BasePage {
|
|||
await this.enterServiceAddressButton.click();
|
||||
await this.addressForm.populateAddress({ address: appointmentDetails.serviceAddress! });
|
||||
if (await this.repeatedClicksModalCloseButton.isVisible()) {
|
||||
await this.repeatedClicksModalCloseButton.click();
|
||||
await this.repeatedClicksModalCloseButton.click();
|
||||
}
|
||||
if (faker.datatype.boolean()) {
|
||||
await this.vehicleProtectedYesButton.check();
|
||||
|
|
@ -134,7 +139,13 @@ export class ServiceLocationPage extends BasePage {
|
|||
await this.selectAShopOptions.locator(`[buttonbodycopy="${appointmentDetails.shopAddress}"]`).check();
|
||||
} else {
|
||||
// await this.firstAppointmentButton.click();
|
||||
await this.clickWithRetry(this.firstAppointmentButton, this.page);
|
||||
// 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();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ const cashRepairMobileCCData : Partial<ITestData> = {
|
|||
serviceAddress: {
|
||||
street: '13735 San Antonio Ave',
|
||||
city: 'Chino',
|
||||
state: 'California',
|
||||
state: 'CA',
|
||||
postalCode: '91710',
|
||||
country: 'United States'
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ const cashReplaceMultiGlassMobileData: Partial<ITestData> = {
|
|||
// Use street address from current faker seed
|
||||
street: getDefaultTestData().customerDetails!.address.street,
|
||||
city: 'Rosedale',
|
||||
state: 'Maryland',
|
||||
state: 'MD',
|
||||
postalCode: '21237',
|
||||
country: 'United States'
|
||||
},
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ const cashReplaceSafeliteCanNotRecalMobileData: Partial<ITestData> = {
|
|||
// Use street address from current faker seed
|
||||
street: getDefaultTestData().customerDetails!.address.street,
|
||||
city: 'Rosedale',
|
||||
state: 'Maryland',
|
||||
state: 'MD',
|
||||
postalCode: '21237',
|
||||
country: 'United States'
|
||||
},
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ const cashReplaceVinMobileData: Partial<ITestData> = {
|
|||
// Use street address from current faker seed
|
||||
street: getDefaultTestData().customerDetails!.address.street,
|
||||
city: 'Rosedale',
|
||||
state: 'Maryland',
|
||||
state: 'MD',
|
||||
postalCode: '21237',
|
||||
country: 'United States'
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue