import TestCase from "@business-logic/types/TestCase"; import { Page } from "@playwright/test"; import { addSmokeTagToRandomTest, prepareTest, test, TestInfo } from "@business-logic/types/Test"; import { RuleEngine, ValidationOptions } from "@business-logic/types/RuleEngine"; import heavyTruckTests from "./alert-validation/alert0001_HeavyTruck"; import repairAndReplaceTests from "./alert-validation/alert0002_RepairAndReplace"; import splitWindshieldTests from "./alert-validation/alert0003_SplitWindshield"; import repairOnlyTests from "./alert-validation/alert0004_RepairOnly"; import unserviceableZipTests from "./alert-validation/alert0005_UnserviceableZip"; import invalidZipTests from "./alert-validation/alert0006_InvalidZip"; import vinNotFoundTests from "./alert-validation/alert0007_VinNotFound"; import TestSuccessAlert from "@business-logic/types/TestSuccessAlert"; import { AppointmentType, PaymentMethod, ServicePackage, VehicleLookupType, VehicleDamage, PaymentType } from "@business-logic/types/Enums"; import cashRepairMobileCCTests from "./CashRepairMobileCreditCard"; import cashReplaceDynamicRecalMobileTests from "./CashReplaceDynamicRecalMobile"; import cashReplaceGlassAddressLookupInshopAfterPayTests from "./CashReplaceGlassAddressLookupInshopAfterPay"; import cashReplaceGlassLicensePlateLookupInshopPaypalTests from "./CashReplaceGlassLicensePlateLookupInshopPaypal"; import ApiResponseInterceptUtil from "@impl/API/ApiResponseInterceptUtil"; import cashReplaceGlassPromoInshopTests from "./CashReplaceGlassPromoInshop"; import cashReplaceMultiGlassPromoInshopTests from "./CashReplaceMultiGlassPromoInshop"; import cashReplaceRainDefensePromoInshopTests from "./CashReplaceRainDefensePromoInshop"; import cashReplaceSafeliteCanNotRecalMobileTests from "./CashReplaceSafeliteCanNotRecalMobile"; import cashReplaceVinMobileTests from "./CashReplaceVinMobile"; import cashReplaceWiperDropoffTests from "./CashReplaceWiperDropoff"; import cashReplaceWiperPromoInShopTests from "./CashReplaceWiperPromoInshop"; import insuranceAcuityPaypalTests from "./InsuranceAcuityPaypal"; import insuranceITAC21stCenturyTests from "./InsuranceITAC21stCentury"; import insuranceGeicoTests from "./InsuranceGeico"; import insuranceITACOptimizedPriceValidationAllStateTests from "./InsuranceITACOptimizedPriceValidationAllState"; import cashRepairInShopAfterPayTests from "./CashRepairInShopAfterPay"; import cashRepairInShopPayPalTests from "./CashRepairInShopPayPal"; import cashReplaceMultiSlidingGlassDropoffTests from "./CashReplaceMultiSlidingGlassDropoff"; import cashReplaceMultiGlassMobileTests from "./CashReplaceMultiGlassMobile"; import cashReplaceSwitchToInsuranceProgressiveNoCompTests from "./CashReplaceSwitchToInsuranceProgressiveNoComp"; import insuranceBigTruckVerifiedTests from "./InsuranceBigTruckVerified"; import insuranceUnverifiedTests from "./InsuranceUnverified"; /** * Master Test Runner * * This file orchestrates the execution of all test scenarios and defines the primary test workflow. * It imports all test cases and executes them through a common test runner function to ensure * consistent behavior across different test scenarios. */ // Initialize shared rule engine and validation options const ruleEngine = new RuleEngine(); const options = new ValidationOptions(); // Add smoke tag to selected tests for CI/CD pipelines addSmokeTagToRandomTest(splitWindshieldTests); // Standard test scenarios const allStandardTests = [ {name: "CashRepairMobileCreditCard", tests: cashRepairMobileCCTests}, {name: "CashRepairInShopAfterPay", tests: cashRepairInShopAfterPayTests}, {name: "CashRepairInShopPayPal", tests: cashRepairInShopPayPalTests}, {name: "CashReplaceDynamicRecalMobile", tests: cashReplaceDynamicRecalMobileTests}, {name: "CashReplaceGlassAddressLookupInshopAfterPay", tests: cashReplaceGlassAddressLookupInshopAfterPayTests}, {name: "CashReplaceGlassLicensePlateLookupInshopPaypal", tests: cashReplaceGlassLicensePlateLookupInshopPaypalTests}, {name: "CashReplaceGlassPromoInShop", tests: cashReplaceGlassPromoInshopTests}, {name: "CashReplaceMultiGlassPromoInShop", tests: cashReplaceMultiGlassPromoInshopTests}, {name: "CashReplaceMultiSlidingGlassDropoff",tests: cashReplaceMultiSlidingGlassDropoffTests}, {name: "CashReplaceMultiGlassMobile",tests: cashReplaceMultiGlassMobileTests}, {name: "CashReplaceRainDefensePromoInshop", tests: cashReplaceRainDefensePromoInshopTests}, {name: "CashReplaceSafeliteCanNotRecalMobile", tests: cashReplaceSafeliteCanNotRecalMobileTests}, {name: "CashReplaceVinMobile", tests: cashReplaceVinMobileTests}, {name: "CashReplaceWiperDropoff", tests: cashReplaceWiperDropoffTests}, {name: "CashReplaceWiperPromoInshop", tests: cashReplaceWiperPromoInShopTests}, {name: "InsuranceAcuityPaypal", tests: insuranceAcuityPaypalTests}, {name: "InsuranceITAC21stCentury", tests: insuranceITAC21stCenturyTests}, {name: "CashReplaceSwitchToInsuranceProgressiveNoComp", tests: cashReplaceSwitchToInsuranceProgressiveNoCompTests}, {name: "InsuranceBigTruckVerified", tests: insuranceBigTruckVerifiedTests}, {name: "InsuranceUnverified", tests: insuranceUnverifiedTests}, // {name: "InsuranceGeico", tests: insuranceGeicoTests}, // {name: "InsuranceITACOptimizedPriceValidationAllState", tests: insuranceITACOptimizedPriceValidationAllStateTests} ]; // Alert validation scenarios const allAlertTests = [ { 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 4: Repair Only", tests: repairOnlyTests }, { name: "Alert Scenario 5: Unserviceable Zip", tests: unserviceableZipTests }, { name: "Alert Scenario 6: Invalid Zip", tests: invalidZipTests }, { name: "Alert Scenario 7: VIN Not Found", tests: vinNotFoundTests } ]; // Standard test cases test.describe.parallel('Standard E2E Test Flows', () => { allStandardTests.forEach(scenario => { scenario.tests.forEach(testCase => { test(...prepareTest(testCase, run, options, ruleEngine)); }); }); }); // Alert validation test cases test.describe.parallel('Alert Validation Tests', () => { allAlertTests.forEach(scenario => { test.describe(scenario.name, () => { scenario.tests.forEach(testCase => { test(...prepareTest(testCase, run, options, ruleEngine)); }); }); }); }); /** * After each test, capture screenshot and handle cleanup */ test.afterEach(async ({ page, testInfo }) => { await TestCase.afterEachMethod(page, testInfo); }); /** * Main test runner function that executes each test case * @param page - The Playwright page object * @param testInfo - Test information and context */ async function run(page: Page, testInfo: TestInfo): Promise { try { await testInfo.testCase.setup(); testInfo.testCase.setupPages(page); await testInfo.testCase.pages.homePage.goto(); await runWorkflow(page, testInfo.testCase); } catch (error) { // Catch successful alert tests and log message if (error instanceof TestSuccessAlert) { console.log(error.message); // Catch and throw other errors } else { throw error; } } } /** * Main workflow that executes the test steps in sequence * * This function contains the common test flow for all test scenarios: * 1. Start at home page and enter vehicle/damage information * 2. Select lookup method and provide details * 3. Answer part questions if applicable * 4. Select service package and payment method * 5. Handle insurance flow if applicable * 6. Select service location and schedule appointment * 7. Complete order and validate confirmation * * @param page - The Playwright page object * @param testCase - The test case to execute */ async function runWorkflow(page: Page, testCase: TestCase) { // Intercept API Responses const apiResponseInterceptUtil = new ApiResponseInterceptUtil(testCase.testData); page.on('response', apiResponseInterceptUtil.handleInterceptResponse); // Destructure test data for easier access const { paymentMethod, customerDetails, vehicleDetails, vehicleDamage, paymentDetails, partQuestions, enterFunnelWithZip, capabilityQuestions, vehiclePartQuestions, moldingQuestions, skipEstimatePage } = testCase.testData; // Check if the vehicle damage includes a windshield crack const hasWindshieldCrack = vehicleDamage!.some(damage => damage === VehicleDamage.WindshieldCrack ); //============================= TEST WORKFLOW STEPS ============================= // Use Environment Variable to decide whether or not we want to skip content site aka home page if (process.env.SKIP_CONTENT_SITE == "false") { await test.step('HomePage >> Lets Get Started', async () => { let homePage = testCase.pages.homePage; console.log(`Customer for this test: ${customerDetails?.firstName} ${customerDetails?.lastName}`); await homePage.letsGetStarted(customerDetails?.address.postalCode!, !!enterFunnelWithZip!); }); } else { // If enterFunnelWithZip is true, add zip code to url if (!!enterFunnelWithZip!) { const currentUrl = page.url(); const zipParam = `&zipCode=${customerDetails?.address.postalCode!}`; if (!currentUrl.includes('zipCode=')) { await page.goto(currentUrl + zipParam); } } 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); // 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); // Handle different vehicle lookup methods switch (vehicleDetails!.vehicleLookupType!) { case VehicleLookupType.Address: let vehicleLookupAddressPage = testCase.pages.vehicleLookupAddressPage; await vehicleLookupAddressPage.handleVehicleLookupAddressPage(testCase.testData); break; case VehicleLookupType.LicensePlateNumber: let vehicleLookupLicensePage = testCase.pages.vehicleLookupLicensePage; await vehicleLookupLicensePage.handleVehicleLookupLicensePage(testCase.testData); break; case VehicleLookupType.Vin: let vinLookupPage = testCase.pages.vinLookupPage; await vinLookupPage.handleVehicleLookupVinPage(testCase.testData); break; case VehicleLookupType.Zip: let serviceZipPage = testCase.pages.serviceZipPage; await serviceZipPage.handleServiceZipPage(testCase.testData); break; } } else { // Otherwise just use zip lookup for service zip page let serviceZipPage = testCase.pages.serviceZipPage; await serviceZipPage.handleServiceZipPage(testCase.testData); } // Handle part questions if applicable if (partQuestions && partQuestions.length > 0) { let partQuestionsPage = testCase.pages.partQuestionsPage; await partQuestionsPage.handlePartQuestionsPage(testCase.testData); } // Handle molding questions if applicable if (moldingQuestions && moldingQuestions.length > 0) { let moldingQuestionsPage = testCase.pages.moldingQuestionsPage; await moldingQuestionsPage.handleMoldingQuestionsPage(testCase.testData); } // Handle vehicle part questions if applicable if (vehiclePartQuestions && vehiclePartQuestions.length > 0) { let vehiclePartsPage = testCase.pages.vehiclePartsPage; await vehiclePartsPage.handleVehiclePartsPage(testCase.testData); } // Handle capability questions if applicable if (capabilityQuestions && capabilityQuestions.length > 0) { let capabilityQuestionsPage = testCase.pages.capabilityQuestionsPage; await capabilityQuestionsPage.handleCapabilityQuestionsPage(testCase.testData); } // Select service package and payment method let servicePackagesPage = testCase.pages.servicePackagesPage; await servicePackagesPage.handleServicePackagePage(testCase.testData); //============================= INSURANCE FLOW =============================` // Insurance flow - if user selected Insurance as Payment Method if (paymentMethod == PaymentMethod.Insurance) { await handleInsuranceFlow(testCase); } //============================= SERVICE SCHEDULING ============================= // Select service location let serviceLocationPage = testCase.pages.serviceLocationPage; await serviceLocationPage.handleServiceLocationPage(testCase.testData); // Schedule appointment let schedulePage = testCase.pages.schedulePage; await schedulePage.handleSchedulePage(testCase.testData); // Enter contact details let contactDetailsPage = testCase.pages.contactDetailsPage; await contactDetailsPage.handleContactDetailsPage(testCase.testData); //============================= PAYMENT PROCESSING ============================= // Handle payment let paymentMethodPage = testCase.pages.paymentMethodPage; await paymentMethodPage.handlePaymentMethodPage(testCase.testData); // If user selected Pay with Insurance as Payment Method, Enter Insurance Flow if (paymentDetails?.paymentType === PaymentType.PayWithInsurance) { await handleInsuranceFlow(testCase); } //============================= ORDER CONFIRMATION ============================= // Validate order confirmation let orderConfirmationPage = testCase.pages.orderConfirmationPage; await orderConfirmationPage.verifyOrderConfirmationPage(testCase.testData); } export async function handleInsuranceFlow(testCase: TestCase) { const { isPolicyFound, isPolicyDriver, endorsements, isRecalVehicle, isCashToInsurance: isCashInsuranceFlow } = 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(isRecalVehicle) { let recalibrationInfoPage = testCase.pages.recalibrationInfoPage; await recalibrationInfoPage.handleRecalibrationInfoPage(); } //handle coveraage statement page let coverageStatementPage = testCase.pages.coverageStatementPage; await coverageStatementPage.handleCoverageStatementPage(testCase.testData); 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(); } }