Revert "Merge pull request #2458 from Safelite/feature/CASH-530"

This reverts commit dafc79cd64, reversing
changes made to 8ae73d4b6b.
This commit is contained in:
Scott Kiener 2025-04-30 10:01:27 -04:00
parent d5dee09502
commit de2f501773
38 changed files with 508 additions and 817 deletions

View file

@ -23,6 +23,4 @@ CCIS_API_URL="https://api.test.belronus.io"
ADMIN_SERVICE_API_URL="https://issadminapi.dev.sagaws.net/iss-admin/api/v1/"
# API authentication (replace with actual value when running tests)
CCIS_API_AUTH="undefined"
SKIP_CONTENT_SITE=false
CCIS_API_AUTH="undefined"

View file

@ -9,8 +9,6 @@ export interface ICustomerDetails {
notes: string,
address: IAddress,
apptDate?: string,
apptTime?: string,
apptDuration?: string,
packagePrice?: string
}

View file

@ -27,7 +27,6 @@ import { CoverageStatementPage } from "../../pages/CoverageStatementPage"
import { VerifyDetailsPage } from "../../pages/VerifyDetailsPage"
import { EndorsementsPage } from "../../pages/EndorsementsPage"
import { PolicyDriverPage } from "../../pages/PolicyDriverPage"
import { ServiceZipPage } from "../../pages/ServiceZipPage"
// File containing interface for all Page Object Models
export default interface ITestPages {
@ -49,8 +48,7 @@ export default interface ITestPages {
recalibrationInfoPage: RecalibrationInfoPage,
schedulePage: SchedulePage,
serviceLocationPage: ServiceLocationPage,
servicePackagesPage: ServicePackagesPage,
serviceZipPage: ServiceZipPage,
servicePackagePage: ServicePackagesPage,
vehicleDamagePage: VehicleDamagePage,
vehicleLookupAddressPage: VehicleLookupAddressPage,
vehicleLookupLicensePage: VehicleLookupLicensePage,

View file

@ -1,27 +0,0 @@
import { test } from '@business-logic/types/Test';
export type Context = {
kind: string;
name: string | symbol;
access: {
get?(): unknown;
set?(value: unknown): void;
has?(value: unknown): boolean;
};
private?: boolean;
static?: boolean;
addInitializer?(initializer: () => void): void;
};
export type Method = (...args: any[]) => any;
export function step(label: string): Method {
return <T extends Method>(value: T, context: Context): Method => {
return function (this: any, ...args: any[]): Promise<any> {
// console.log(`Method ${value.name} has been decorated`, context, args, label);
return test.step(label, async () => {
return value.call(this, ...args);
});
};
};
}

View file

@ -41,7 +41,6 @@ import { CoverageStatementPage } from "../../pages/CoverageStatementPage";
import { VerifyDetailsPage } from "../../pages/VerifyDetailsPage";
import { EndorsementsPage } from "../../pages/EndorsementsPage";
import { PolicyDriverPage } from "../../pages/PolicyDriverPage";
import { ServiceZipPage } from "../../pages/ServiceZipPage";
// File for Test Case Class
@ -165,8 +164,7 @@ export default class TestCase extends DisposableBase implements ITestCase {
recalibrationInfoPage: new RecalibrationInfoPage(page),
schedulePage: new SchedulePage(page),
serviceLocationPage: new ServiceLocationPage(page),
servicePackagesPage: new ServicePackagesPage(page),
serviceZipPage: new ServiceZipPage(page),
servicePackagePage: new ServicePackagesPage(page),
vehicleDamagePage: new VehicleDamagePage(page),
vehicleLookupAddressPage: new VehicleLookupAddressPage(page),
vehicleLookupLicensePage: new VehicleLookupLicensePage(page),

View file

@ -2,8 +2,6 @@ import { expect, type Locator, type Page } from '@playwright/test';
import { IClaimDetails, ICustomerDetails } from '@business-logic/types/CustomerDetails';
import { InsuranceBasePage } from './InsuranceBasePage';
import { STATE_ABBREVIATIONS } from '@business-logic/constants/StateAbbreviation';
import { ITestData } from '@business-logic/types/ITestData';
import { step } from '@business-logic/types/Step';
export class CCPolicyInfoPage extends InsuranceBasePage {
readonly policyNumber: Locator;
@ -72,12 +70,4 @@ export class CCPolicyInfoPage extends InsuranceBasePage {
throw error;
}
}
@step("CCPolicyInfoPage >> Fill out claim information")
async handleCCPolicyInfoPage(testData: Partial<ITestData>) {
const { customerDetails, claimDetails } = testData;
await this.populatePage(customerDetails!, claimDetails!, await this.hasCityInfo());
await this.nextPage();
}
}

View file

@ -1,7 +1,5 @@
import { Page } from "@playwright/test";
import { PartQuestionsPage } from "./PartQuestionPage";
import { step } from "@business-logic/types/Step";
import { ITestData } from "@business-logic/types/ITestData";
export default class CapabilityQuestionsPage extends PartQuestionsPage {
url = process.env['BASE_URL']! + '/fmg/?fmgPage=capability-questions';
@ -9,18 +7,4 @@ export default class CapabilityQuestionsPage extends PartQuestionsPage {
constructor(page: Page) {
super(page);
}
@step("CapabilityQuestionsPage >> Select Capability Questions: ")
async handleCapabilityQuestionsPage(testCase: Partial<ITestData>) {
const { capabilityQuestions } = testCase;
// Validate the capability questions are on the page
await this.validatePartQuestions(capabilityQuestions!);
// Select the capability question responses
await this.selectPartQuestionResponses(capabilityQuestions!);
// Proceed to the next page
await this.nextPage();
}
}

View file

@ -1,8 +1,6 @@
import { expect, type Locator, type Page } from '@playwright/test';
import { BasePage } from './BasePage';
import { ICustomerDetails } from '@business-logic/types/CustomerDetails';
import { step } from '@business-logic/types/Step';
import { ITestData } from '@business-logic/types/ITestData';
export class ContactDetailsPage extends BasePage {
readonly page: Page;
@ -41,11 +39,4 @@ export class ContactDetailsPage extends BasePage {
await this.notesTextBox.fill(notes);
}
}
@step("ContactDetailsPage >> Enter contact details: ")
async handleContactDetailsPage(testData: Partial<ITestData>) {
const { customerDetails } = testData;
await this.enterContactDetails(customerDetails!);
await this.nextPage();
}
}

View file

@ -1,8 +1,6 @@
import { expect, type Locator, type Page } from '@playwright/test';
import { InsuranceBasePage } from './InsuranceBasePage';
import { IClaimDetails } from '@business-logic/types/CustomerDetails';
import { step } from '@business-logic/types/Step';
import { ITestData } from '@business-logic/types/ITestData';
export class CoverageStatementPage extends InsuranceBasePage {
readonly page: Page;
@ -56,12 +54,5 @@ export class CoverageStatementPage extends InsuranceBasePage {
async validateUnverifiedText(){
await expect(this.verfiyingCoverageText).toBeEnabled();
}
@step("CoverageStatementPage >> Next page: ")
async handleCoverageStatementPage(testData: Partial<ITestData>) {
const { claimDetails } = testData;
await this.validateDeductibleAmount(claimDetails!);
await this.nextPage();
}
}

View file

@ -1,7 +1,5 @@
import { expect, type Locator, type Page } from '@playwright/test';
import { InsuranceBasePage } from './InsuranceBasePage';
import { ITestData } from '@business-logic/types/ITestData';
import { step } from '@business-logic/types/Step';
export class DuplicateCheckPage extends InsuranceBasePage {
readonly page: Page;
@ -20,9 +18,4 @@ export class DuplicateCheckPage extends InsuranceBasePage {
await this.page.waitForLoadState();
}
@step("DuplicateCheckPage >> Start a new claim: ")
async handleDuplicateCheckPage(testCase: Partial<ITestData>) {
await this.startNewClaim();
await this.nextPage();
}
}

View file

@ -3,8 +3,6 @@ import { BasePage } from './BasePage';
import { IEndorsementDetails } from '@business-logic/types/CustomerDetails';
import { EndorsementType } from '@business-logic/types/Enums';
import { InsuranceBasePage } from './InsuranceBasePage';
import { step } from '@business-logic/types/Step';
import { ITestData } from '@business-logic/types/ITestData';
export class EndorsementsPage extends InsuranceBasePage {
readonly page: Page;
@ -54,12 +52,4 @@ export class EndorsementsPage extends InsuranceBasePage {
}
}
}
@step("EndorsementsPage >> Select endorsements: ")
async handleEndorsementsPage(testData: Partial<ITestData>) {
const { endorsements } = testData;
await this.verifyEndorsements(endorsements!);
await this.selectEndorsements(endorsements!);
await this.nextPage();
}
}

View file

@ -5,8 +5,6 @@ import { IVehicleDetails } from '@business-logic/types/CustomerDetails';
import { VinLookupPage } from './VinLookupPage';
import { VehicleLookupAddressPage } from './VehicleLookupAddressPage';
import { VehicleLookupLicensePage } from './VehicleLookupLicensePage';
import { step } from '@business-logic/types/Step';
import { ITestData } from '@business-logic/types/ITestData';
export class EstimatePage extends BasePage {
readonly page: Page;
@ -22,7 +20,7 @@ export class EstimatePage extends BasePage {
constructor(page: Page) {
super(page);
this.page = page;
this.vinLookupButton = page.locator('label').filter({ hasText: 'Provide my VIN' }).locator('div');
this.vinLookupButton = page.getByLabel('Provide my VIN', { exact: true });
this.zipLookupButton = page.locator('label').filter({ hasText: 'I\'d rather not share my VIN' }).locator('div');
this.addressLookupButton = page.getByLabel('Provide my home address', { exact: true });
this.licenseLookupButton = page.getByLabel('Provide my license plate #', { exact: true });
@ -70,10 +68,4 @@ export class EstimatePage extends BasePage {
async selectZipLookup(){
await this.zipLookupButton.click();
}
@step("EstimatePage >> Select Lookup Type")
async handleEstimatePage(testData: Partial<ITestData>) {
const { vehicleDetails } = testData;
await this.vehicleLookup(vehicleDetails!);
}
}

View file

@ -1,9 +1,6 @@
import { type Locator, type Page } from '@playwright/test';
import { BasePage } from './BasePage';
import { IClaimDetails } from '@business-logic/types/CustomerDetails';
import { step } from '@business-logic/types/Step';
import TestCase from '@business-logic/types/TestCase';
import { ITestData } from '@business-logic/types/ITestData';
export class InsuranceCompanyPage extends BasePage {
@ -47,12 +44,4 @@ export class InsuranceCompanyPage extends BasePage {
}
}
}
@step("InsuranceCompanyPage >> Enter insurance company: ")
async handleInsuranceCompanyPage(testData: Partial<ITestData>) {
const { claimDetails } = testData;
await this.enterInsuranceCompany(claimDetails!.client!);
await this.nextPage();
}
}

View file

@ -1,7 +1,5 @@
import { Page } from "@playwright/test";
import { PartQuestionsPage } from "./PartQuestionPage";
import { step } from "@business-logic/types/Step";
import { ITestData } from "@business-logic/types/ITestData";
export default class MoldingQuestionsPage extends PartQuestionsPage {
url = process.env['BASE_URL']! + '/fmg/?fmgPage=molding-questions';
@ -9,12 +7,4 @@ export default class MoldingQuestionsPage extends PartQuestionsPage {
constructor(page: Page) {
super(page);
}
@step("MoldingQuestionsPage >> Select Molding Questions: ")
async handleMoldingQuestionsPage(testCase: Partial<ITestData>) {
const { moldingQuestions } = testCase;
await this.validatePartQuestions(moldingQuestions!);
await this.selectPartQuestionResponses(moldingQuestions!);
await this.nextPage();
}
}

View file

@ -1,10 +1,8 @@
import { expect, type Locator, type Page } from '@playwright/test';
import { BasePage } from './BasePage';
import { test } from '@business-logic/types/Test';
import { ICustomerDetails, IVehicleDetails } from '@business-logic/types/CustomerDetails';
import { ServicePackage, PaymentType, PaymentMethod, AppointmentType } from '@business-logic/types/Enums';
import { ServicePackage, PaymentType, PaymentMethod } from '@business-logic/types/Enums';
import { ITestData } from '@business-logic/types/ITestData';
import { step } from '@business-logic/types/Step';
export class OrderConfirmationPage extends BasePage {
readonly page: Page;
@ -19,7 +17,6 @@ export class OrderConfirmationPage extends BasePage {
readonly cartServicePackageText: Locator;
readonly winshieldWiper: Locator;
readonly rainDefense: Locator;
readonly appointmentSummarySection: Locator;
url = process.env['BASE_URL']! + '/fmg/?fmgPage=confirmation';
@ -37,7 +34,6 @@ export class OrderConfirmationPage extends BasePage {
this.subtotalText = this.page.locator('.sub-total');
this.finalAmountDue = this.page.locator('div.amount-due');
this.cartServicePackageText = this.cartServicePackageText = this.page.locator('.cart-panel');
this.appointmentSummarySection = this.page.locator('.main .scheduleText, .main .add-to-calendar-text, .main .appointment-text, .main .duration-text-block');
// this.validateURL(this.url);
}
@ -46,10 +42,10 @@ export class OrderConfirmationPage extends BasePage {
const { vehicleDetails, customerDetails, servicePackage, promoCode,
isPolicyFound, claimDetails, paymentDetails, isUseVehicleOnPolicy, paymentMethod } = testData;
await this.serviceText.waitFor({ state: "visible" });
expect.soft((await this.getActualAppointmentSummary()).map(item => item.toLowerCase())).toEqual((await this.getExpectedAppointmentSummary(testData)).map(item => item.toLowerCase()));
// Grab text
const serviceTextValue = await this.serviceText.textContent();
const apptDateValue = await this.apptDateText.textContent();
const emailTextValue = await this.emailText.textContent();
const servicePackageValue = await this.cartServicePackageText.textContent();
const amountDueValue = await this.amountDueText.textContent();
@ -61,6 +57,8 @@ export class OrderConfirmationPage extends BasePage {
const servicePackageAmt = Number.parseFloat(servicePackageValue!.split('$')[1].replaceAll(',', ''));
// General Validations
expect.soft(serviceTextValue).toContain(`${vehicleDetails!.year} ${vehicleDetails!.make} ${vehicleDetails!.model}`);
expect.soft(apptDateValue).toContain(customerDetails!.apptDate);
expect.soft(emailTextValue).toContain(customerDetails!.email);
// Service package validations
@ -125,63 +123,9 @@ export class OrderConfirmationPage extends BasePage {
}
}
async getFormattedAppointmentDate(appointmentDate: string) {
// Parse the original date
let parsedAppointmentDate = new Date(`${appointmentDate}` + 'T00:00:00');
// Format the new date as a string
let updatedAppointmentDate = parsedAppointmentDate.toLocaleDateString('en-US', { weekday: 'long', month: 'long', day: 'numeric' });
return updatedAppointmentDate;
}
async logOrderNumber() {
const sessionStorage = JSON.parse(await this.page.evaluate('sessionStorage.getItem(\'submittedState\')'));
return sessionStorage.order.workOrderNumber;
return sessionStorage.workOrderNumber;
}
async getActualAppointmentSummary(): Promise<string[]> {
let appointmentSummary: string[] = [];
for (let element of await this.appointmentSummarySection.all()){
let text = (await element.textContent() || "").replaceAll(/\u00A0|&nbsp;/g, ' ');
appointmentSummary.push(text.trim());
}
return appointmentSummary;
}
async getExpectedAppointmentSummary(testData: Partial<ITestData>): Promise<string[]> {
const { appointmentDetails, customerDetails, vehicleDetails } = testData;
let appointmentSummary: string[] = [];
// Format the expected appointment date
const formattedExpectedAppointmentDate = await this.getFormattedAppointmentDate(customerDetails!.apptDate!);
appointmentSummary.push(
appointmentDetails?.serviceLocation == AppointmentType.Mobile
? formattedExpectedAppointmentDate + `${customerDetails!.apptTime?.replace("arriving between", "Between").replaceAll(":00", "")}`
: appointmentDetails?.serviceLocation == AppointmentType.InShop
? formattedExpectedAppointmentDate + `${customerDetails!.apptTime}`
: formattedExpectedAppointmentDate + "Drop off before 9:30 AM"
);
appointmentSummary.push("Add to calendar");
appointmentSummary.push(
appointmentDetails?.serviceLocation == AppointmentType.Mobile
? appointmentDetails?.serviceAddress
? ("We're coming to you at" + appointmentDetails.serviceAddress.street + ", " + appointmentDetails.serviceAddress.city + ", " + appointmentDetails.serviceAddress.state + " " + appointmentDetails.serviceAddress.postalCode + "to service your " + `${vehicleDetails!.year} ${vehicleDetails!.make} ${vehicleDetails!.model}`)
: ""
: appointmentDetails?.shopAddress
? ("You're going to a Safelite shop at" + appointmentDetails.shopAddress + "to service your " + `${vehicleDetails!.year} ${vehicleDetails!.make} ${vehicleDetails!.model}`)
: "");
appointmentSummary.push("Duration: " + customerDetails!.apptDuration!);
return appointmentSummary;
}
@step("OrderConfirmationPage >> Validate order")
async verifyOrderConfirmationPage(testData: Partial<ITestData>) {
await this.validateOrderConfirmationPage(testData);
const workOrderNumber = await this.logOrderNumber();
await test.step(`Session Storage Work Order Number: ${workOrderNumber}`, async () => {
console.log(`Session Storage Work Order Number: ${workOrderNumber}`);
});
}
}

View file

@ -1,8 +1,6 @@
import { expect, type Locator, type Page } from '@playwright/test';
import { BasePage } from './BasePage';
import { IPartQuestion } from '@business-logic/types/CustomerDetails';
import { step } from '@business-logic/types/Step';
import { ITestData } from '@business-logic/types/ITestData';
export class PartQuestionsPage extends BasePage {
readonly page: Page;
@ -58,12 +56,4 @@ export class PartQuestionsPage extends BasePage {
}
}
}
@step("PartQuestionsPage >> Select Vehicle Part Question Responses")
async handlePartQuestionsPage(testData: Partial<ITestData>) {
const { partQuestions } = testData;
await this.validatePartQuestions(partQuestions!);
await this.selectPartQuestionResponses(partQuestions!);
await this.nextPage();
}
}

View file

@ -1,12 +1,11 @@
import { expect, type Locator, type Page } from '@playwright/test';
import { BasePage } from './BasePage';
import { IPaymentDetails } from '@business-logic/types/CustomerDetails';
import { AppointmentType, PaymentMethod, PaymentType, ServicePackage, VehicleDamage } from '@business-logic/types/Enums';
import { PaymentMethod, PaymentType, ServicePackage, VehicleDamage } from '@business-logic/types/Enums';
import { PaymentPage } from './PaymentPage';
import { AfterpayPage } from './AfterpayPage';
import { PaypalPage } from './PaypalPage';
import { ITestData } from '@business-logic/types/ITestData';
import { step } from '@business-logic/types/Step';
export class PaymentMethodPage extends BasePage {
readonly page: Page;
@ -18,7 +17,6 @@ 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;
@ -50,7 +48,6 @@ 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);
@ -91,27 +88,110 @@ 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();
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.appointmentDetailsDropdown.click(); // 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()) {
@ -259,221 +339,4 @@ 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 hasRecalPart: boolean = false;
if (!isRepair) {
hasRecalPart = localStorage.order.lineItems.glassParts.find((item: any) => item.requiresRecalibration === true) ? true : false;
}
let recalRequired = !isRepair && (isInsurance || isCaliforniaState) && hasRecalPart
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) {
// Parse the original date
let parsedAppointmentDate = new Date(`${appointmentDate}` + 'T00:00:00');
// Format the new date as a string
let updatedAppointmentDate = parsedAppointmentDate.toLocaleDateString('en-US', { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' });
return updatedAppointmentDate;
}
@step("PaymentMethodPage >> Select Payment Method: ")
async handlePaymentMethodPage(testData: Partial<ITestData>) {
const { servicePackage, isRecalVehicle, paymentDetails } = testData;
await this.validatePaymentDetailsPage(testData);
// Verify VAPS wipers on backend for standard and premium packages
if (servicePackage === ServicePackage.Standard || servicePackage === ServicePackage.Premium) {
await this.verifyVAPS();
}
if (paymentDetails?.paymentType) {
await this.executePayment(paymentDetails!, isRecalVehicle!);
} else {
await this.nextPage();
}
}
}

View file

@ -1,8 +1,6 @@
import { expect, type Locator, type Page } from '@playwright/test';
import { InsuranceBasePage } from './InsuranceBasePage';
import { ICustomerDetails } from '@business-logic/types/CustomerDetails';
import { step } from '@business-logic/types/Step';
import { ITestData } from '@business-logic/types/ITestData';
export class PolicyDriverPage extends InsuranceBasePage {
readonly page: Page;
@ -49,11 +47,5 @@ export class PolicyDriverPage extends InsuranceBasePage {
await this.driverNotListedOption.click();
}
}
@step("PolicyDriverPage >> Select policy driver: ")
async handlePolicyDriverPage(testData: Partial<ITestData>) {
const { customerDetails } = testData;
await this.selectPolicyDriver(customerDetails!);
await this.nextPage();
}
}

View file

@ -1,6 +1,5 @@
import { expect, type Locator, type Page } from '@playwright/test';
import { InsuranceBasePage } from './InsuranceBasePage';
import { step } from '@business-logic/types/Step';
export class PolicyInfoSubmittedPage extends InsuranceBasePage {
readonly page: Page;
@ -21,10 +20,5 @@ export class PolicyInfoSubmittedPage extends InsuranceBasePage {
const policyInfoMessage = await this.policyInfoMessage.textContent();
expect(policyInfoMessage).toBe("Your policy and vehicle information has been submitted for coverage verification")
}
@step("PolicyInfoSubmittedPage >> Verify policy info submitted: ")
async handlePolicyInfoSubmittedPage() {
await this.verifyPolicyInfoSubmitted();
await this.nextPage();
}
}

View file

@ -1,8 +1,6 @@
import { expect, type Locator, type Page } from '@playwright/test';
import { IVehicleDetails } from '@business-logic/types/CustomerDetails';
import { InsuranceBasePage } from './InsuranceBasePage';
import { ITestData } from '@business-logic/types/ITestData';
import { step } from '@business-logic/types/Step';
export class PolicyVehiclesPage extends InsuranceBasePage {
readonly page: Page;
@ -28,29 +26,4 @@ export class PolicyVehiclesPage extends InsuranceBasePage {
async selectVehicleNotListed(){
await this.page.getByText('Vehicle not listed').click();
}
@step("PolicyVehiclesPage >> Select Vehicle: ")
async handlePolicyVehiclesPage(testCase: Partial<ITestData>) {
const { vehicleDetails, otherVehiclesOnPolicy, isUseVehicleOnPolicy } = testCase;
// Validate other vehicles on policy
if (otherVehiclesOnPolicy && otherVehiclesOnPolicy.length > 0) {
for (const vehicle of otherVehiclesOnPolicy) {
await this.validateVehicleIsOnPolicy(vehicle);
}
}
// If vehicle is not on the policy, select new vehicle
if (!(isUseVehicleOnPolicy ?? true)) {
await this.selectVehicleNotListed();
await this.nextPage();
await this.selectVehicle(vehicleDetails!);
await this.nextPage();
} else {
// Otherwise, select the vehicle entered in Safelite.com
await this.selectVehicle(vehicleDetails!);
await this.nextPage();
}
}
}

View file

@ -1,6 +1,5 @@
import { Locator, Page } from "@playwright/test";
import { InsuranceBasePage } from "./InsuranceBasePage";
import { step } from "@business-logic/types/Step";
export default class RecalibrationInfoPage extends InsuranceBasePage {
url = process.env['BASE_URL']! + '/FixMyGlass/RecalibrationInfo.aspx';
@ -12,9 +11,4 @@ export default class RecalibrationInfoPage extends InsuranceBasePage {
this.continueButton = page.getByRole('button', { name: 'Continue' });
}
@step("RecalibrationInfoPage >> Click continue button: ")
async handleRecalibrationInfoPage() {
await this.nextPage();
}
}

View file

@ -1,11 +1,8 @@
import { expect, type Locator, type Page } from '@playwright/test';
import { BasePage } from './BasePage';
import { IAppointmentDetails, ICustomerDetails } from '@business-logic/types/CustomerDetails';
import { IAppointmentDetails } from '@business-logic/types/CustomerDetails';
import { formatDate, formatTime } from '@impl/utils/DateUtils';
import { AppointmentType, ServiceLocation } from '@business-logic/types/Enums';
import { time } from 'console';
import { step } from '@business-logic/types/Step';
import { ITestData } from '@business-logic/types/ITestData';
export class SchedulePage extends BasePage {
readonly page: Page;
@ -16,8 +13,6 @@ 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);
@ -28,8 +23,6 @@ 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[aria-labelledby=\'chooseTimeSlot\'] label');
}
async scheduleAppointment(appointmentDetails: IAppointmentDetails) {
@ -47,47 +40,20 @@ export class SchedulePage extends BasePage {
await this.modalContinueButton.click();
}
async scheduleFirstAppointment(customerDetails: ICustomerDetails) {
while (!(await this.firstAvailableDate.isVisible())) {
async scheduleFirstAppointment(serviceLocation: AppointmentType) {
if (await this.firstAvailableDate.isVisible()) {
await this.firstAvailableDate.click();
} else {
await this.viewMoreDatesLink.click();
while(await this.firstAvailableDate.isHidden()){
await this.viewMoreDatesLink.click();
}
await this.firstAvailableDate.click();
}
await this.firstAvailableDate.click().then(async () => {
customerDetails.apptDate = `${await this.firstAvailableDate.getAttribute("id")}`
});
// 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.apptDuration = (await this.appointmentDuration.innerText()).replace("Duration: ", "");
await this.nextPage();
serviceLocation === AppointmentType.DropOff ? await this.dropOffButton.click() : await this.firstAvailableTime.click();
const apptDate = `${await this.dateText.allInnerTexts()}`
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;
}
@step("SchedulePage >> Schedule appointment: ")
async handleSchedulePage(testData: Partial<ITestData>) {
const { customerDetails } = testData;
await this.scheduleFirstAppointment(customerDetails!);
}
}
}

View file

@ -4,8 +4,6 @@ import { IAppointmentDetails } from '@business-logic/types/CustomerDetails';
import { 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;
@ -121,9 +119,6 @@ export class ServiceLocationPage extends BasePage {
await this.mobileButton.click();
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 {
@ -140,8 +135,7 @@ export class ServiceLocationPage extends BasePage {
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.clickWithRetry(this.firstAppointmentButton, this.page);
await this.firstAppointmentButton.scrollIntoViewIfNeeded().then(async () => {
await this.firstAppointmentButton.click();
if (appointmentDetails) {
@ -156,11 +150,4 @@ export class ServiceLocationPage extends BasePage {
await expect(this.RecalWarningMessage2).toBeVisible();
}
@step("ServiceLocationPage >> Select service location: ")
async handleServiceLocationPage(testData: Partial<ITestData>) {
const { appointmentDetails } = testData;
await this.selectLocation(appointmentDetails!);
await this.nextPage();
}
}

View file

@ -2,8 +2,6 @@ import { expect, type Locator, type Page } from '@playwright/test';
import { BasePage } from './BasePage';
import { ServicePackage, VehicleDamage } from '@business-logic/types/Enums';
import { PaymentMethod } from '@business-logic/types/Enums';
import { step } from '@business-logic/types/Step';
import { ITestData } from '@business-logic/types/ITestData';
export class ServicePackagesPage extends BasePage {
readonly page: Page;
@ -180,55 +178,4 @@ export class ServicePackagesPage extends BasePage {
throw new Error("No glass parts found in the order");
}
}
@step("ServicePackagePage >> Select Payment Method and Service Type: ")
async handleServicePackagePage(testData: Partial<ITestData>) {
const { customerDetails, paymentMethod, servicePackage, promoCode, canNotRecal, dynamicRecal, hasOemEndorsement, vehicleDamage } = testData;
// Define repair damage types (vs. replacement types)
const repairTypes: VehicleDamage[] = [
VehicleDamage.WindshieldOneChip,
VehicleDamage.WindshieldTwoChips,
VehicleDamage.WindshieldThreeChips
];
// Determine if we're replacing or repairing
const isReplace = !repairTypes.some(damageType => {
return vehicleDamage!.includes(damageType);
});
await this.handleQuotePopup(customerDetails!.email!);
await this.selectPaymentMethod(paymentMethod!);
await this.selectServicePackage(servicePackage!);
// Enter promo code
if (promoCode) {
await this.enterPromo(promoCode);
}
// Backend Validations
// Validate backend for can not recal if applicable
if (canNotRecal) {
await this.verifyCanNotRecal();
}
// Validate backend for dynamic recal if applicable
if (dynamicRecal) {
await this.verifyDynamicRecal();
}
// Validate backend for repair info (including chip verification)
await this.verifyIsRepair(!isReplace, vehicleDamage!);
if (isReplace) {
// Validate backend for parts info
await this.verifyVehicleParts(vehicleDamage!);
}
// Validate backend for OEM endorsement
if (hasOemEndorsement) {
await this.verifyOEMPart();
}
await this.nextPage();
}
}

View file

@ -1,20 +0,0 @@
import { Page } from "@playwright/test";
import { LookupPage } from "./LookupPage";
import { step } from "@business-logic/types/Step";
import { ITestData } from "@business-logic/types/ITestData";
export class ServiceZipPage extends LookupPage {
url = process.env['BASE_URL']! + '/fmg/?fmgPage=service-zip';
constructor(page: Page) {
super(page);
}
@step("ZipLookupPage >> Lookup by service ZIP: ")
async handleServiceZipPage(testData: Partial<ITestData>) {
const { customerDetails, vehicleDetails, alertFlags } = testData;
await this.enterZip(customerDetails!.address.postalCode!);
await this.handleZipValidation(customerDetails!.address.postalCode!, vehicleDetails!.vehicleLookupType!, alertFlags!);
}
}

View file

@ -2,8 +2,6 @@ import { type Locator, type Page, expect, test } from '@playwright/test';
import { BasePage } from './BasePage';
import { SideDoorDamage, VehicleDamage, WindshieldDamage } from '@business-logic/types/Enums';
import TestSuccessAlert from '@business-logic/types/TestSuccessAlert';
import { step } from '@business-logic/types/Step';
import { ITestData } from '@business-logic/types/ITestData';
export class VehicleDamagePage extends BasePage {
readonly page: Page;
@ -163,22 +161,4 @@ export class VehicleDamagePage extends BasePage {
console.log(`Alert encountered: ${alertMessage}`);
expect(alertMessage).toContain("Service not availableWe're sorry, but we currently offer only repair service for your vehicle type. Need help with next steps? Call us at800-394-0288.")
}
@step('VehicleDamagePage >> Select Damage')
async handleVehicleDamagePage(testData: Partial<ITestData>): Promise<void> {
const {vehicleDamage} = testData;
const {isRepairReplace, isRepairOnly} = testData.alertFlags || {};
await this.selectDamage(vehicleDamage!);
// Handle alert conditions for vehicle damage
if (isRepairReplace) {
await this.checkForBothRepairReplaceAlertMessage();
throw new TestSuccessAlert('Both assertions are met successfully.');
}
if (isRepairOnly) {
await this.checkForRepairOnlyAlertMessage();
throw new TestSuccessAlert('Both assertions are met successfully.');
}
await this.nextPage();
}
}

View file

@ -3,8 +3,6 @@ import { LookupPage } from './LookupPage';
import { AddressForm } from './forms/AddressForm';
import { VehicleSelectionForm } from './forms/VehicleSelectionForm';
import { ICustomerDetails, IVehicleDetails } from '@business-logic/types/CustomerDetails';
import { step } from '@business-logic/types/Step';
import { ITestData } from '@business-logic/types/ITestData';
export class VehicleLookupAddressPage extends LookupPage {
readonly addressForm: AddressForm;
@ -27,11 +25,4 @@ export class VehicleLookupAddressPage extends LookupPage {
//await this.nextPage();
//await this.vehicleSelectionForm.selectVehicle(vehicleDetails);
}
@step("VehicleLookupAddressPage >> Lookup by address: ")
async handleVehicleLookupAddressPage(testData: Partial<ITestData>) {
const { customerDetails, vehicleDetails, alertFlags } = testData;
await this.lookupVehicleByAddress(customerDetails!, vehicleDetails!);
await this.handleZipValidation(customerDetails!.address.postalCode!, vehicleDetails!.vehicleLookupType!, alertFlags!);
}
}

View file

@ -1,8 +1,6 @@
import { type Locator, type Page } from '@playwright/test';
import { LookupPage } from './LookupPage';
import { IVehicleDetails } from '@business-logic/types/CustomerDetails';
import { step } from '@business-logic/types/Step';
import { ITestData } from '@business-logic/types/ITestData';
export class VehicleLookupLicensePage extends LookupPage {
readonly licensePlateNumTextBox: Locator;
@ -26,12 +24,4 @@ export class VehicleLookupLicensePage extends LookupPage {
async enterPlateDetails(vehicleDetails: IVehicleDetails) {
await this.licensePlateNumTextBox.fill(vehicleDetails.licensePlateNumber || '');
}
@step("VehicleLookupLicensePage >> Lookup by license plate: ")
async handleVehicleLookupLicensePage(testData: Partial<ITestData>) {
const { customerDetails, vehicleDetails, alertFlags } = testData;
await this.enterPlateDetails(vehicleDetails!);
await this.enterZip(customerDetails!.address.postalCode!);
await this.handleZipValidation(customerDetails!.address.postalCode!, vehicleDetails!.vehicleLookupType!, alertFlags!);
}
}

View file

@ -1,7 +1,5 @@
import { Page } from "@playwright/test";
import { PartQuestionsPage } from "./PartQuestionPage";
import { step } from "@business-logic/types/Step";
import { ITestData } from "@business-logic/types/ITestData";
export default class VehiclePartQuestionsPage extends PartQuestionsPage{
url = process.env['BASE_URL']! + '/fmg/?fmgPage=vehicle-parts';
@ -9,12 +7,4 @@ export default class VehiclePartQuestionsPage extends PartQuestionsPage{
constructor(page: Page) {
super(page);
}
@step("VehiclePartsPage >> Select Vehicle Part Questions: ")
async handleVehiclePartsPage(testCase: Partial<ITestData>) {
const { vehiclePartQuestions } = testCase;
await this.validatePartQuestions(vehiclePartQuestions!);
await this.selectPartQuestionResponses(vehiclePartQuestions!);
await this.nextPage();
}
}

View file

@ -2,8 +2,6 @@ import { type Locator, type Page, expect, test } from '@playwright/test';
import { BasePage } from './BasePage';
import { IVehicleDetails } from '@business-logic/types/CustomerDetails';
import TestSuccessAlert from '@business-logic/types/TestSuccessAlert';
import { step } from '@business-logic/types/Step';
import { ITestData } from '@business-logic/types/ITestData';
export class VehicleSelectionPage extends BasePage {
readonly page: Page;
@ -44,20 +42,4 @@ export class VehicleSelectionPage extends BasePage {
await console.log(`Alert encountered: ${alertMessage}`);
await expect(alertMessage).toContain('Service not available in your areaWe do not offer glass service for your vehicle in your ZIP code. We apologize for the inconvenience.');
}
@step("VehicleSelectionPage >> Select Vehicle: ")
async handleVehicleSelectionPage(testData: Partial<ITestData>) {
const { vehicleDetails } = testData;
const { isHeavyTruckVehicle, isSplitWindshield } = testData.alertFlags || {};
await this.selectVehicle(vehicleDetails!);
// Handle alert conditions for vehicle selection
if (isHeavyTruckVehicle || isSplitWindshield) {
await this.checkForAlertMessages();
throw new TestSuccessAlert('Both assertions are met successfully.');
}
await this.nextPage();
}
}

View file

@ -1,8 +1,6 @@
import { expect, type Locator, type Page } from '@playwright/test';
import { IClaimDetails, ICustomerDetails } from '@business-logic/types/CustomerDetails';
import { InsuranceBasePage } from './InsuranceBasePage';
import { step } from '@business-logic/types/Step';
import { ITestData } from '@business-logic/types/ITestData';
export class VerifyDetailsPage extends InsuranceBasePage {
readonly page: Page;
@ -76,11 +74,4 @@ export class VerifyDetailsPage extends InsuranceBasePage {
// Return the original string if format is unknown
return date;
}
@step("VerifyDetailsPage >> Verify policy details: ")
async handleVerifyDetailsPage(testData: Partial<ITestData>) {
const { customerDetails, claimDetails } = testData;
await this.verifyPolicyDetails(customerDetails!, claimDetails!);
await this.nextPage();
}
}

View file

@ -1,7 +1,5 @@
import { type Locator, type Page } from '@playwright/test';
import { LookupPage } from './LookupPage';
import { step } from '@business-logic/types/Step';
import { ITestData } from '@business-logic/types/ITestData';
export class VinLookupPage extends LookupPage {
readonly vinLookupTextBox: Locator;
@ -22,12 +20,4 @@ export class VinLookupPage extends LookupPage {
async enterVin(vin: string) {
await this.vinLookupTextBox.fill(vin);
}
@step("VinLookupPage >> Lookup by VIN: ")
async handleVehicleLookupVinPage(testData: Partial<ITestData>) {
const { customerDetails, vehicleDetails, alertFlags } = testData;
await this.enterVin(vehicleDetails!.vin!);
await this.enterZip(customerDetails!.address.postalCode!);
await this.handleZipValidation(customerDetails!.address.postalCode!, vehicleDetails!.vehicleLookupType!, alertFlags!);
}
}

View file

@ -156,11 +156,35 @@ async function runWorkflow(page: Page, testCase: TestCase) {
// Destructure test data for easier access
const {
paymentMethod, customerDetails, vehicleDetails, vehicleDamage,
paymentDetails, partQuestions, enterFunnelWithZip, capabilityQuestions,
vehiclePartQuestions, moldingQuestions, skipEstimatePage
servicePackage, paymentMethod, customerDetails, vehicleDetails, vehicleDamage,
appointmentDetails, paymentDetails, claimDetails, partQuestions, enterFunnelWithZip,
capabilityQuestions, vehiclePartQuestions, moldingQuestions, isPolicyFound,
otherVehiclesOnPolicy, isUseVehicleOnPolicy, isDuplicateClaim, isRecalNotification,
alertFlags, endorsements, isPolicyDriver, skipEstimatePage, isRecalVehicle, canNotRecal,
dynamicRecal, hasOemEndorsement, promoCode
} = testCase.testData;
// Destructure alert flag data
const {
isHeavyTruckVehicle, isRepairReplace, isSplitWindshield, isRepairOnly,
isUnserviceableZip, isInvalidZip, isVinNotFound
} = testCase.testData.alertFlags || {};
// Define repair damage types (vs. replacement types)
const repairTypes: VehicleDamage[] = [
VehicleDamage.WindshieldOneChip,
VehicleDamage.WindshieldTwoChips,
VehicleDamage.WindshieldThreeChips
];
// Determine if we're replacing or repairing
const isReplace = !repairTypes.some(damageType => {
return vehicleDamage!.includes(damageType);
});
// Check if the insurance policy has endorsements
const hasEndorsements = endorsements && endorsements.length > 0;
// Check if the vehicle damage includes a windshield crack
const hasWindshieldCrack = vehicleDamage!.some(damage =>
damage === VehicleDamage.WindshieldCrack
@ -187,166 +211,414 @@ async function runWorkflow(page: Page, testCase: TestCase) {
console.log(`Customer for this test: ${customerDetails?.firstName} ${customerDetails?.lastName}`);
}
// Handle vehicle selection page
let vehicleSelectionPage = testCase.pages.vehicleSelectionPage;
await vehicleSelectionPage.handleVehicleSelectionPage(testCase.testData);
// Handle vehicle damage page
let vehicleDamagePage = testCase.pages.vehicleDamagePage;
await vehicleDamagePage.handleVehicleDamagePage(testCase.testData);
await test.step('VehicleSelectionPage >> Select Vehicle', async () => {
let vehicleSelectionPage = testCase.pages.vehicleSelectionPage;
await vehicleSelectionPage.selectVehicle(vehicleDetails!);
// Handle alert conditions for vehicle selection
if (isHeavyTruckVehicle || isSplitWindshield) {
await vehicleSelectionPage.checkForAlertMessages();
throw new TestSuccessAlert('Both assertions are met successfully.');
}
await vehicleSelectionPage.nextPage();
});
await test.step('VehicleDamagePage >> Select Damage', async () => {
let vehicleDamagePage = testCase.pages.vehicleDamagePage;
await vehicleDamagePage.selectDamage(vehicleDamage!);
// Handle alert conditions for vehicle damage
if (isRepairReplace) {
await vehicleDamagePage.checkForBothRepairReplaceAlertMessage();
throw new TestSuccessAlert('Both assertions are met successfully.');
}
if (isRepairOnly) {
await vehicleDamagePage.checkForRepairOnlyAlertMessage();
throw new TestSuccessAlert('Both assertions are met successfully.');
}
await vehicleDamagePage.nextPage();
});
// If the vehicle has a windshield crack as part of its damage, go to estimate page and select lookup type
if (hasWindshieldCrack && !skipEstimatePage) {
let estimatePage = testCase.pages.estimatePage;
await estimatePage.handleEstimatePage(testCase.testData);
await test.step('EstimatePage >> Select Lookup Type', async () => {
let estimatePage = testCase.pages.estimatePage;
await estimatePage.vehicleLookup(vehicleDetails!);
});
// Handle different vehicle lookup methods
switch (vehicleDetails!.vehicleLookupType!) {
case VehicleLookupType.Address:
let vehicleLookupAddressPage = testCase.pages.vehicleLookupAddressPage;
await vehicleLookupAddressPage.handleVehicleLookupAddressPage(testCase.testData);
await test.step('VehicleLookupAddressPage >> Lookup by address: ' + customerDetails!.address.street, async () => {
let vehicleLookupAddressPage = testCase.pages.vehicleLookupAddressPage;
await vehicleLookupAddressPage.lookupVehicleByAddress(customerDetails!, vehicleDetails!);
await vehicleLookupAddressPage.handleZipValidation(customerDetails!.address.postalCode!, vehicleDetails!.vehicleLookupType!, alertFlags!);
});
break;
case VehicleLookupType.LicensePlateNumber:
let vehicleLookupLicensePage = testCase.pages.vehicleLookupLicensePage;
await vehicleLookupLicensePage.handleVehicleLookupLicensePage(testCase.testData);
await test.step('VehicleLookupLicensePage >> Lookup by license plate: ' + vehicleDetails!.licensePlateNumber, async () => {
let vehicleLookupLicensePage = testCase.pages.vehicleLookupLicensePage;
await vehicleLookupLicensePage.enterPlateDetails(vehicleDetails!);
await vehicleLookupLicensePage.enterZip(customerDetails!.address.postalCode!);
await vehicleLookupLicensePage.handleZipValidation(customerDetails!.address.postalCode!, vehicleDetails!.vehicleLookupType!, alertFlags!);
});
break;
case VehicleLookupType.Vin:
let vinLookupPage = testCase.pages.vinLookupPage;
await vinLookupPage.handleVehicleLookupVinPage(testCase.testData);
await test.step('VinLookupPage >> Lookup by VIN: ' + vehicleDetails!.vin!, async () => {
let vinLookupPage = testCase.pages.vinLookupPage;
await vinLookupPage.enterVin(vehicleDetails!.vin!);
await vinLookupPage.enterZip(customerDetails!.address.postalCode!);
await vinLookupPage.handleZipValidation(customerDetails!.address.postalCode!, vehicleDetails!.vehicleLookupType!, alertFlags!);
});
break;
case VehicleLookupType.Zip:
let serviceZipPage = testCase.pages.serviceZipPage;
await serviceZipPage.handleServiceZipPage(testCase.testData);
break;
await test.step('ZipLookupPage >> Lookup by service ZIP: ' + customerDetails!.address.postalCode!, async () => {
let zipLookupPage = testCase.pages.zipLookupPage;
let vinLookupPage = testCase.pages.vinLookupPage;
await vinLookupPage.enterZip(customerDetails!.address.postalCode!);
await zipLookupPage.handleZipValidation(customerDetails!.address.postalCode!, vehicleDetails!.vehicleLookupType!, alertFlags!);
});
}
} else {
// Otherwise just use zip lookup for service zip page
let serviceZipPage = testCase.pages.serviceZipPage;
await serviceZipPage.handleServiceZipPage(testCase.testData);
// Otherwise just use zip lookup
await test.step('ZipLookupPage >> Lookup by service ZIP: ' + customerDetails!.address.postalCode!, async () => {
let zipLookupPage = testCase.pages.zipLookupPage;
let vinLookupPage = testCase.pages.vinLookupPage;
await vinLookupPage.enterZip(customerDetails!.address.postalCode!);
await zipLookupPage.handleZipValidation(customerDetails!.address.postalCode!, vehicleDetails!.vehicleLookupType!, alertFlags!);
});
}
// Handle part questions if applicable
if (partQuestions && partQuestions.length > 0) {
let partQuestionsPage = testCase.pages.partQuestionsPage;
await partQuestionsPage.handlePartQuestionsPage(testCase.testData);
await test.step('PartQuestionsPage >> Select Vehicle Part Question Responses', async () => {
let partQuestionsPage = testCase.pages.partQuestionsPage;
await partQuestionsPage.validatePartQuestions(partQuestions);
await partQuestionsPage.selectPartQuestionResponses(partQuestions);
await partQuestionsPage.nextPage();
});
}
// Handle molding questions if applicable
if (moldingQuestions && moldingQuestions.length > 0) {
let moldingQuestionsPage = testCase.pages.moldingQuestionsPage;
await moldingQuestionsPage.handleMoldingQuestionsPage(testCase.testData);
await test.step('MoldingQuestionsPage >> Select Molding Question Responses', async () => {
let moldingQuestionsPage = testCase.pages.moldingQuestionsPage;
await moldingQuestionsPage.validatePartQuestions(moldingQuestions);
await moldingQuestionsPage.selectPartQuestionResponses(moldingQuestions);
await moldingQuestionsPage.nextPage();
});
}
// Handle vehicle part questions if applicable
if (vehiclePartQuestions && vehiclePartQuestions.length > 0) {
let vehiclePartsPage = testCase.pages.vehiclePartsPage;
await vehiclePartsPage.handleVehiclePartsPage(testCase.testData);
await test.step('VehiclePartsPage >> Select Vehicle Part Responses', async () => {
let vehiclePartsPage = testCase.pages.vehiclePartsPage;
await vehiclePartsPage.validatePartQuestions(vehiclePartQuestions);
await vehiclePartsPage.selectPartQuestionResponses(vehiclePartQuestions);
await vehiclePartsPage.nextPage();
});
}
// Handle capability questions if applicable
if (capabilityQuestions && capabilityQuestions.length > 0) {
let capabilityQuestionsPage = testCase.pages.capabilityQuestionsPage;
await capabilityQuestionsPage.handleCapabilityQuestionsPage(testCase.testData);
await test.step('CapabilityQuestionsPage >> Select Capability Question Responses', async () => {
let capabilityQuestionsPage = testCase.pages.capabilityQuestionsPage;
await capabilityQuestionsPage.validatePartQuestions(capabilityQuestions);
await capabilityQuestionsPage.selectPartQuestionResponses(capabilityQuestions);
await capabilityQuestionsPage.nextPage();
});
}
// Select service package and payment method
let servicePackagesPage = testCase.pages.servicePackagesPage;
await servicePackagesPage.handleServicePackagePage(testCase.testData);
await test.step('ServicePackagePage >> Select Payment Method and Service Type', async() => {
let servicePackagePage = testCase.pages.servicePackagePage;
await servicePackagePage.handleQuotePopup(customerDetails!.email!);
await servicePackagePage.selectPaymentMethod(paymentMethod!);
await servicePackagePage.selectServicePackage(servicePackage!);
// Enter promo code
if (promoCode) {
await servicePackagePage.enterPromo(promoCode);
}
// Backend Validations
// Validate backend for can not recal if applicable
if (canNotRecal) {
await servicePackagePage.verifyCanNotRecal();
}
// Validate backend for dynamic recal if applicable
if (dynamicRecal) {
await servicePackagePage.verifyDynamicRecal();
}
// Validate backend for repair info (including chip verification)
await servicePackagePage.verifyIsRepair(!isReplace, vehicleDamage!);
if (isReplace) {
// Validate backend for parts info
await servicePackagePage.verifyVehicleParts(vehicleDamage!);
}
// Validate backend for OEM endorsement
if (hasOemEndorsement) {
await servicePackagePage.verifyOEMPart();
}
await servicePackagePage.nextPage();
});
//============================= INSURANCE FLOW =============================`
// Insurance flow - if user selected Insurance as Payment Method
if (paymentMethod == PaymentMethod.Insurance) {
await handleInsuranceFlow(testCase);
await test.step('InsuranceCoveragePage >> Select your insurance', async() => {
let insuranceCompanyPage = testCase.pages.insuranceCompanyPage;
await insuranceCompanyPage.enterInsuranceCompany(claimDetails!.client!);
await insuranceCompanyPage.nextPage();
});
await test.step('CCPolicyInfoPage >> Fill out claim information', async() => {
let ccPolicyInfoPage = testCase.pages.ccPolicyInfoPage;
await ccPolicyInfoPage.populatePage(customerDetails!, claimDetails!, await ccPolicyInfoPage.hasCityInfo());
await ccPolicyInfoPage.nextPage();
});
// Handle duplicate claim case if applicable
if (isDuplicateClaim) {
await test.step('DuplicateCheckPage >> Start New Claim', async () => {
let duplicateCheckPage = testCase.pages.duplicateCheckPage;
await duplicateCheckPage.startNewClaim();
await duplicateCheckPage.nextPage();
});
}
// Handle policy found vs. not found flows
if (isPolicyFound) {
await test.step('PolicyVehiclesPage >> Select vehicle', async () => {
let policyVehiclesPage = testCase.pages.policyVehiclesPage;
let vehicleSelectionPage = testCase.pages.vehicleSelectionPage;
// Validate other vehicles on policy
if (otherVehiclesOnPolicy && otherVehiclesOnPolicy.length > 0) {
for (const vehicle of otherVehiclesOnPolicy) {
await policyVehiclesPage.validateVehicleIsOnPolicy(vehicle);
}
}
// If vehicle is not on the policy, select new vehicle
if (!(isUseVehicleOnPolicy ?? true)) {
await policyVehiclesPage.selectVehicleNotListed();
await policyVehiclesPage.nextPage();
await vehicleSelectionPage.selectVehicle(vehicleDetails!);
await policyVehiclesPage.nextPage();
} else {
// Otherwise, select the vehicle entered in Safelite.com
await policyVehiclesPage.selectVehicle(vehicleDetails!);
await policyVehiclesPage.nextPage();
}
});
// Handle policy driver selection if applicable
if (isPolicyDriver) {
await test.step('PolicyDriverPage >> Confirm Driver at time of damage', async () => {
let policyDriverPage = testCase.pages.policyDriverPage;
await policyDriverPage.selectPolicyDriver(customerDetails!);
await policyDriverPage.nextPage();
});
}
// Handle endorsements if applicable
if (hasEndorsements) {
await test.step('EndorsementsPage >> Select Endorsements', async () => {
let endorsementsPage = testCase.pages.endorsementsPage;
await endorsementsPage.verifyEndorsements(endorsements);
await endorsementsPage.selectEndorsements(endorsements);
await endorsementsPage.nextPage();
});
}
} else {
// Policy not found flow
await test.step('VerifyDetailsPage >> Verify Details', async () => {
let verifyDetailsPage = testCase.pages.verifyDetailsPage;
await verifyDetailsPage.verifyPolicyDetails(customerDetails!, claimDetails!);
await verifyDetailsPage.nextPage();
});
}
// Continue with the insurance flow after policy information
await test.step('PolicyInfoSubmittedPage >> Continue With Safelite Autoglass', async () => {
let policyInfoSubmittedPage = testCase.pages.policyInfoSubmittedPage;
await policyInfoSubmittedPage.verifyPolicyInfoSubmitted();
await policyInfoSubmittedPage.nextPage();
});
// Handle recalibration notification if applicable
if (isRecalNotification) {
await test.step('RecallibrationInfoPage >> Continue With Recalibration Information', async () => {
let recalibrationInfoPage = testCase.pages.recalibrationInfoPage;
await recalibrationInfoPage.nextPage();
});
}
// Continue to coverage statement
await test.step('CoverageStatementPage >> Next page', async () => {
let coverageStatementPage = testCase.pages.coverageStatementPage;
await coverageStatementPage.validateDeductibleAmount(claimDetails!);
await coverageStatementPage.nextPage();
});
}
//============================= SERVICE SCHEDULING =============================
// Select service location
let serviceLocationPage = testCase.pages.serviceLocationPage;
await serviceLocationPage.handleServiceLocationPage(testCase.testData);
await test.step('ServiceLocationPage >> Select service location', async () => {
let serviceLocationPage = testCase.pages.serviceLocationPage;
await serviceLocationPage.selectLocation(appointmentDetails!);
await serviceLocationPage.nextPage();
});
// Schedule appointment
let schedulePage = testCase.pages.schedulePage;
await schedulePage.handleSchedulePage(testCase.testData);
await test.step('SchedulePage >> Select day and time', async () => {
let schedulePage = testCase.pages.schedulePage;
customerDetails!.apptDate! = await schedulePage.scheduleFirstAppointment(appointmentDetails!.serviceLocation);
});
// Enter contact details
let contactDetailsPage = testCase.pages.contactDetailsPage;
await contactDetailsPage.handleContactDetailsPage(testCase.testData);
await test.step('ContactDetailsPage >> Enter contact details', async () => {
let contactDetailsPage = testCase.pages.contactDetailsPage;
await contactDetailsPage.enterContactDetails(customerDetails!);
await contactDetailsPage.nextPage();
});
//============================= PAYMENT PROCESSING =============================
// Handle payment
let paymentMethodPage = testCase.pages.paymentMethodPage;
await paymentMethodPage.handlePaymentMethodPage(testCase.testData);
await test.step('PaymentMethodPage >> Execute Payment', async () => {
let paymentMethodPage = testCase.pages.paymentMethodPage;
await paymentMethodPage.validatePaymentDetailsPage(testCase.testData);
// Verify VAPS wipers on backend for standard and premium packages
if (servicePackage === ServicePackage.Standard || servicePackage === ServicePackage.Premium) {
await paymentMethodPage.verifyVAPS();
}
if (paymentDetails?.paymentType) {
await paymentMethodPage.executePayment(paymentDetails!, isRecalVehicle!);
} else {
await paymentMethodPage.nextPage();
}
});
// If user selected Pay with Insurance as Payment Method, Enter Insurance Flow
if (paymentDetails?.paymentType === PaymentType.PayWithInsurance) {
await handleInsuranceFlow(testCase);
await test.step('InsuranceCoveragePage >> Select your insurance', async() => {
let insuranceCompanyPage = testCase.pages.insuranceCompanyPage;
await insuranceCompanyPage.enterInsuranceCompany(claimDetails!.client!);
await insuranceCompanyPage.nextPage();
});
await test.step('CCPolicyInfoPage >> Fill out claim information', async() => {
const ccPolicyInfoPage = testCase.pages.ccPolicyInfoPage;
await ccPolicyInfoPage.populatePage(customerDetails!, claimDetails!, await ccPolicyInfoPage.hasCityInfo());
await ccPolicyInfoPage.nextPage();
});
// Handle duplicate claim case if applicable
if (isDuplicateClaim) {
await test.step('DuplicateCheckPage >> Start New Claim', async () => {
const duplicateCheckPage = testCase.pages.duplicateCheckPage;
await duplicateCheckPage.startNewClaim();
await duplicateCheckPage.nextPage();
});
}
// Handle policy found vs. not found flows
if (isPolicyFound) {
await test.step('PolicyVehiclesPage >> Select vehicle', async () => {
const policyVehiclesPage = testCase.pages.policyVehiclesPage;
const vehicleSelectionPage = testCase.pages.vehicleSelectionPage;
// Validate other vehicles on policy
if (otherVehiclesOnPolicy && otherVehiclesOnPolicy.length > 0) {
for (const vehicle of otherVehiclesOnPolicy) {
await policyVehiclesPage.validateVehicleIsOnPolicy(vehicle);
}
}
// If vehicle is not on the policy, select new vehicle
if (!(isUseVehicleOnPolicy ?? true)) {
await policyVehiclesPage.selectVehicleNotListed();
await policyVehiclesPage.nextPage();
await vehicleSelectionPage.selectVehicle(vehicleDetails!);
await policyVehiclesPage.nextPage();
} else {
// Otherwise, select the vehicle entered in Safelite.com
await policyVehiclesPage.selectVehicle(vehicleDetails!);
await policyVehiclesPage.nextPage();
}
});
// Handle policy driver selection if applicable
if (isPolicyDriver) {
await test.step('PolicyDriverPage >> Confirm Driver at time of damage', async () => {
const policyDriverPage = testCase.pages.policyDriverPage;
await policyDriverPage.selectPolicyDriver(customerDetails!);
await policyDriverPage.nextPage();
});
}
// Handle endorsements if applicable
if (hasEndorsements) {
await test.step('EndorsementsPage >> Select Endorsements', async () => {
const endorsementsPage = testCase.pages.endorsementsPage;
await endorsementsPage.verifyEndorsements(endorsements);
await endorsementsPage.selectEndorsements(endorsements);
await endorsementsPage.nextPage();
});
}
} else {
// Policy not found flow
await test.step('VerifyDetailsPage >> Verify Details', async () => {
const verifyDetailsPage = testCase.pages.verifyDetailsPage;
await verifyDetailsPage.verifyPolicyDetails(customerDetails!, claimDetails!);
await verifyDetailsPage.nextPage();
});
}
// Continue with the insurance flow after policy information
await test.step('PolicyInfoSubmittedPage >> Continue With Safelite Autoglass', async () => {
const policyInfoSubmittedPage = testCase.pages.policyInfoSubmittedPage;
await policyInfoSubmittedPage.verifyPolicyInfoSubmitted();
await policyInfoSubmittedPage.nextPage();
});
// Handle recalibration notification if applicable
if (isRecalNotification) {
await test.step('RecallibrationInfoPage >> Continue With Recalibration Information', async () => {
const recalibrationInfoPage = testCase.pages.recalibrationInfoPage;
await recalibrationInfoPage.nextPage();
});
}
// Continue to coverage statement
await test.step('CoverageStatementPage >> Next page', async () => {
const coverageStatementPage = testCase.pages.coverageStatementPage;
await coverageStatementPage.validateDeductibleAmount(claimDetails!);
await coverageStatementPage.nextPage();
});
}
//============================= ORDER CONFIRMATION =============================
// Validate order confirmation
let orderConfirmationPage = testCase.pages.orderConfirmationPage;
await orderConfirmationPage.verifyOrderConfirmationPage(testCase.testData);
}
await test.step('OrderConfirmationPage >> Validate order', async () => {
let orderConfirmationPage = testCase.pages.orderConfirmationPage;
await orderConfirmationPage.validateOrderConfirmationPage(testCase.testData);
});
export async function handleInsuranceFlow(testCase: TestCase) {
const { isPolicyFound, isPolicyDriver, endorsements, isRecalNotification } = testCase.testData;
// Check if the insurance policy has endorsements
const hasEndorsements = endorsements && endorsements.length > 0;
// Handle insurance company page
let insuranceCompanyPage = testCase.pages.insuranceCompanyPage;
await insuranceCompanyPage.handleInsuranceCompanyPage(testCase.testData);
// Handle ccPolicyInfoPage
let ccPolicyInfoPage = testCase.pages.ccPolicyInfoPage;
await ccPolicyInfoPage.handleCCPolicyInfoPage(testCase.testData);
let duplicateCheckPage = testCase.pages.duplicateCheckPage;
if (duplicateCheckPage.page.url().includes('DuplicateCheck.aspx')) {
await duplicateCheckPage.handleDuplicateCheckPage(testCase.testData);
}
if (isPolicyFound) {
let policyVehiclesPage = testCase.pages.policyVehiclesPage;
await policyVehiclesPage.handlePolicyVehiclesPage(testCase.testData);
// Handle policy driver selection if applicable
if (isPolicyDriver) {
let policyDriverPage = testCase.pages.policyDriverPage;
await policyDriverPage.handlePolicyDriverPage(testCase.testData);
}
// Handle endorsements if applicable
if (hasEndorsements) {
let endorsementsPage = testCase.pages.endorsementsPage;
await endorsementsPage.handleEndorsementsPage(testCase.testData);
}
}else {
//Handle verify details page
let verifyDetailsPage = testCase.pages.verifyDetailsPage;
await verifyDetailsPage.handleVerifyDetailsPage(testCase.testData);
}
// Handle Policy info submitted page
let policyInfoSubmittedPage = testCase.pages.policyInfoSubmittedPage;
await policyInfoSubmittedPage.handlePolicyInfoSubmittedPage();
if(isRecalNotification)
{
let recalibrationInfoPage = testCase.pages.recalibrationInfoPage;
await recalibrationInfoPage.handleRecalibrationInfoPage();
}
//handle coveraage statement page
let coverageStatementPage = testCase.pages.coverageStatementPage;
await coverageStatementPage.handleCoverageStatementPage(testCase.testData);
// Get the order number and wrap it in a test step
const workOrderNumber = await testCase.pages.orderConfirmationPage.logOrderNumber();
await test.step(`Session Storage Work Order Number: ${workOrderNumber}`, async () => {
console.log(`Session Storage Work Order Number: ${workOrderNumber}`);
});
}

View file

@ -28,7 +28,7 @@ const cashRepairMobileCCData : Partial<ITestData> = {
serviceAddress: {
street: '13735 San Antonio Ave',
city: 'Chino',
state: 'CA',
state: 'California',
postalCode: '91710',
country: 'United States'
}

View file

@ -39,7 +39,7 @@ const cashReplaceDynamicRecalMobileData: Partial<ITestData> = {
// Use street address from current faker seed
street: getDefaultTestData().customerDetails!.address.street,
city: 'Rosedale',
state: 'MD',
state: 'Maryland',
postalCode: '21237',
country: 'United States'
},

View file

@ -35,7 +35,7 @@ const cashReplaceMultiGlassMobileData: Partial<ITestData> = {
// Use street address from current faker seed
street: getDefaultTestData().customerDetails!.address.street,
city: 'Rosedale',
state: 'MD',
state: 'Maryland',
postalCode: '21237',
country: 'United States'
},

View file

@ -48,7 +48,7 @@ const cashReplaceSafeliteCanNotRecalMobileData: Partial<ITestData> = {
// Use street address from current faker seed
street: getDefaultTestData().customerDetails!.address.street,
city: 'Rosedale',
state: 'MD',
state: 'Maryland',
postalCode: '21237',
country: 'United States'
},

View file

@ -45,7 +45,7 @@ const cashReplaceVinMobileData: Partial<ITestData> = {
// Use street address from current faker seed
street: getDefaultTestData().customerDetails!.address.street,
city: 'Rosedale',
state: 'MD',
state: 'Maryland',
postalCode: '21237',
country: 'United States'
}