Updates with 631 changes
Improves the handling of cash to insurance flows, including adding new test cases and adjusting logic for policy verification and payment methods. Also, updates UI elements to ensure correct display of deductible information and handles split windshield scenarios. The `safelite-playwright-core` dependency is updated to version 1.0.22.
This commit is contained in:
commit
8da9b21539
25 changed files with 783 additions and 208 deletions
8
playwright-tests/package-lock.json
generated
8
playwright-tests/package-lock.json
generated
|
|
@ -23,7 +23,7 @@
|
|||
"luxon": "^3.6.1",
|
||||
"ortoni-report": "^3.0.2",
|
||||
"playwright-jira-reporter": "^1.0.4",
|
||||
"safelite-playwright-core": "^1.0.21",
|
||||
"safelite-playwright-core": "^1.0.22",
|
||||
"typescript": "^5.8.3"
|
||||
}
|
||||
},
|
||||
|
|
@ -3278,9 +3278,9 @@
|
|||
"peer": true
|
||||
},
|
||||
"node_modules/safelite-playwright-core": {
|
||||
"version": "1.0.21",
|
||||
"resolved": "https://pkgs.dev.azure.com/Safelite/Digital/_packaging/DigitalQA/npm/registry/safelite-playwright-core/-/safelite-playwright-core-1.0.21.tgz",
|
||||
"integrity": "sha1-qvCxkMa7MWLpUNHHNklAD3osv8U=",
|
||||
"version": "1.0.22",
|
||||
"resolved": "https://pkgs.dev.azure.com/Safelite/Digital/_packaging/DigitalQA/npm/registry/safelite-playwright-core/-/safelite-playwright-core-1.0.22.tgz",
|
||||
"integrity": "sha1-KIwwcw2+Uy3s9xV/9zhCyWfH/7Y=",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@
|
|||
"luxon": "^3.6.1",
|
||||
"ortoni-report": "^3.0.2",
|
||||
"playwright-jira-reporter": "^1.0.4",
|
||||
"safelite-playwright-core": "^1.0.21",
|
||||
"safelite-playwright-core": "^1.0.22",
|
||||
"typescript": "^5.8.3"
|
||||
},
|
||||
"private": "true"
|
||||
|
|
|
|||
|
|
@ -9,7 +9,8 @@ export class CoverageStatementPage extends InsuranceBasePage {
|
|||
readonly scheduleOnlineButton: Locator;
|
||||
readonly cancelMyClaimButton: Locator;
|
||||
readonly deductibleAmount: Locator;
|
||||
readonly verfiyingCoverageText: Locator;
|
||||
readonly verifyingCoverageText: Locator;
|
||||
readonly noCompText: Locator;
|
||||
readonly continueButton: Locator; // For ITAC/NoComp
|
||||
url = process.env['BASE_URL']! + '/FixMyGlass/CoverageStatement.aspx';
|
||||
|
||||
|
|
@ -19,7 +20,8 @@ export class CoverageStatementPage extends InsuranceBasePage {
|
|||
this.scheduleOnlineButton = this.page.getByText('Continue to schedule online');
|
||||
this.cancelMyClaimButton = this.page.getByText('Cancel my claim');
|
||||
this.deductibleAmount = this.page.getByRole('heading', { name: '$' }).locator('span');
|
||||
this.verfiyingCoverageText = this.page.getByRole('heading', { name: 'We’re verifying your coverage' });
|
||||
this.verifyingCoverageText = this.page.getByRole('heading', { name: 'We\'re verifying your coverage' });
|
||||
this.noCompText = this.page.getByRole('heading', { name: 'Your policy doesn\'t cover this service' });
|
||||
this.continueButton = page.getByRole('button', { name: 'Continue' });
|
||||
// this.validateURL(this.url);
|
||||
}
|
||||
|
|
@ -46,16 +48,20 @@ export class CoverageStatementPage extends InsuranceBasePage {
|
|||
"span.deductible-text-black[data-bind='text: deductibleFormatted']"
|
||||
);
|
||||
|
||||
const unverifiedDeductibleElement = this.verifyingCoverageText;
|
||||
|
||||
// Check if the locator is visible before running the expectation
|
||||
if (await deductibleElement.isVisible()) {
|
||||
// Check if the page contains the properly formatted deductible amount
|
||||
await expect(deductibleElement).toContainText(`$${expectedDeductibleRegex}`);
|
||||
}
|
||||
}
|
||||
|
||||
async validateUnverifiedText(){
|
||||
await expect(this.verfiyingCoverageText).toBeEnabled();
|
||||
if (await unverifiedDeductibleElement.isVisible() || await this.noCompText.isVisible()) {
|
||||
// Click on continue button if unverified header is visible
|
||||
await this.continueButton.click();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@step("CoverageStatementPage >> Next page: ")
|
||||
async handleCoverageStatementPage(testData: Partial<ITestData>) {
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ export class OrderConfirmationPage extends BasePage {
|
|||
this.apptDateText = this.page.locator('[class="scheduleText"]');
|
||||
this.amountDueText = this.page.getByLabel('expand cart');
|
||||
this.viewCartButton = this.page.locator('#cart-dropdown-head');
|
||||
this.deductibleText = this.page.locator('#deductible-value');
|
||||
this.deductibleText = this.page.locator('.deductible');
|
||||
this.subtotalText = this.page.locator('.sub-total');
|
||||
this.finalAmountDue = this.page.locator('div.amount-due');
|
||||
this.cartServicePackageText = this.cartServicePackageText = this.page.locator('.cart-panel');
|
||||
|
|
@ -45,8 +45,8 @@ export class OrderConfirmationPage extends BasePage {
|
|||
|
||||
async validateOrderConfirmationPage(testData: Partial<ITestData>) {
|
||||
// Destructure data we use
|
||||
const { vehicleDetails, customerDetails, servicePackage,
|
||||
paymentDetails, paymentMethod } = testData;
|
||||
const { vehicleDetails, customerDetails, servicePackage, promoCode, isCashInsuranceFlow,
|
||||
isPolicyFound, claimDetails, paymentDetails, isUseVehicleOnPolicy, paymentMethod, isPolicyUnverified } = 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()));
|
||||
|
|
@ -63,7 +63,7 @@ export class OrderConfirmationPage extends BasePage {
|
|||
const servicePackageAmt = Number.parseFloat(servicePackageValue!.split('$')[1].replaceAll(',', ''));
|
||||
|
||||
// General Validations
|
||||
expect.soft(emailTextValue).toContain(customerDetails!.email);
|
||||
expect.soft(emailTextValue?.toLowerCase()).toContain(customerDetails!.email);
|
||||
|
||||
// Service package validations
|
||||
await expect.soft(this.cartServicePackageText).toContainText(`${servicePackage}`)
|
||||
|
|
@ -89,43 +89,25 @@ export class OrderConfirmationPage extends BasePage {
|
|||
const finalAmountDueAmt = Number.parseFloat(finalAmountDueValue!.split('$')[1].replaceAll(',', ''));
|
||||
|
||||
|
||||
|
||||
expect.soft(subtotalAmt).toBeGreaterThan(0);
|
||||
// expect.soft(deductibleAmt).toEqual(0);
|
||||
|
||||
if (paymentDetails!.paymentType === PaymentType.PayAtService && (servicePackageAmt > 0)) {
|
||||
if ((paymentDetails!.paymentType === PaymentType.PayAtService || isCashInsuranceFlow) && (servicePackageAmt > 0)) {
|
||||
// Verify amount due > 0
|
||||
expect.soft(amountDueAmt).toBeGreaterThan(0);
|
||||
expect.soft(finalAmountDueAmt).toBeGreaterThan(0);
|
||||
|
||||
if (isPolicyUnverified && PaymentType.PayWithInsurance){
|
||||
expect.soft(finalAmountDueAmt).toContain('Verifying coverage')
|
||||
}
|
||||
} else {
|
||||
// Verify amount due 0
|
||||
expect.soft(amountDueAmt).toEqual(0);
|
||||
expect.soft(finalAmountDueAmt).toEqual(0);
|
||||
}
|
||||
} else {
|
||||
// Price validations for insurance users
|
||||
if (servicePackage === ServicePackage.GlassOnly) {
|
||||
expect.soft(servicePackageAmt).toEqual(0);
|
||||
} else {
|
||||
expect.soft(servicePackageAmt).toBeGreaterThan(0);
|
||||
}
|
||||
|
||||
// Check for either "Verifying coverage" or "0.00" in price fields
|
||||
expect.soft(
|
||||
amountDueValue?.includes('Verifying coverage') ||
|
||||
amountDueValue?.includes('0.00')
|
||||
).toBeTruthy();
|
||||
|
||||
expect.soft(
|
||||
subtotalTextValue?.includes('Verifying coverage') ||
|
||||
subtotalTextValue?.includes('0.00')
|
||||
).toBeTruthy();
|
||||
|
||||
expect.soft(
|
||||
finalAmountDueValue?.includes('Verifying coverage') ||
|
||||
finalAmountDueValue?.includes('0.00')
|
||||
).toBeTruthy();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async getFormattedAppointmentDate(appointmentDate: string) {
|
||||
|
||||
|
|
|
|||
|
|
@ -358,10 +358,12 @@ l
|
|||
}
|
||||
let isCaliforniaState = localStorage.order.serviceLocation.state as string == 'CA' ? true : false;
|
||||
let hasRecalPart: boolean = false;
|
||||
let canSafeliteRecalibrate: boolean = false;
|
||||
if (!isRepair) {
|
||||
hasRecalPart = localStorage.order.lineItems.glassParts.find((item: any) => item.requiresRecalibration === true) ? true : false;
|
||||
canSafeliteRecalibrate = localStorage.order.lineItems.glassParts.find((item: any) => item.canSafeliteRecalibrate === true) ? true : false;
|
||||
}
|
||||
let recalRequired = !isRepair && (isInsurance || isCaliforniaState) && hasRecalPart
|
||||
let recalRequired = !isRepair && (isInsurance || isCaliforniaState) && hasRecalPart && canSafeliteRecalibrate
|
||||
let stringForRepair: string[] = ["Expert windshield repair", "Exclusive resin sealant", "Nationwide lifetime guarantee"];
|
||||
let stringIfRecal = isRepair
|
||||
? ""
|
||||
|
|
|
|||
|
|
@ -157,10 +157,20 @@ export class ServicePackagesPage extends BasePage {
|
|||
|
||||
// Validate the presence of specific parts in the glassParts array
|
||||
const glassParts = vuexState.order?.lineItems?.glassParts;
|
||||
|
||||
|
||||
const WINDSHIELD_TYPES = [
|
||||
"SINGLE WINDSHIELD",
|
||||
"DRIVER SPLIT WINDSHIELD",
|
||||
"PASSENGER SPLIT WINDSHIELD"
|
||||
];
|
||||
|
||||
if (glassParts?.length > 0) {
|
||||
for (const partType of vehicleDamage) {
|
||||
const hasPartType = glassParts.some(glassPart => glassPart.partType === partType);
|
||||
// Normalize part type to "WINDSHIELD" if it matches any of the defined types (Split Windshield types)
|
||||
const normalizedPartType = WINDSHIELD_TYPES.includes(partType) ? "WINDSHIELD" : partType;
|
||||
|
||||
const hasPartType = glassParts.some(glassPart => glassPart.partType === normalizedPartType);
|
||||
|
||||
await expect(hasPartType, `Expected part type: ${partType}`).toBe(true);
|
||||
}
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -27,9 +27,13 @@ export class VehicleDamagePage extends BasePage {
|
|||
readonly rearStationaryBttn: Locator;
|
||||
readonly rearSlidingGlassBttn: Locator;
|
||||
readonly editVehicleLink: Locator;
|
||||
readonly singleSplitWindshieldChkBox: Locator;
|
||||
readonly driverSplitWindshieldChkBox: Locator;
|
||||
readonly passengerSplitWindshieldChkBox: Locator;
|
||||
|
||||
readonly noReplacementAvailableAlert: Locator;
|
||||
readonly bothReplaceRepairAlert: Locator;
|
||||
readonly splitWindshieldAlert: Locator;
|
||||
url = process.env['BASE_URL']! + '/fmg/?fmgPage=vehicle-damage';
|
||||
|
||||
constructor(page: Page) {
|
||||
|
|
@ -51,8 +55,12 @@ export class VehicleDamagePage extends BasePage {
|
|||
this.passengerVentGlassChkBox = this.page.locator('[aria-labelledby="passengerSideOptions"]').locator('[buttonlabel="Vent glass"]');
|
||||
this.passengerBackDoorChkBox = this.page.locator('[aria-labelledby="passengerSideOptions"]').locator('[buttonlabel="Back door"]');
|
||||
this.rearWindowChkBox = this.page.locator('[buttonlabel="Rear window"]');
|
||||
this.singleSplitWindshieldChkBox = this.page.locator('[aria-labelledby="WindshieldReplaceOptions"]').locator('[buttonlabel="Single windshield"]');
|
||||
this.driverSplitWindshieldChkBox = this.page.locator('[aria-labelledby="WindshieldReplaceOptions"]').locator('[buttonlabel="Split windshield, driver side"]');
|
||||
this.passengerSplitWindshieldChkBox = this.page.locator('[aria-labelledby="WindshieldReplaceOptions"]').locator('[buttonlabel="Split windshield, passenger side"]');
|
||||
this.noReplacementAvailableAlert = this.page.locator('.alert-danger.widget-name-NoReplacementAvailableError');
|
||||
this.bothReplaceRepairAlert = this.page.locator('div.alert-danger.widget-name-HasReplacementConflict');
|
||||
this.splitWindshieldAlert = this.page.locator('.alert-danger.widget-name-SplitSingleConflict');
|
||||
this.rearStationaryBttn = this.page.locator('label').filter({ hasText: 'Stationary' });
|
||||
this.rearSlidingGlassBttn = this.page.locator('label').filter({ hasText: 'Glass with slider' });
|
||||
this.editVehicleLink = this.page.getByRole('link', { name: 'Edit vehicle' });
|
||||
|
|
@ -77,6 +85,21 @@ export class VehicleDamagePage extends BasePage {
|
|||
await this.windshieldChkBox.check();
|
||||
await this.selectCrack();
|
||||
break;
|
||||
case VehicleDamage.SingleSplitWindshield:
|
||||
await this.windshieldChkBox.check();
|
||||
await this.selectCrack();
|
||||
await this.singleSplitWindshieldChkBox.check();
|
||||
break;
|
||||
case VehicleDamage.DriverSplitWindshield:
|
||||
await this.windshieldChkBox.check();
|
||||
await this.selectCrack();
|
||||
await this.driverSplitWindshieldChkBox.check();
|
||||
break;
|
||||
case VehicleDamage.PassengerSplitWindshield:
|
||||
await this.windshieldChkBox.check();
|
||||
await this.selectCrack();
|
||||
await this.passengerSplitWindshieldChkBox.check();
|
||||
break;
|
||||
case VehicleDamage.DriverFrontDoor:
|
||||
await this.sideDoorButton.check();
|
||||
await this.driverSideButton.check();
|
||||
|
|
@ -165,10 +188,17 @@ export class VehicleDamagePage extends BasePage {
|
|||
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.")
|
||||
}
|
||||
|
||||
async checkForSplitWindshieldAlertMessage(): Promise<void> {
|
||||
await expect(this.splitWindshieldAlert).toBeVisible();
|
||||
const alertMessage = await this.splitWindshieldAlert.textContent();
|
||||
console.log(`Alert encountered: ${alertMessage}`);
|
||||
expect(alertMessage).toContain("Single-piece or split?Please select just one windshield option: single-piece or split.")
|
||||
}
|
||||
|
||||
@step('VehicleDamagePage >> Select Damage')
|
||||
async handleVehicleDamagePage(testData: Partial<ITestData>): Promise<void> {
|
||||
const {vehicleDamage} = testData;
|
||||
const {isRepairReplace, isRepairOnly} = testData.alertFlags || {};
|
||||
const {isRepairReplace, isRepairOnly, isSplitWindshield} = testData.alertFlags || {};
|
||||
|
||||
await this.validateProgressBar(ProgressBarPercentages.VehicleDamagePage);
|
||||
await this.selectDamage(vehicleDamage!);
|
||||
|
|
@ -181,6 +211,10 @@ export class VehicleDamagePage extends BasePage {
|
|||
await this.checkForRepairOnlyAlertMessage();
|
||||
throw new TestSuccessAlert('Both assertions are met successfully.');
|
||||
}
|
||||
if (isSplitWindshield) {
|
||||
await this.checkForSplitWindshieldAlertMessage();
|
||||
throw new TestSuccessAlert('Both assertions are met successfully.');
|
||||
}
|
||||
await this.nextPage();
|
||||
}
|
||||
}
|
||||
|
|
@ -12,6 +12,7 @@ export class VehicleSelectionPage extends BasePage {
|
|||
readonly makeDropdown: Locator;
|
||||
readonly modelDropdown: Locator;
|
||||
readonly styleDropdown: Locator;
|
||||
readonly zipCodeTextBox: Locator;
|
||||
readonly discontinuedServiceAlert: Locator;
|
||||
|
||||
url = process.env['BASE_URL']! + '/fmg/?fmgPage=vehicle';
|
||||
|
|
@ -23,6 +24,7 @@ export class VehicleSelectionPage extends BasePage {
|
|||
this.makeDropdown = this.page.locator('#makeQuestionField');
|
||||
this.modelDropdown = this.page.locator('#modelQuestionField');
|
||||
this.styleDropdown = this.page.locator('#styleQuestionField');
|
||||
this.zipCodeTextBox = this.page.getByRole('textbox', { name: 'Zip code' });
|
||||
this.discontinuedServiceAlert = this.page.locator('.alert-danger.widget-name-AlertNoServiceWidget');
|
||||
// this.validateURL(this.url);
|
||||
}
|
||||
|
|
@ -49,13 +51,18 @@ export class VehicleSelectionPage extends BasePage {
|
|||
@step("VehicleSelectionPage >> Select Vehicle: ")
|
||||
async handleVehicleSelectionPage(testData: Partial<ITestData>) {
|
||||
await this.validateProgressBar(ProgressBarPercentages.VehicleSelectionPage);
|
||||
const { vehicleDetails } = testData;
|
||||
const { isHeavyTruckVehicle, isSplitWindshield } = testData.alertFlags || {};
|
||||
const { vehicleDetails, isHeavyTruck, customerDetails } = testData;
|
||||
const { isHeavyTruckVehicleAlert, isSplitWindshield } = testData.alertFlags || {};
|
||||
|
||||
await this.selectVehicle(vehicleDetails!);
|
||||
|
||||
if (isHeavyTruck) {
|
||||
await this.zipCodeTextBox.fill(customerDetails?.address.postalCode!);
|
||||
}
|
||||
|
||||
// Handle alert conditions for vehicle selection
|
||||
if (isHeavyTruckVehicle || isSplitWindshield) {
|
||||
if (isHeavyTruckVehicleAlert) {
|
||||
await this.continueButton.click();
|
||||
await this.checkForAlertMessages();
|
||||
throw new TestSuccessAlert('Both assertions are met successfully.');
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,12 +27,17 @@ import insuranceAcuityPaypalTests from "./InsuranceAcuityPaypal";
|
|||
import insuranceITAC21stCenturyTests from "./InsuranceITAC21stCentury";
|
||||
import insuranceGeicoTests from "./InsuranceGeico";
|
||||
import insuranceITACOptimizedPriceValidationAllStateTests from "./InsuranceITACOptimizedPriceValidationAllState";
|
||||
import insuranceNoCompProgressiveTests from "./InsuranceNoCompProgressive";
|
||||
import cashRepairInShopAfterPayTests from "./CashRepairInShopAfterPay";
|
||||
import cashRepairInShopPayPalTests from "./CashRepairInShopPayPal";
|
||||
import cashReplaceMultiSlidingGlassDropoffTests from "./CashReplaceMultiSlidingGlassDropoff";
|
||||
import cashReplaceMultiGlassMobileTests from "./CashReplaceMultiGlassMobile";
|
||||
import { getTestObject, TestCase, prepareTest, RuleEngine, TestInfo } from 'framework/Typedefs';
|
||||
import { createTestPages } from "framework/TestPages";
|
||||
import cashReplaceSwitchToInsuranceProgressiveNoCompTests from "./CashReplaceSwitchToInsuranceProgressiveNoComp";
|
||||
import insuranceBigTruckVerifiedTests from "./InsuranceBigTruckVerified";
|
||||
import insuranceUnverifiedTests from "./InsuranceUnverified";
|
||||
import CashReplaceSplitWindshieldTests from "./CashReplaceSplitWindshield";
|
||||
|
||||
const test = getTestObject();
|
||||
|
||||
|
|
@ -69,8 +74,14 @@ const allStandardTests = [
|
|||
{name: "CashReplaceVinMobile", tests: cashReplaceVinMobileTests},
|
||||
{name: "CashReplaceWiperDropoff", tests: cashReplaceWiperDropoffTests},
|
||||
{name: "CashReplaceWiperPromoInshop", tests: cashReplaceWiperPromoInShopTests},
|
||||
{name: "CashReplaceSwitchToInsuranceProgressiveNoComp", tests: cashReplaceSwitchToInsuranceProgressiveNoCompTests},
|
||||
// TODO: Uncomment when QA is ready to run heavy truck tests
|
||||
// {name: "CashReplaceSplitWindshield", tests: CashReplaceSplitWindshieldTests},
|
||||
{name: "InsuranceAcuityPaypal", tests: insuranceAcuityPaypalTests},
|
||||
{name: "InsuranceITAC21stCentury", tests: insuranceITAC21stCenturyTests},
|
||||
{name: "InsuranceNoCompProgressive", tests: insuranceNoCompProgressiveTests},
|
||||
// {name: "InsuranceBigTruckVerified", tests: insuranceBigTruckVerifiedTests},
|
||||
{name: "InsuranceUnverified", tests: insuranceUnverifiedTests},
|
||||
// {name: "InsuranceGeico", tests: insuranceGeicoTests},
|
||||
// {name: "InsuranceITACOptimizedPriceValidationAllState", tests: insuranceITACOptimizedPriceValidationAllStateTests}
|
||||
|
||||
|
|
@ -78,9 +89,10 @@ const allStandardTests = [
|
|||
|
||||
// Alert validation scenarios
|
||||
const allAlertTests = [
|
||||
{ name: "Alert Scenario 1: Heavy Truck", tests: heavyTruckTests },
|
||||
//TODO: Uncomment when QA is ready to run heavy truck tests
|
||||
// { name: "Alert Scenario 1: Heavy Truck", tests: heavyTruckTests },
|
||||
{ name: "Alert Scenario 2: Repair and Replace", tests: repairAndReplaceTests },
|
||||
{ name: "Alert Scenario 3: Split Windshield", tests: splitWindshieldTests },
|
||||
// { name: "Alert Scenario 3: Split Windshield", tests: splitWindshieldTests },
|
||||
{ name: "Alert Scenario 4: Repair Only", tests: repairOnlyTests },
|
||||
{ name: "Alert Scenario 5: Unserviceable Zip", tests: unserviceableZipTests },
|
||||
{ name: "Alert Scenario 6: Invalid Zip", tests: invalidZipTests },
|
||||
|
|
@ -166,10 +178,14 @@ async function runWorkflow(page: Page, testCase: TestCase) {
|
|||
} = testCase.testData;
|
||||
|
||||
// Check if the vehicle damage includes a windshield crack
|
||||
const hasWindshieldCrack = vehicleDamage!.some(damage =>
|
||||
damage === VehicleDamage.WindshieldCrack
|
||||
const hasWindshieldCrack = vehicleDamage!.some(damage =>
|
||||
damage === VehicleDamage.WindshieldCrack ||
|
||||
damage === VehicleDamage.DriverSplitWindshield ||
|
||||
damage === VehicleDamage.PassengerSplitWindshield ||
|
||||
damage === VehicleDamage.SingleSplitWindshield
|
||||
);
|
||||
|
||||
|
||||
//============================= TEST WORKFLOW STEPS =============================
|
||||
|
||||
// Use Environment Variable to decide whether or not we want to skip content site aka home page
|
||||
|
|
@ -273,6 +289,7 @@ async function runWorkflow(page: Page, testCase: TestCase) {
|
|||
let serviceLocationPage = testCase.pages.serviceLocationPage;
|
||||
await serviceLocationPage.handleServiceLocationPage(testCase.testData);
|
||||
|
||||
|
||||
// Schedule appointment
|
||||
let schedulePage = testCase.pages.schedulePage;
|
||||
await schedulePage.handleSchedulePage(testCase.testData);
|
||||
|
|
@ -300,7 +317,7 @@ async function runWorkflow(page: Page, testCase: TestCase) {
|
|||
}
|
||||
|
||||
export async function handleInsuranceFlow(testCase: TestCase) {
|
||||
const { flow, isPolicyDriver, endorsements, isRecalNotification } = testCase.testData;
|
||||
const { isPolicyFound, isPolicyDriver, endorsements, isRecalVehicle, isCashInsuranceFlow, flow } = testCase.testData;
|
||||
|
||||
// Check if the insurance policy has endorsements
|
||||
const hasEndorsements = endorsements && endorsements.length > 0;
|
||||
|
|
@ -344,7 +361,7 @@ export async function handleInsuranceFlow(testCase: TestCase) {
|
|||
let policyInfoSubmittedPage = testCase.pages.policyInfoSubmittedPage;
|
||||
await policyInfoSubmittedPage.handlePolicyInfoSubmittedPage();
|
||||
|
||||
if(isRecalNotification)
|
||||
if(isRecalVehicle)
|
||||
{
|
||||
let recalibrationInfoPage = testCase.pages.recalibrationInfoPage;
|
||||
await recalibrationInfoPage.handleRecalibrationInfoPage();
|
||||
|
|
@ -353,4 +370,22 @@ export async function handleInsuranceFlow(testCase: TestCase) {
|
|||
//handle coveraage statement page
|
||||
let coverageStatementPage = testCase.pages.coverageStatementPage;
|
||||
await coverageStatementPage.handleCoverageStatementPage(testCase.testData);
|
||||
|
||||
// Handle scenario where user selected Cash to Insurance and needs to go back through the flow
|
||||
// right now we are choosing pay at appointment as payment method for this scenario
|
||||
if (isCashInsuranceFlow) {
|
||||
let serviceLocationPage = testCase.pages.serviceLocationPage;
|
||||
await serviceLocationPage.nextPage();
|
||||
|
||||
//schedule
|
||||
let schedulePage = testCase.pages.schedulePage;
|
||||
await schedulePage.nextPage();
|
||||
//customer dertails
|
||||
let contactDetailsPage = testCase.pages.contactDetailsPage;
|
||||
await contactDetailsPage.nextPage();
|
||||
|
||||
//paymentmethods
|
||||
let paymentMethodPage = testCase.pages.paymentMethodPage;
|
||||
await paymentMethodPage.nextPage();
|
||||
}
|
||||
}
|
||||
74
playwright-tests/tests/CashReplaceSplitWindshield.ts
Normal file
74
playwright-tests/tests/CashReplaceSplitWindshield.ts
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
//Imports here
|
||||
import { ITestData } from 'framework/TestData'
|
||||
import { PartQuestionType, PaymentType, VehicleDamage } from 'safelite-playwright-core';
|
||||
import { ITestCase } from '../framework/Typedefs'
|
||||
import { VehicleLookupType } from 'safelite-playwright-core';
|
||||
import { getDefaultTestData, setFakerSeedFromTestName } from 'safelite-playwright-core';
|
||||
|
||||
// Set the seed before generating any data
|
||||
setFakerSeedFromTestName("CashReplaceSplitWindshield.ts");
|
||||
|
||||
// Now get the test data with the seeded faker
|
||||
const CashReplaceSplitWindshieldData: Partial<ITestData> = {
|
||||
...getDefaultTestData(), // Get default data with current seed
|
||||
|
||||
isHeavyTruck: true, // Flag for big truck
|
||||
|
||||
customerDetails: {
|
||||
...getDefaultTestData().customerDetails!,
|
||||
address: {
|
||||
...getDefaultTestData().customerDetails!.address,
|
||||
postalCode: '55414'
|
||||
}
|
||||
},
|
||||
|
||||
// Override vehicle details
|
||||
vehicleDetails: {
|
||||
...getDefaultTestData().vehicleDetails!,
|
||||
year: '2006',
|
||||
make: 'Navistar',
|
||||
model: '5000 I',
|
||||
style: '2 door conventional cab',
|
||||
vehicleLookupType: VehicleLookupType.Zip
|
||||
},
|
||||
|
||||
vehiclePartQuestions: [
|
||||
{
|
||||
partQuestionType: PartQuestionType.DriverWindshield,
|
||||
isOnPage: true,
|
||||
optionToSelect: 'Green Tint',
|
||||
secondaryQuestionOptionToSelect: 'driver side, encap, asymmetrically strengthen'
|
||||
},
|
||||
{
|
||||
partQuestionType: PartQuestionType.PassengerWindshield,
|
||||
isOnPage: true,
|
||||
optionToSelect: 'Green Tint',
|
||||
secondaryQuestionOptionToSelect: 'passenger side, encap, asymmetrically strengthen'
|
||||
},
|
||||
],
|
||||
|
||||
// Override default vehicle damage (Split Windshield)
|
||||
vehicleDamage: [VehicleDamage.DriverSplitWindshield, VehicleDamage.PassengerSplitWindshield],
|
||||
|
||||
// Override appointment details
|
||||
appointmentDetails: {
|
||||
...getDefaultTestData().appointmentDetails!,
|
||||
shopAddress: "504 Malcolm Ave Se, Minneapolis, MN 55414"
|
||||
},
|
||||
|
||||
// Override payment details
|
||||
paymentDetails: {
|
||||
paymentType: PaymentType.PayAtService
|
||||
}
|
||||
}
|
||||
|
||||
const CashReplaceSplitWindshieldTests: ITestCase[] = [];
|
||||
|
||||
const tc = {
|
||||
name: `CashReplaceSplitWindshield`,
|
||||
tags: ['@E2E','@CashReplaceSplitWindshield', '@test_report', '@CASH'],
|
||||
testData: CashReplaceSplitWindshieldData
|
||||
};
|
||||
CashReplaceSplitWindshieldTests.push(tc);
|
||||
|
||||
export default CashReplaceSplitWindshieldTests;
|
||||
|
|
@ -0,0 +1,81 @@
|
|||
//Imports here
|
||||
import { ITestData } from 'framework/TestData'
|
||||
import { ServiceLocation } from "safelite-playwright-core";
|
||||
import { DamageType, PartQuestionType, PaymentType } from 'safelite-playwright-core'
|
||||
import { ITestCase } from '../framework/Typedefs'
|
||||
import { getDefaultTestData, setFakerSeedFromTestName } from 'safelite-playwright-core';
|
||||
|
||||
// Set the seed for consistent data generation
|
||||
setFakerSeedFromTestName("CashReplaceSwitchToInsuranceProgressiveNoComp");
|
||||
|
||||
// Define insurance test data for Progressive
|
||||
const cashReplaceSwitchToInsuranceProgressiveNoCompData: Partial<ITestData> = {
|
||||
...getDefaultTestData(),
|
||||
|
||||
isCashInsuranceFlow: true,
|
||||
|
||||
// Override customer details based on provided ZIP code
|
||||
customerDetails: {
|
||||
...getDefaultTestData().customerDetails!,
|
||||
address: {
|
||||
...getDefaultTestData().customerDetails!.address,
|
||||
postalCode: "70458",
|
||||
},
|
||||
},
|
||||
|
||||
// Vehicle details for a 2012 Chrysler 300
|
||||
vehicleDetails: {
|
||||
...getDefaultTestData().vehicleDetails!,
|
||||
year: "2012",
|
||||
make: "Chrysler",
|
||||
model: "300",
|
||||
style: "4 door sedan"
|
||||
},
|
||||
|
||||
partQuestions: [
|
||||
{
|
||||
partQuestionType: PartQuestionType.GeneralQuestion1,
|
||||
isOnPage: true,
|
||||
optionToSelect: 'Yes'
|
||||
},
|
||||
],
|
||||
|
||||
// Override payment details
|
||||
paymentDetails: {
|
||||
paymentType: PaymentType.PayWithInsurance, // Ensures insurance payment method is selected
|
||||
},
|
||||
|
||||
// Insurance claim details
|
||||
claimDetails: {
|
||||
client: "Progressive",
|
||||
policyNumber: "Mock495646B",
|
||||
policyDeductible: 0,
|
||||
damageDate: new Date(new Date().setDate(new Date().getDate() - 1)).toLocaleDateString("en-US", { month: "2-digit", day: "2-digit", year: "numeric" }),
|
||||
damageCause: DamageType.Rock,
|
||||
},
|
||||
|
||||
isPolicyFound: true,
|
||||
isUseVehicleOnPolicy: true,
|
||||
isPolicyDriver: true,
|
||||
|
||||
// Appointment details for in-shop service
|
||||
appointmentDetails: {
|
||||
serviceLocation: ServiceLocation.InShop,
|
||||
shopAddress: "8985 Yellow Brick Rd, Rosedale, MD 21237",
|
||||
appointmentDate: getDefaultTestData().appointmentDetails?.appointmentDate,
|
||||
},
|
||||
|
||||
|
||||
};
|
||||
|
||||
// Create and register the test case
|
||||
const cashReplaceSwitchToInsuranceProgressiveNoCompTests: ITestCase[] = [];
|
||||
|
||||
const tc = {
|
||||
name: `CashReplaceSwitchToInsuranceProgressiveNoComp`,
|
||||
tags: ["@E2E", "@CashReplaceSwitchToInsuranceProgressiveNoComp", "@test_report", "@CASH"],
|
||||
testData: cashReplaceSwitchToInsuranceProgressiveNoCompData,
|
||||
};
|
||||
cashReplaceSwitchToInsuranceProgressiveNoCompTests.push(tc);
|
||||
|
||||
export default cashReplaceSwitchToInsuranceProgressiveNoCompTests;
|
||||
82
playwright-tests/tests/InsuranceBigTruckVerified.ts
Normal file
82
playwright-tests/tests/InsuranceBigTruckVerified.ts
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
//Imports here
|
||||
import { ITestData } from 'framework/TestData'
|
||||
import { ServiceLocation, DamageType, PaymentType, PartQuestionType } from 'safelite-playwright-core';
|
||||
import { ITestCase } from '../framework/Typedefs'
|
||||
import { PaymentMethod } from "framework/localTypes/Enums";
|
||||
import { VehicleLookupType } from 'safelite-playwright-core';
|
||||
import { getDefaultTestData, setFakerSeedFromTestName } from 'safelite-playwright-core';
|
||||
|
||||
// Set the seed based on test name for consistent but unique data
|
||||
setFakerSeedFromTestName("InsuranceBigTruckVerified");
|
||||
|
||||
// Now get the test data with the seeded faker
|
||||
const insuranceBigTruckVerifiedData: Partial<ITestData> = {
|
||||
...getDefaultTestData(), // Get default data with current seed
|
||||
|
||||
// Key feature: Insurance flow with GEICO
|
||||
paymentMethod: PaymentMethod.Insurance,
|
||||
|
||||
// Insurance claim flags
|
||||
isDuplicateClaim: true,
|
||||
isPolicyFound: true,
|
||||
isUseVehicleOnPolicy: true,
|
||||
isHeavyTruck: true,
|
||||
|
||||
// Override customer details with specific name and California location
|
||||
customerDetails: {
|
||||
...getDefaultTestData().customerDetails!,
|
||||
firstName: 'Big',
|
||||
lastName: 'Truck',
|
||||
address: {
|
||||
...getDefaultTestData().customerDetails!.address,
|
||||
city: 'Ontario',
|
||||
state: 'California',
|
||||
postalCode: '43085'
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
// Insurance claim details
|
||||
claimDetails: {
|
||||
client: 'USAA',
|
||||
policyNumber: 'Mock900040BigTruck',
|
||||
policyDeductible: 2000.00,
|
||||
policyZip: '55414',
|
||||
damageDate: new Date(new Date().setDate(new Date().getDate() - 1)).toLocaleDateString('en-US', {month: '2-digit', day: '2-digit', year: 'numeric'}),
|
||||
damageCause: DamageType.Rock
|
||||
},
|
||||
|
||||
// Hyundai vehicle details with VIN lookup
|
||||
vehicleDetails: {
|
||||
...getDefaultTestData().vehicleDetails!,
|
||||
year: '2025',
|
||||
make: 'Peterbilt',
|
||||
model: '579',
|
||||
style: 'conventional cab',
|
||||
vin: '1XPBDP9X6SD693446',
|
||||
vehicleLookupType: VehicleLookupType.Vin,
|
||||
},
|
||||
|
||||
// No need to override vehicleDamage as it already defaults to WindshieldCrack
|
||||
|
||||
// Override for in-shop appointment
|
||||
appointmentDetails: {
|
||||
serviceLocation: ServiceLocation.InShop,
|
||||
shopAddress: '5719 Brandt Pike, Dayton, OH 45424',
|
||||
appointmentDate: getDefaultTestData().appointmentDetails?.appointmentDate
|
||||
},
|
||||
|
||||
// Override payment details (empty because we skip payment method page in insurance flow)
|
||||
paymentDetails: {}
|
||||
}
|
||||
|
||||
const insuranceBigTruckVerifiedTests: ITestCase[] = [];
|
||||
|
||||
const tc = {
|
||||
name: `InsuranceBigTruckVerified`,
|
||||
tags: ['@E2E','@InsuranceBigTruckVerified', '@test_report', '@Insurance'],
|
||||
testData: insuranceBigTruckVerifiedData
|
||||
};
|
||||
insuranceBigTruckVerifiedTests.push(tc);
|
||||
|
||||
export default insuranceBigTruckVerifiedTests;
|
||||
|
|
@ -20,7 +20,7 @@ const insuranceITAC21stCenturyData: Partial<ITestData> = {
|
|||
isDuplicateClaim: true,
|
||||
flow: Flow.Managed,
|
||||
isUseVehicleOnPolicy: true,
|
||||
isRecalNotification: true, // Special flag for recalibration notification
|
||||
isRecalVehicle: true, // Special flag for recalibration notification
|
||||
|
||||
// Override customer details for California location
|
||||
customerDetails: {
|
||||
|
|
|
|||
90
playwright-tests/tests/InsuranceNoCompProgressive.ts
Normal file
90
playwright-tests/tests/InsuranceNoCompProgressive.ts
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
//Imports here
|
||||
import { ITestData } from 'framework/TestData'
|
||||
import { ServiceLocation, DamageType, PaymentType, PartQuestionType } from 'safelite-playwright-core';
|
||||
import { ITestCase } from '../framework/Typedefs'
|
||||
import { PaymentMethod } from "framework/localTypes/Enums";
|
||||
import { VehicleLookupType } from 'safelite-playwright-core';
|
||||
import { getDefaultTestData, setFakerSeedFromTestName } from 'safelite-playwright-core';
|
||||
|
||||
// Set the seed based on test name for consistent but unique data
|
||||
setFakerSeedFromTestName("InsuranceNoCompProgressive");
|
||||
|
||||
// Now get the test data with the seeded faker
|
||||
const insuranceNoCompProgressiveData: Partial<ITestData> = {
|
||||
...getDefaultTestData(), // Get default data with current seed
|
||||
|
||||
// Key feature: Insurance flow with GEICO
|
||||
paymentMethod: PaymentMethod.Insurance,
|
||||
|
||||
// Insurance claim flags
|
||||
isDuplicateClaim: true,
|
||||
isPolicyFound: true,
|
||||
isUseVehicleOnPolicy: true,
|
||||
isHeavyTruck: false,
|
||||
isPolicyDriver: true,
|
||||
isRecalVehicle: true,
|
||||
|
||||
// Override customer details with specific name and California location
|
||||
customerDetails: {
|
||||
...getDefaultTestData().customerDetails!,
|
||||
firstName: 'SHERI',
|
||||
lastName: 'SCHATZ',
|
||||
address: {
|
||||
...getDefaultTestData().customerDetails!.address,
|
||||
city: 'Slidell',
|
||||
state: 'Louisiana',
|
||||
postalCode: '70458'
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
// Insurance claim details
|
||||
claimDetails: {
|
||||
client: 'Progressive',
|
||||
policyNumber: 'Mock495646B',
|
||||
policyDeductible: 1722.20,
|
||||
policyZip: '70458',
|
||||
damageDate: new Date(new Date().setDate(new Date().getDate() - 1)).toLocaleDateString('en-US', {month: '2-digit', day: '2-digit', year: 'numeric'}),
|
||||
damageCause: DamageType.Rock
|
||||
},
|
||||
|
||||
// Hyundai vehicle details with VIN lookup
|
||||
vehicleDetails: {
|
||||
...getDefaultTestData().vehicleDetails!,
|
||||
year: '2015',
|
||||
make: 'Acura',
|
||||
model: 'MDX',
|
||||
style: '4 door utility',
|
||||
vehicleLookupType: VehicleLookupType.Zip,
|
||||
},
|
||||
|
||||
// Part questions related to recalibration
|
||||
partQuestions: [
|
||||
{
|
||||
partQuestionType: PartQuestionType.GeneralQuestion1,
|
||||
isOnPage: true,
|
||||
optionToSelect: 'Yes'
|
||||
},
|
||||
],
|
||||
|
||||
// Override for in-shop appointment
|
||||
appointmentDetails: {
|
||||
serviceLocation: ServiceLocation.InShop,
|
||||
shopAddress: '56705 Garrett Road, Slidell, LA 70458',
|
||||
appointmentDate: getDefaultTestData().appointmentDetails?.appointmentDate
|
||||
},
|
||||
|
||||
// Override payment details (empty because we skip payment method page in insurance flow)
|
||||
paymentDetails: {}
|
||||
}
|
||||
|
||||
const insuranceNoCompProgressiveTests: ITestCase[] = [];
|
||||
|
||||
const tc = {
|
||||
name: `InsuranceNoCompProgressive`,
|
||||
tags: ['@E2E','@InsuranceNoCompProgressive', '@test_report', '@Insurance'],
|
||||
testData: insuranceNoCompProgressiveData
|
||||
};
|
||||
insuranceNoCompProgressiveTests.push(tc);
|
||||
|
||||
export default insuranceNoCompProgressiveTests;
|
||||
87
playwright-tests/tests/InsuranceUnverified.ts
Normal file
87
playwright-tests/tests/InsuranceUnverified.ts
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
//Imports here
|
||||
import { ITestData } from 'framework/TestData'
|
||||
import { ServiceLocation, DamageType, PaymentType, PartQuestionType } from 'safelite-playwright-core';
|
||||
import { ITestCase } from '../framework/Typedefs'
|
||||
import { PaymentMethod } from "framework/localTypes/Enums";
|
||||
import { VehicleLookupType } from 'safelite-playwright-core';
|
||||
import { getDefaultTestData, setFakerSeedFromTestName } from 'safelite-playwright-core';
|
||||
|
||||
// Set the seed based on test name for consistent but unique data
|
||||
setFakerSeedFromTestName("InsuranceUnverified");
|
||||
|
||||
// Now get the test data with the seeded faker
|
||||
const insuranceUnverifiedData: Partial<ITestData> = {
|
||||
...getDefaultTestData(), // Get default data with current seed
|
||||
|
||||
// Key feature: Insurance flow with GEICO
|
||||
paymentMethod: PaymentMethod.Insurance,
|
||||
|
||||
// Insurance claim flags
|
||||
isPolicyFound: false,
|
||||
isPolicyUnverified: true,
|
||||
isRecalVehicle: true,
|
||||
|
||||
// Override customer details with specific name and California location
|
||||
customerDetails: {
|
||||
...getDefaultTestData().customerDetails!,
|
||||
firstName: 'Jane',
|
||||
lastName: 'Unverified',
|
||||
address: {
|
||||
...getDefaultTestData().customerDetails!.address,
|
||||
city: 'Richmond',
|
||||
state: 'Virginia',
|
||||
postalCode: '23219'
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
// Insurance claim details
|
||||
claimDetails: {
|
||||
client: '21st Century',
|
||||
policyNumber: 'UnverifiedMock',
|
||||
policyDeductible: "Unverified",
|
||||
policyZip: '43123',
|
||||
damageDate: new Date(new Date().setDate(new Date().getDate() - 1)).toLocaleDateString('en-US', {month: '2-digit', day: '2-digit', year: 'numeric'}),
|
||||
damageCause: DamageType.Rock
|
||||
},
|
||||
|
||||
// Hyundai vehicle details with VIN lookup
|
||||
vehicleDetails: {
|
||||
...getDefaultTestData().vehicleDetails!,
|
||||
year: '2014',
|
||||
make: 'Honda',
|
||||
model: 'Accord',
|
||||
style: '4 door sedan',
|
||||
vehicleLookupType: VehicleLookupType.Zip,
|
||||
},
|
||||
|
||||
// Part questions related to recalibration
|
||||
partQuestions: [
|
||||
{
|
||||
partQuestionType: PartQuestionType.GeneralQuestion1,
|
||||
isOnPage: true,
|
||||
optionToSelect: 'Yes'
|
||||
},
|
||||
],
|
||||
|
||||
// Override for in-shop appointment
|
||||
appointmentDetails: {
|
||||
serviceLocation: ServiceLocation.InShop,
|
||||
shopAddress: '5719 Brandt Pike, Dayton, OH 45424',
|
||||
appointmentDate: getDefaultTestData().appointmentDetails?.appointmentDate
|
||||
},
|
||||
|
||||
// Override payment details (empty because we skip payment method page in insurance flow)
|
||||
paymentDetails: {}
|
||||
}
|
||||
|
||||
const insuranceUnverifiedTests: ITestCase[] = [];
|
||||
|
||||
const tc = {
|
||||
name: `InsuranceUnverified`,
|
||||
tags: ['@E2E','@InsuranceUnverified', '@test_report', '@Insurance'],
|
||||
testData: insuranceUnverifiedData
|
||||
};
|
||||
insuranceUnverifiedTests.push(tc);
|
||||
|
||||
export default insuranceUnverifiedTests;
|
||||
|
|
@ -4,11 +4,23 @@ import { VehicleDamage, ServiceLocation } from 'safelite-playwright-core';
|
|||
import { ITestCase } from '../../framework/Typedefs';
|
||||
import { getNextWeekday } from 'safelite-playwright-core';
|
||||
import { defaultTestData } from 'safelite-playwright-core';
|
||||
import { getDefaultTestData, setFakerSeedFromTestName } from 'safelite-playwright-core';
|
||||
|
||||
// Heavy Truck (alert) Test Data
|
||||
const heavyTruckData: Partial<ITestData> = {
|
||||
...defaultTestData, // Start with all defaults
|
||||
|
||||
|
||||
isHeavyTruck: true, // Flag for heavy truck vehicle
|
||||
|
||||
customerDetails: {
|
||||
...getDefaultTestData().customerDetails!,
|
||||
address: {
|
||||
...getDefaultTestData().customerDetails!.address,
|
||||
postalCode: '21237'
|
||||
}
|
||||
},
|
||||
|
||||
// Override specific fields with test-specific data
|
||||
vehicleDetails: {
|
||||
...defaultTestData.vehicleDetails!,
|
||||
|
|
@ -18,7 +30,7 @@ const heavyTruckData: Partial<ITestData> = {
|
|||
style: 'conventional cab'
|
||||
},
|
||||
alertFlags: {
|
||||
isHeavyTruckVehicle: true
|
||||
isHeavyTruckVehicleAlert: true
|
||||
},
|
||||
vehicleDamage: [
|
||||
VehicleDamage.WindshieldOneChip,
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
// Imports here
|
||||
import { ITestData } from 'framework/TestData';
|
||||
import { ITestCase } from '../../framework/Typedefs'
|
||||
import { ITestCase, TestCase } from '../../framework/Typedefs'
|
||||
import { VehicleDamage } from 'safelite-playwright-core';
|
||||
import { defaultTestData } from 'safelite-playwright-core';
|
||||
import { getDefaultTestData, setFakerSeedFromTestName } from 'safelite-playwright-core';
|
||||
|
||||
// Windshield selected, when vehicle has split windshield (alert) Test Data
|
||||
const splitWindshieldData: Partial<ITestData> = {
|
||||
|
|
@ -10,11 +11,21 @@ const splitWindshieldData: Partial<ITestData> = {
|
|||
|
||||
// Override specific fields with test-specific data
|
||||
vehicleDamage: [
|
||||
VehicleDamage.WindshieldOneChip
|
||||
VehicleDamage.SingleSplitWindshield,
|
||||
VehicleDamage.DriverSplitWindshield,
|
||||
VehicleDamage.PassengerSplitWindshield
|
||||
],
|
||||
alertFlags: {
|
||||
isSplitWindshield: true
|
||||
}
|
||||
},
|
||||
customerDetails: {
|
||||
...getDefaultTestData().customerDetails!,
|
||||
address: {
|
||||
...getDefaultTestData().customerDetails!.address,
|
||||
postalCode: '55414'
|
||||
}
|
||||
},
|
||||
isHeavyTruck: true, // Flag for heavy truck vehicle
|
||||
};
|
||||
|
||||
const vehiclesToTest = [
|
||||
|
|
@ -35,20 +46,21 @@ const vehiclesToTest = [
|
|||
make: 'Kenworth',
|
||||
model: 'T600',
|
||||
style: 'conventional cab'
|
||||
}
|
||||
},
|
||||
];
|
||||
|
||||
const splitWindshieldTests: ITestCase[] = [];
|
||||
|
||||
// Generate test cases for each vehicle
|
||||
vehiclesToTest.forEach((vehicle, index) => {
|
||||
const testData = {
|
||||
...splitWindshieldData,
|
||||
vehicleDetails: {
|
||||
...defaultTestData.vehicleDetails!,
|
||||
...vehicle
|
||||
}
|
||||
};
|
||||
|
||||
const testData = {
|
||||
...splitWindshieldData,
|
||||
vehicleDetails: {
|
||||
...defaultTestData.vehicleDetails!,
|
||||
...vehicle
|
||||
},
|
||||
}
|
||||
|
||||
const tc = {
|
||||
name: `alert0003_${vehicle.make.toLowerCase()}_${vehicle.model.toLowerCase()} Windshield selected, when vehicle has split windshield - ${vehicle.make} ${vehicle.model} ${vehicle.year}`,
|
||||
|
|
|
|||
|
|
@ -94,8 +94,16 @@ export default {
|
|||
FirstName: transfer.data.first_name,
|
||||
LastName: transfer.data.last_name,
|
||||
Email: transfer.data.email,
|
||||
Subject: transfer.data.chat_summary, // for now passing in chat_summery in Subject. But this will be changed in future.
|
||||
Subject: transfer.data.chat_summary,
|
||||
};
|
||||
window.embedded_svc.settings.extraPrechatFormDetails = [
|
||||
{
|
||||
label: "Scarlett AI Summary",
|
||||
value: transfer.data.chat_summary,
|
||||
transcriptFields: ["Scarlett_AI_Summary__c"],
|
||||
displayToAgent: true,
|
||||
},
|
||||
];
|
||||
if (
|
||||
window.embedded_svc.liveAgentAPI &&
|
||||
typeof window.embedded_svc.liveAgentAPI.startChat === "function"
|
||||
|
|
|
|||
|
|
@ -117,6 +117,10 @@
|
|||
<span>{{ amountPaidText }}</span>
|
||||
<span>{{ getLineItemAmount(amountPaid) }}</span>
|
||||
</div>
|
||||
<div v-if="donationCartItem" class="donation-amount">
|
||||
<span>{{ donationCartItemName }}</span>
|
||||
<span>{{ getLineItemAmount(donationCartItem.subTotal) }}</span>
|
||||
</div>
|
||||
<div class="amount-due">
|
||||
<span>{{ amountDueText }}</span>
|
||||
<span>{{ getLineItemAmount(amountDue, showCoverageAsPending) }}</span>
|
||||
|
|
@ -472,10 +476,6 @@ export default {
|
|||
});
|
||||
}
|
||||
|
||||
if (this.donationCartItem) {
|
||||
cartItems.push(this.donationCartItem);
|
||||
}
|
||||
|
||||
return cartItems;
|
||||
},
|
||||
},
|
||||
|
|
@ -1309,12 +1309,15 @@ export default {
|
|||
.sub-total,
|
||||
.sales-tax,
|
||||
.amount-due,
|
||||
.amount-paid {
|
||||
font-weight: 500;
|
||||
.amount-paid,
|
||||
.donation-amount {
|
||||
font-family:
|
||||
UrbanistSemibold, AvertaSemibold; //Okay to remove AvertaSemibold after 2025.06.19 merge/release
|
||||
color: $black;
|
||||
}
|
||||
.sub-total {
|
||||
border-top: 1px solid $green;
|
||||
background-color: $green-100;
|
||||
}
|
||||
.service-type,
|
||||
.deductible {
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ import { saveSession } from "@/helpers/heritage-integration/order-helper.js";
|
|||
import baseMixin from "@/mixins/base-mixin.js";
|
||||
import { queryStrings } from "@/constants/query-strings";
|
||||
import { nextTick } from "vue";
|
||||
import { consumeQueryFromStash } from "@/router/methods/helpers/querystring-stash";
|
||||
import { peekQueryFromStash } from "@/router/methods/helpers/querystring-stash";
|
||||
|
||||
// Define Validation Rules
|
||||
defineRule("zip-required", required(errorMessages.SERVICE_ZIP_REQUIRED));
|
||||
|
|
@ -100,7 +100,7 @@ export default {
|
|||
}
|
||||
|
||||
const zip =
|
||||
consumeQueryFromStash(queryStrings.ZIP_CODE) ??
|
||||
peekQueryFromStash(queryStrings.ZIP_CODE) ??
|
||||
store.getters.order.serviceLocation.zipCode;
|
||||
|
||||
var vinByAddressPromise;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import { reactive } from "vue";
|
||||
import { debugLog } from "@/helpers/debug-log-helper";
|
||||
|
||||
const queryStash = reactive({
|
||||
queries: [],
|
||||
|
|
@ -27,10 +28,18 @@ export function stashAllQueries(toRoute) {
|
|||
}
|
||||
|
||||
function getStashedQuery(key) {
|
||||
debugLog(`Fetching querystring with key:`, key);
|
||||
const match = queryStash.queries.find(
|
||||
(entry) => entry?.key?.toLowerCase() === key?.toLowerCase()
|
||||
);
|
||||
|
||||
if (match) {
|
||||
debugLog(`Found result:`, match.value);
|
||||
debugLog(`Already consumed:`, match.used);
|
||||
} else {
|
||||
debugLog(`Found no result`);
|
||||
}
|
||||
|
||||
return match;
|
||||
}
|
||||
|
||||
|
|
|
|||
14
src/router/methods/route-logic/payment.js
Normal file
14
src/router/methods/route-logic/payment.js
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
import store from "@/store";
|
||||
import { storeActions } from "@/constants/store-actions";
|
||||
import { paymentMethods } from "@/constants/payment-method-constants";
|
||||
import { debugLog } from "@/helpers/debug-log-helper";
|
||||
|
||||
export async function paymentBeforeEnter(to, from) {
|
||||
const piaType = store.getters.order?.payment?.piaType;
|
||||
debugLog(`Entering payment with type =`, piaType);
|
||||
|
||||
if (piaType === paymentMethods.PAYPAL) {
|
||||
debugLog(`Changing to payment type =`, paymentMethods.CREDIT_CARD);
|
||||
await store.dispatch(storeActions.SAVE_PAYMENT_METHOD_CHOICE, paymentMethods.CREDIT_CARD);
|
||||
}
|
||||
}
|
||||
|
|
@ -11,6 +11,7 @@ import { autoRouteBeforeEnter } from "@/router/methods/route-logic/auto-route";
|
|||
import { errorBeforeEnter } from "@/router/methods/route-logic/error";
|
||||
import { restartBeforeEnter } from "@/router/methods/route-logic/restart";
|
||||
import { paymentMethodBeforeEnter } from "@/router/methods/route-logic/payment-method";
|
||||
import { paymentBeforeEnter } from "@/router/methods/route-logic/payment";
|
||||
|
||||
export const routes = [
|
||||
// Non-virtual pages.
|
||||
|
|
@ -32,7 +33,7 @@ export const routes = [
|
|||
createRoute(routeData.SCHEDULE),
|
||||
createRoute(routeData.CUSTOMER_DETAILS),
|
||||
createRoute(routeData.PAYMENT_METHOD, paymentMethodBeforeEnter),
|
||||
createRoute(routeData.PAYMENT),
|
||||
createRoute(routeData.PAYMENT, paymentBeforeEnter),
|
||||
createRoute(routeData.PAYMENT_PIA_RETURN),
|
||||
createRoute(routeData.CONFIRMATION),
|
||||
createRoute(routeData.RETURN_USER),
|
||||
|
|
|
|||
|
|
@ -1072,33 +1072,6 @@ export const getters = {
|
|||
},
|
||||
};
|
||||
|
||||
function getNonFalseValuesOfPropertyInArrayOfObjects(array, propertyName) {
|
||||
return (array ?? []).map((x) => x[propertyName]).filter((x) => x);
|
||||
}
|
||||
|
||||
function getTimeSlotsAdditionalEventData(
|
||||
provisionalTriggers,
|
||||
zipCode,
|
||||
firstAvailableAppointmentDateString,
|
||||
shopAppointmentType
|
||||
) {
|
||||
var numberOfDays = null;
|
||||
if (firstAvailableAppointmentDateString)
|
||||
numberOfDays = getDateDifferenceInDays(
|
||||
new Date().toISOString().split("T")[0],
|
||||
firstAvailableAppointmentDateString
|
||||
);
|
||||
|
||||
if (shopAppointmentType)
|
||||
return `FirstAvailableAppointment:${numberOfDays},Zip:${zipCode},ShopAppointmentType:${shopAppointmentType},ProvisionalTriggers:${provisionalTriggers.join(
|
||||
","
|
||||
)}`;
|
||||
else
|
||||
return `FirstAvailableAppointment:${numberOfDays},Zip:${zipCode},ProvisionalTriggers:${provisionalTriggers.join(
|
||||
","
|
||||
)}`;
|
||||
}
|
||||
|
||||
// Export Actions
|
||||
export const actions = {
|
||||
// Vehicle API Actions
|
||||
|
|
@ -2059,20 +2032,31 @@ export const actions = {
|
|||
},
|
||||
};
|
||||
|
||||
return globalMethods.callHttpClient({
|
||||
let hasCalled = timeSlotCallFlags.shop;
|
||||
if (!hasCalled) {
|
||||
timeSlotCallFlags.shop = true;
|
||||
}
|
||||
|
||||
const options = {
|
||||
method: endpoints.GetShopTimeSlots.method,
|
||||
endpoint: endpoints.GetShopTimeSlots.url,
|
||||
payload: payload,
|
||||
logApiCall: true,
|
||||
pageNameToLog: pageNameToLog,
|
||||
additionalSuccessEventDataHandler: (response) =>
|
||||
};
|
||||
|
||||
// Only set handler if this is the very first call in this session
|
||||
if (!hasCalled) {
|
||||
options.additionalSuccessEventDataHandler = (response) =>
|
||||
getTimeSlotsAdditionalEventData(
|
||||
response.data.provisionalTriggers,
|
||||
order.serviceLocation.zipCode,
|
||||
response.data.days?.[0]?.date,
|
||||
shopAppointmentType
|
||||
),
|
||||
});
|
||||
);
|
||||
}
|
||||
|
||||
return globalMethods.callHttpClient(options);
|
||||
},
|
||||
|
||||
getMobileTimeSlots(context, { payload: { startDate, endDate }, pageNameToLog }) {
|
||||
|
|
@ -2116,19 +2100,30 @@ export const actions = {
|
|||
zipCode: order.serviceLocation.zipCode,
|
||||
};
|
||||
|
||||
return globalMethods.callHttpClient({
|
||||
let hasCalled = timeSlotCallFlags.mobile;
|
||||
if (!hasCalled) {
|
||||
timeSlotCallFlags.mobile = true;
|
||||
}
|
||||
|
||||
const options = {
|
||||
method: endpoints.GetMobileTimeSlots.method,
|
||||
endpoint: endpoints.GetMobileTimeSlots.url,
|
||||
payload: payload,
|
||||
logApiCall: true,
|
||||
pageNameToLog: pageNameToLog,
|
||||
additionalSuccessEventDataHandler: (response) =>
|
||||
};
|
||||
|
||||
// Only set handler if this is the very first call in this session
|
||||
if (!hasCalled) {
|
||||
options.additionalSuccessEventDataHandler = (response) =>
|
||||
getTimeSlotsAdditionalEventData(
|
||||
response.data.provisionalTriggers,
|
||||
order.serviceLocation.zipCode,
|
||||
response.data.days?.[0]?.date
|
||||
),
|
||||
});
|
||||
);
|
||||
}
|
||||
|
||||
return globalMethods.callHttpClient(options);
|
||||
},
|
||||
|
||||
getMobilePremiumFee(context, { pageNameToLog }) {
|
||||
|
|
@ -3457,100 +3452,6 @@ export default createStore({
|
|||
actions,
|
||||
});
|
||||
|
||||
// Private Functions
|
||||
|
||||
function getHasRecalibrationPart(state) {
|
||||
return containsRecalParts(state.order.lineItems);
|
||||
}
|
||||
|
||||
function sortArrayOfObjectsByPropertyValue(arrayOfObjects, propertyName) {
|
||||
if (!arrayOfObjects) return null;
|
||||
|
||||
return arrayOfObjects.sort((a, b) => {
|
||||
if (a[propertyName] < b[propertyName]) return -1;
|
||||
else if (a[propertyName] > b[propertyName]) return 1;
|
||||
else return 0;
|
||||
});
|
||||
}
|
||||
|
||||
function convertGlassPieceNamingForApi(glassArray) {
|
||||
if (!glassArray || glassArray.length === 0) return [];
|
||||
|
||||
// check if array already converted. (likely when a session has been saved previously and then reloaded)
|
||||
if (glassArray[0].location !== undefined) {
|
||||
return glassArray;
|
||||
}
|
||||
|
||||
const converted = [];
|
||||
glassArray.forEach((glass) => {
|
||||
converted.push({
|
||||
location: glass.glassLocation,
|
||||
name: glass.glassName,
|
||||
});
|
||||
});
|
||||
return converted;
|
||||
}
|
||||
|
||||
function convertResultsForApi(resultsArray) {
|
||||
if (!resultsArray) return [];
|
||||
const converted = [];
|
||||
resultsArray.forEach((answer) => {
|
||||
converted.push({
|
||||
location: answer.glassLocation,
|
||||
name: answer.glassName,
|
||||
result: answer.result,
|
||||
});
|
||||
});
|
||||
return converted;
|
||||
}
|
||||
|
||||
function convertGlassPieceNamingFromApi(glassArray) {
|
||||
glassArray.forEach((glass) => {
|
||||
glass.glassLocation = glass.glassPiece.location;
|
||||
glass.glassName = glass.glassPiece.name;
|
||||
delete glass.glassPiece;
|
||||
return glass;
|
||||
});
|
||||
return glassArray;
|
||||
}
|
||||
|
||||
function addPricesToLineItems(lineItems, pricingLineItems) {
|
||||
lineItems.forEach((lineItem) => {
|
||||
const lineItemIndex = pricingLineItems.findIndex(
|
||||
(pricingLineItem) => pricingLineItem.partNumber === lineItem.partNumber
|
||||
);
|
||||
|
||||
if (lineItem.childParts) {
|
||||
addPricesToLineItems(lineItem.childParts, pricingLineItems);
|
||||
}
|
||||
|
||||
const pricedLineItem = pricingLineItems.splice(lineItemIndex, 1)[0];
|
||||
lineItem.laborAmount = pricedLineItem.laborAmount;
|
||||
lineItem.sellingPrice = pricedLineItem.sellingPrice;
|
||||
lineItem.kitPrice = pricedLineItem.kitPrice;
|
||||
lineItem.salesTax = pricedLineItem.salesTax;
|
||||
});
|
||||
|
||||
return lineItems;
|
||||
}
|
||||
|
||||
function addTaxesToPricedLineItems(pricedLineItems, taxingLineItems = []) {
|
||||
pricedLineItems.forEach((pricedLineItem) => {
|
||||
const lineItemIndex = taxingLineItems.findIndex(
|
||||
(taxingLineItem) => taxingLineItem.partNumber === pricedLineItem.partNumber
|
||||
);
|
||||
|
||||
if (pricedLineItem.childParts) {
|
||||
addTaxesToPricedLineItems(pricedLineItem.childParts, taxingLineItems);
|
||||
}
|
||||
|
||||
const taxedLineItem = taxingLineItems.splice(lineItemIndex, 1)[0];
|
||||
pricedLineItem.salesTax = taxedLineItem?.salesTax ?? 0;
|
||||
});
|
||||
|
||||
return pricedLineItems;
|
||||
}
|
||||
|
||||
export function mapTaxedLineItemsToStoreFormat(availableLineItems, storeLineItems) {
|
||||
// clone the lineItems array because what we're passing in is referencing the store directly
|
||||
const lineItems = deepClone(storeLineItems);
|
||||
|
|
@ -3658,6 +3559,127 @@ export function getArrayOfAllLineItemsAndChildParts(lineItems) {
|
|||
return consolidatedLineItemsArray;
|
||||
}
|
||||
|
||||
// Private Functions
|
||||
|
||||
function getNonFalseValuesOfPropertyInArrayOfObjects(array, propertyName) {
|
||||
return (array ?? []).map((x) => x[propertyName]).filter((x) => x);
|
||||
}
|
||||
|
||||
function getTimeSlotsAdditionalEventData(
|
||||
provisionalTriggers,
|
||||
zipCode,
|
||||
firstAvailableAppointmentDateString,
|
||||
shopAppointmentType
|
||||
) {
|
||||
var numberOfDays = null;
|
||||
if (firstAvailableAppointmentDateString)
|
||||
numberOfDays = getDateDifferenceInDays(
|
||||
new Date().toISOString().split("T")[0],
|
||||
firstAvailableAppointmentDateString
|
||||
);
|
||||
|
||||
if (shopAppointmentType)
|
||||
return `FirstAvailableAppointment:${numberOfDays},Zip:${zipCode},ShopAppointmentType:${shopAppointmentType},ProvisionalTriggers:${provisionalTriggers.join(
|
||||
","
|
||||
)}`;
|
||||
else
|
||||
return `FirstAvailableAppointment:${numberOfDays},Zip:${zipCode},ProvisionalTriggers:${provisionalTriggers.join(
|
||||
","
|
||||
)}`;
|
||||
}
|
||||
|
||||
function getHasRecalibrationPart(state) {
|
||||
return containsRecalParts(state.order.lineItems);
|
||||
}
|
||||
|
||||
function sortArrayOfObjectsByPropertyValue(arrayOfObjects, propertyName) {
|
||||
if (!arrayOfObjects) return null;
|
||||
|
||||
return arrayOfObjects.sort((a, b) => {
|
||||
if (a[propertyName] < b[propertyName]) return -1;
|
||||
else if (a[propertyName] > b[propertyName]) return 1;
|
||||
else return 0;
|
||||
});
|
||||
}
|
||||
|
||||
function convertGlassPieceNamingForApi(glassArray) {
|
||||
if (!glassArray || glassArray.length === 0) return [];
|
||||
|
||||
// check if array already converted. (likely when a session has been saved previously and then reloaded)
|
||||
if (glassArray[0].location !== undefined) {
|
||||
return glassArray;
|
||||
}
|
||||
|
||||
const converted = [];
|
||||
glassArray.forEach((glass) => {
|
||||
converted.push({
|
||||
location: glass.glassLocation,
|
||||
name: glass.glassName,
|
||||
});
|
||||
});
|
||||
return converted;
|
||||
}
|
||||
|
||||
function convertResultsForApi(resultsArray) {
|
||||
if (!resultsArray) return [];
|
||||
const converted = [];
|
||||
resultsArray.forEach((answer) => {
|
||||
converted.push({
|
||||
location: answer.glassLocation,
|
||||
name: answer.glassName,
|
||||
result: answer.result,
|
||||
});
|
||||
});
|
||||
return converted;
|
||||
}
|
||||
|
||||
function convertGlassPieceNamingFromApi(glassArray) {
|
||||
glassArray.forEach((glass) => {
|
||||
glass.glassLocation = glass.glassPiece.location;
|
||||
glass.glassName = glass.glassPiece.name;
|
||||
delete glass.glassPiece;
|
||||
return glass;
|
||||
});
|
||||
return glassArray;
|
||||
}
|
||||
|
||||
function addPricesToLineItems(lineItems, pricingLineItems) {
|
||||
lineItems.forEach((lineItem) => {
|
||||
const lineItemIndex = pricingLineItems.findIndex(
|
||||
(pricingLineItem) => pricingLineItem.partNumber === lineItem.partNumber
|
||||
);
|
||||
|
||||
if (lineItem.childParts) {
|
||||
addPricesToLineItems(lineItem.childParts, pricingLineItems);
|
||||
}
|
||||
|
||||
const pricedLineItem = pricingLineItems.splice(lineItemIndex, 1)[0];
|
||||
lineItem.laborAmount = pricedLineItem.laborAmount;
|
||||
lineItem.sellingPrice = pricedLineItem.sellingPrice;
|
||||
lineItem.kitPrice = pricedLineItem.kitPrice;
|
||||
lineItem.salesTax = pricedLineItem.salesTax;
|
||||
});
|
||||
|
||||
return lineItems;
|
||||
}
|
||||
|
||||
function addTaxesToPricedLineItems(pricedLineItems, taxingLineItems = []) {
|
||||
pricedLineItems.forEach((pricedLineItem) => {
|
||||
const lineItemIndex = taxingLineItems.findIndex(
|
||||
(taxingLineItem) => taxingLineItem.partNumber === pricedLineItem.partNumber
|
||||
);
|
||||
|
||||
if (pricedLineItem.childParts) {
|
||||
addTaxesToPricedLineItems(pricedLineItem.childParts, taxingLineItems);
|
||||
}
|
||||
|
||||
const taxedLineItem = taxingLineItems.splice(lineItemIndex, 1)[0];
|
||||
pricedLineItem.salesTax = taxedLineItem?.salesTax ?? 0;
|
||||
});
|
||||
|
||||
return pricedLineItems;
|
||||
}
|
||||
|
||||
function getFlattenedArrayOfLineItemsWithChildParts(lineItems, childPartRecursiveCall = false) {
|
||||
let flattenedArray = [];
|
||||
lineItems?.forEach((lineItem) => {
|
||||
|
|
@ -3966,3 +3988,8 @@ function getExternalParameterDefaultState() {
|
|||
function saveExternalParameterState(externalParameterState) {
|
||||
window.sessionStorage.setItem("externalParameterState", JSON.stringify(externalParameterState));
|
||||
}
|
||||
|
||||
const timeSlotCallFlags = {
|
||||
shop: false,
|
||||
mobile: false,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -121,8 +121,8 @@ $body-color: $gray-600;
|
|||
|
||||
//Fonts
|
||||
$font-family-sans-serif: AvertaRegular, Arial, Helvetica, sans-serif;
|
||||
$font-family-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New",
|
||||
monospace;
|
||||
$font-family-monospace:
|
||||
SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
|
||||
// stylelint-enable value-keyword-case
|
||||
$font-family-base: $font-family-sans-serif;
|
||||
$font-family-code: $font-family-monospace;
|
||||
|
|
@ -170,8 +170,7 @@ $spacers: (
|
|||
/* 16px */ 5: $spacer * 1.5,
|
||||
/* 24px */ 6: $spacer * 2,
|
||||
/* 32px */ 7: $spacer * 2.5,
|
||||
/* 40px */ 8: $spacer * 3,
|
||||
/* 48px */
|
||||
/* 40px */ 8: $spacer * 3 /* 48px */,
|
||||
);
|
||||
|
||||
//Enable negative spacing (does NOT work on padding)
|
||||
|
|
|
|||
Loading…
Reference in a new issue