diff --git a/playwright-tests/framework/TestData.ts b/playwright-tests/framework/TestData.ts index 9ed648426..1af123c41 100644 --- a/playwright-tests/framework/TestData.ts +++ b/playwright-tests/framework/TestData.ts @@ -3,7 +3,8 @@ import { PaymentMethod } from './localTypes/Enums' export interface ITestData extends base { // Put any project-specific data here. Anything useful to other Safelite projects should be submitted as a pull request to safelite-playwright-core. - paymentMethod: PaymentMethod - isOptedInForTextMessages: boolean - totalAmount?: number + paymentMethod: PaymentMethod, + isOptedInForTextMessages: boolean, + totalAmount?: number, + isForcedOEM?: boolean } \ No newline at end of file diff --git a/playwright-tests/framework/TestPages.ts b/playwright-tests/framework/TestPages.ts index e873a1c7b..c2cc04b35 100644 --- a/playwright-tests/framework/TestPages.ts +++ b/playwright-tests/framework/TestPages.ts @@ -24,6 +24,7 @@ import { CCPolicyInfoPage } from "../pages/CCPolicyInfoPage" import { DuplicateCheckPage } from "../pages/DuplicateCheckPage" import { PolicyVehiclesPage } from "../pages/PolicyVehiclesPage" import { PolicyInfoSubmittedPage } from "../pages/PolicyInfoSubmittedPage" +import { HeritageProblemGlassQuestionsPage } from "../pages/HeritageProblemGlassQuestionsPage" import RecalibrationInfoPage from "../pages/RecalibrationInfoPage" import { CoverageStatementPage } from "../pages/CoverageStatementPage" import { VerifyDetailsPage } from "../pages/VerifyDetailsPage" @@ -48,6 +49,7 @@ export interface ITestPages { paymentMethodPage: PaymentMethodPage, policyInfoSubmittedPage: PolicyInfoSubmittedPage, policyVehiclesPage: PolicyVehiclesPage, + heritageProblemGlassQuestionsPage: HeritageProblemGlassQuestionsPage, recalibrationInfoPage: RecalibrationInfoPage, schedulePage: SchedulePage, mobileDetailsPage: MobileDetailsPage, @@ -83,6 +85,7 @@ export const createTestPages: TestPagesFactory = (page: Page) => { paymentMethodPage: new PaymentMethodPage(page), policyInfoSubmittedPage: new PolicyInfoSubmittedPage(page), policyVehiclesPage: new PolicyVehiclesPage(page), + heritageProblemGlassQuestionsPage: new HeritageProblemGlassQuestionsPage(page), recalibrationInfoPage: new RecalibrationInfoPage(page), schedulePage: new SchedulePage(page), mobileDetailsPage: new MobileDetailsPage(page), diff --git a/playwright-tests/pages/BasePage.ts b/playwright-tests/pages/BasePage.ts index 6596986df..1562677a2 100644 --- a/playwright-tests/pages/BasePage.ts +++ b/playwright-tests/pages/BasePage.ts @@ -169,4 +169,20 @@ export class BasePage { Soft.expect(actualProgressPercentage).toBe(progressPercentage); console.log(`Progress Bar Percentage: Actual - ${actualProgressPercentage} vs Expected - ${progressPercentage}`); } + + async validateOEMPart( isOEM: boolean): Promise { + if (isOEM!) { + // Get Vuex state from localStorage + const vuexState = JSON.parse(await this.page.evaluate('localStorage.getItem(\'vuex\')')); + + // Validate the presence of an OEM part + if (vuexState.order?.lineItems?.glassParts?.length > 0) { + const firstGlassPartNumber = vuexState.order.lineItems.glassParts[0].partNumber; + + await expect(firstGlassPartNumber.includes("OEM")).toBe(true); + } else { + throw new Error("No glass parts found in the order"); + } + } + } } \ No newline at end of file diff --git a/playwright-tests/pages/HeritageProblemGlassQuestionsPage.ts b/playwright-tests/pages/HeritageProblemGlassQuestionsPage.ts new file mode 100644 index 000000000..097fd5200 --- /dev/null +++ b/playwright-tests/pages/HeritageProblemGlassQuestionsPage.ts @@ -0,0 +1,42 @@ +import { expect, type Locator, type Page } from '@playwright/test'; +import { InsuranceBasePage } from './InsuranceBasePage'; +import { ITestData } from 'framework/TestData'; +import { step } from 'framework/localTypes/Step'; + +export class HeritageProblemGlassQuestionsPage extends InsuranceBasePage { + readonly provideVinManuallyButton: Locator; + readonly provideLicensePlateButton: Locator; + readonly provideHomeAddressButton: Locator; + readonly continueOnVinPopUpButton: Locator; + readonly dontShareVinButton: Locator; + + readonly yestoGlassQuestionButton: Locator; + readonly notoGlassQuestionButton: Locator; + readonly continueButton: Locator; + + + constructor(page: Page) { + super(page); + + this.provideVinManuallyButton = page.locator('label[for="VINManually"]'); + this.provideLicensePlateButton = page.locator('label[for="licensePlate"]'); + this.provideHomeAddressButton = page.locator('label[for="HomeAddress"]'); + this.continueOnVinPopUpButton = page.locator('button:has-text("Continue")'); + this.dontShareVinButton = page.getByRole('button', { name: "I would rather not share my VIN" }); + + this.yestoGlassQuestionButton = page.locator('label:has-text("Yes")'); + this.notoGlassQuestionButton = page.locator('label:has-text("No")'); + this.continueButton = page.locator('button[type="submit"].btn-success.nav-continue'); + + } + + + @step("HeritageProblemGlassQuestionsPage >> Handle VIN popup and answer glass question on heritage") + // Handles OEM scenario with vehicle that has only one glass question + async handleHeritageProblemGlassQuestionsPage(testData: Partial){ + + await this.dontShareVinButton.click(); + await this.yestoGlassQuestionButton.click(); + await this.continueButton.click(); + } +} \ No newline at end of file diff --git a/playwright-tests/pages/OrderConfirmationPage.ts b/playwright-tests/pages/OrderConfirmationPage.ts index 02951bdd2..a65c80fd2 100644 --- a/playwright-tests/pages/OrderConfirmationPage.ts +++ b/playwright-tests/pages/OrderConfirmationPage.ts @@ -47,7 +47,7 @@ export class OrderConfirmationPage extends BasePage { async validateOrderConfirmationPage(testData: Partial) { // Destructure data we use const { vehicleDetails, customerDetails, servicePackage, isCashInsuranceFlow, - isPolicyFound, claimDetails, paymentDetails, isUseVehicleOnPolicy, paymentMethod, isPolicyUnverified } = testData; + isPolicyFound, claimDetails, paymentDetails, isUseVehicleOnPolicy, paymentMethod, isPolicyUnverified} = testData; await this.serviceText.waitFor({ state: "visible" }); Soft.expect((await this.getActualAppointmentSummary()).map(item => item.toLowerCase())).toEqual((await this.getExpectedAppointmentSummary(testData)).map(item => item.toLowerCase())); diff --git a/playwright-tests/pages/PaymentMethodPage.ts b/playwright-tests/pages/PaymentMethodPage.ts index 4ea1a8b82..015a088ae 100644 --- a/playwright-tests/pages/PaymentMethodPage.ts +++ b/playwright-tests/pages/PaymentMethodPage.ts @@ -499,12 +499,16 @@ export class PaymentMethodPage extends BasePage { @step("PaymentMethodPage >> Select Payment Method: ") async handlePaymentMethodPage(testData: Partial) { - const { servicePackage, isRecalVehicle, paymentDetails } = testData; + const { servicePackage, isRecalVehicle, paymentDetails, isForcedOEM } = testData; await this.validateProgressBar(ProgressBarPercentages.PaymentMethodPage); await this.validatePaymentDetailsPage(testData); await this.ValidateAfterPayBreakOutSection(); + if (isForcedOEM){ + await this.validateOEMPart(isForcedOEM); + } + // Verify VAPS wipers on backend for standard and premium packages if (servicePackage === ServicePackage.Standard || servicePackage === ServicePackage.Premium) { await this.verifyVAPS(); diff --git a/playwright-tests/pages/ServicePackagesPage.ts b/playwright-tests/pages/ServicePackagesPage.ts index 63a60a6e6..ba95f67cd 100644 --- a/playwright-tests/pages/ServicePackagesPage.ts +++ b/playwright-tests/pages/ServicePackagesPage.ts @@ -44,7 +44,7 @@ export class ServicePackagesPage extends BasePage { this.promoCodeTextbox = this.page.getByLabel('Enter a promo code'); this.applyPromoButton = this.page.getByRole('button', { name: 'Apply promo code' }); this.repeatedClicksModalCloseButton = this.page.locator('.QSISlider').locator('img[src*=\'close\']'); - this.afterPayBanner = this.page.locator('#afterpay-banner'); + this.afterPayBanner = this.page.locator('div.afterpay-modal-banner'); this.glassOnlypackagePrice = this.page.locator('fieldset:has(legend#ServicePackageQuestion) label').filter({ hasText: 'Glass service only' }).locator('.pricing-info'); } diff --git a/playwright-tests/tests/0000__M.test.ts b/playwright-tests/tests/0000__M.test.ts index c8788b04a..cd8270a8a 100644 --- a/playwright-tests/tests/0000__M.test.ts +++ b/playwright-tests/tests/0000__M.test.ts @@ -28,6 +28,7 @@ import insuranceITAC21stCenturyTests from "./InsuranceITAC21stCentury"; import insuranceGeicoTests from "./InsuranceGeico"; import insuranceITACOptimizedPriceValidationAllStateTests from "./InsuranceITACOptimizedPriceValidationAllState"; import insuranceNoCompProgressiveTests from "./InsuranceNoCompProgressive"; +import insuranceOEMAllstateTests from "./InsuranceOEMAllState"; import cashRepairInShopAfterPayTests from "./CashRepairInShopAfterPay"; import cashRepairInShopPayPalTests from "./CashRepairInShopPayPal"; import cashReplaceMultiSlidingGlassDropoffTests from "./CashReplaceMultiSlidingGlassDropoff"; @@ -82,6 +83,7 @@ const allStandardTests = [ {name: "InsuranceITAC21stCentury", tests: insuranceITAC21stCenturyTests}, {name: "InsuranceNoCompProgressive", tests: insuranceNoCompProgressiveTests}, // {name: "InsuranceBigTruckVerified", tests: insuranceBigTruckVerifiedTests}, + {name: "InsuranceOEMAllstate", tests: insuranceOEMAllstateTests}, {name: "InsuranceUnverified", tests: insuranceUnverifiedTests}, // {name: "InsuranceGeico", tests: insuranceGeicoTests}, // {name: "InsuranceITACOptimizedPriceValidationAllState", tests: insuranceITACOptimizedPriceValidationAllStateTests} @@ -323,7 +325,7 @@ async function runWorkflow(page: Page, testCase: TestCase) { } export async function handleInsuranceFlow(testCase: TestCase) { - const { isPolicyFound, isPolicyDriver, endorsements, isRecalVehicle, isCashInsuranceFlow, flow } = testCase.testData; + const { isPolicyFound, isPolicyDriver, endorsements, isRecalVehicle, isCashInsuranceFlow, isForcedOEM, flow } = testCase.testData; // Check if the insurance policy has endorsements const hasEndorsements = endorsements && endorsements.length > 0; @@ -332,6 +334,13 @@ export async function handleInsuranceFlow(testCase: TestCase) { let insuranceCompanyPage = testCase.pages.insuranceCompanyPage; await insuranceCompanyPage.handleInsuranceCompanyPage(testCase.testData); + // Handle OEM scenario + if (isForcedOEM) { + // User should be on heritage problem glass questions page after selecting Allstate on insurance company page + let HeritageProblemGlassQuestionsPage = testCase.pages.heritageProblemGlassQuestionsPage; + await HeritageProblemGlassQuestionsPage.handleHeritageProblemGlassQuestionsPage(testCase.testData); + } + // Handle ccPolicyInfoPage let ccPolicyInfoPage = testCase.pages.ccPolicyInfoPage; await ccPolicyInfoPage.handleCCPolicyInfoPage(testCase.testData); diff --git a/playwright-tests/tests/InsuranceOEMAllState.ts b/playwright-tests/tests/InsuranceOEMAllState.ts new file mode 100644 index 000000000..c55939a4c --- /dev/null +++ b/playwright-tests/tests/InsuranceOEMAllState.ts @@ -0,0 +1,88 @@ +//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("InsuranceOEMAllstate"); + +// Now get the test data with the seeded faker +const insuranceOEMAllstateData: Partial = { + ...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, + isForcedOEM: true, + + // Override customer details with specific name and California location + customerDetails: { + ...getDefaultTestData().customerDetails!, + firstName: 'Jane', + lastName: 'OEMTest', + address: { + ...getDefaultTestData().customerDetails!.address, + city: 'Richmond', + state: 'Virginia', + postalCode: '23219' + } + }, + + + // Insurance claim details + claimDetails: { + client: 'Allstate', + policyNumber: 'MockOEMTest', + policyDeductible: "Unverified", + policyZip: '43085', + 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: '2024', + make: 'Jeep', + model: 'Wrangler', + 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: '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 insuranceOEMAllstateTests: ITestCase[] = []; + +const tc = { + name: `InsuranceOEMAllstate`, + tags: ['@E2E','@InsuranceOEMAllstate', '@test_report', '@Insurance'], + testData: insuranceOEMAllstateData +}; +insuranceOEMAllstateTests.push(tc); + +export default insuranceOEMAllstateTests; \ No newline at end of file