diff --git a/azure-pipelines-automated-testing.yml b/azure-pipelines-automated-testing.yml index 34cda2917..a44bb192d 100644 --- a/azure-pipelines-automated-testing.yml +++ b/azure-pipelines-automated-testing.yml @@ -6,7 +6,7 @@ schedules: branches: include: - develop -pool: 'Default' +pool: 'AmazonLinuxPool' variables: # - group: Digital-Infrastructure diff --git a/playwright-tests/framework/TestPages.ts b/playwright-tests/framework/TestPages.ts index cfc7940bd..e873a1c7b 100644 --- a/playwright-tests/framework/TestPages.ts +++ b/playwright-tests/framework/TestPages.ts @@ -30,6 +30,7 @@ import { VerifyDetailsPage } from "../pages/VerifyDetailsPage" import { EndorsementsPage } from "../pages/EndorsementsPage" import { PolicyDriverPage } from "../pages/PolicyDriverPage" import { ServiceZipPage } from "../pages/ServiceZipPage" +import { MobileDetailsPage } from "pages/MobileDetailsPage"; export interface ITestPages { capabilityQuestionsPage: CapabilityQuestionsPage, @@ -49,6 +50,7 @@ export interface ITestPages { policyVehiclesPage: PolicyVehiclesPage, recalibrationInfoPage: RecalibrationInfoPage, schedulePage: SchedulePage, + mobileDetailsPage: MobileDetailsPage, serviceLocationPage: ServiceLocationPage, servicePackagesPage: ServicePackagesPage, serviceZipPage: ServiceZipPage, @@ -83,6 +85,7 @@ export const createTestPages: TestPagesFactory = (page: Page) => { policyVehiclesPage: new PolicyVehiclesPage(page), recalibrationInfoPage: new RecalibrationInfoPage(page), schedulePage: new SchedulePage(page), + mobileDetailsPage: new MobileDetailsPage(page), serviceLocationPage: new ServiceLocationPage(page), servicePackagesPage: new ServicePackagesPage(page), serviceZipPage: new ServiceZipPage(page), diff --git a/playwright-tests/framework/localTypes/Enums.ts b/playwright-tests/framework/localTypes/Enums.ts index 067011f5e..0ab2796b5 100644 --- a/playwright-tests/framework/localTypes/Enums.ts +++ b/playwright-tests/framework/localTypes/Enums.ts @@ -19,7 +19,8 @@ export enum ProgressBarPercentages { ServicePackagePage = '48%', InsuranceCompanyPage = '52%', ServiceLocationPage = '60%', - SchedulePage = '72%', + SchedulePage = '64%', + MobileDetailsPage = '76%', ContactDetailsPage = '84%', PaymentMethodPage = '92%', OrderConfirmationPage = '100%' diff --git a/playwright-tests/pages/AfterpayPage.ts b/playwright-tests/pages/AfterpayPage.ts index b26949e50..7f54fe336 100644 --- a/playwright-tests/pages/AfterpayPage.ts +++ b/playwright-tests/pages/AfterpayPage.ts @@ -28,7 +28,7 @@ export class AfterpayPage extends BasePage { this.expirationDateTextBox = page.getByTestId('payment-method-cardExpiry-input'); this.cvvTextBox = page.getByTestId('payment-method-cardCvv-input'); - this.confirmButton = page.getByRole('button', { name: 'Confirm' }); + this.confirmButton = page.getByRole('button').filter({hasText: 'Confirm'}); } async login(password: string) { @@ -47,8 +47,6 @@ export class AfterpayPage extends BasePage { async executeAfterpayPayment(paymentDetails: IPaymentDetails) { await this.login(paymentDetails.password!); - await this.populateCardDetails(paymentDetails); - await this.confirmButton.click(); } diff --git a/playwright-tests/pages/BasePage.ts b/playwright-tests/pages/BasePage.ts index 2d8d2b07a..ec6c5d767 100644 --- a/playwright-tests/pages/BasePage.ts +++ b/playwright-tests/pages/BasePage.ts @@ -103,32 +103,31 @@ export class BasePage { } async mockScheduleResponseForEarlyBird(customerDetails: ICustomerDetails) { - { + const apiUrl = `https://digitalapi.${process.env['NODE_ENV']!.replace('sys', 'test').toLowerCase()}.safelite.io/schedule/api/v1/schedule/mobile-time-slots`; await this.page.route(apiUrl, async (route) => { - const response = await route.fetch(); - const responseBody = await response.json(); + const currentDate = new Date().toISOString().split('T')[0]; // e.g., "2025-07-23" + if(route.request().postDataJSON().startDate === currentDate) { + const response = await route.fetch(); + const responseBody = await response.json(); - - responseBody.days.forEach((day: any) => { - day.timeSlots.forEach((slot: any) => { - if (slot.id.includes("AM")) { - slot.offerPremium = true; - } + responseBody.days.forEach((day: any) => { + day.timeSlots.forEach((slot: any) => { + if (slot.id.includes("AM")) { + slot.offerPremium = true; + } + }); }); - }); - customerDetails.apptDate = responseBody.days.find((day: any) => - day.timeSlots.some((slot: any) => slot.offerPremium === true) - ).date || undefined; + customerDetails.apptDate = responseBody.days.find((day: any) => day.timeSlots.some((slot: any) => slot.offerPremium === true)).date || undefined; - // Mock the response - await route.fulfill({ - response, - body: JSON.stringify(responseBody), - }); - }); - } + // Mock the response + await route.fulfill({ + response, + body: JSON.stringify(responseBody), + }); + } + }); } async validateProgressBar(progressPercentage: string, timeout: number = 60000) { diff --git a/playwright-tests/pages/CoverageStatementPage.ts b/playwright-tests/pages/CoverageStatementPage.ts index 032104ec1..af0768951 100644 --- a/playwright-tests/pages/CoverageStatementPage.ts +++ b/playwright-tests/pages/CoverageStatementPage.ts @@ -56,7 +56,7 @@ export class CoverageStatementPage extends InsuranceBasePage { if (await unverifiedDeductibleElement.isVisible() || await this.noCompText.isVisible()) { // Click on continue button if unverified header is visible - await this.continueButton.click(); + // await this.continueButton.click(); } } diff --git a/playwright-tests/pages/MobileDetailsPage.ts b/playwright-tests/pages/MobileDetailsPage.ts new file mode 100644 index 000000000..858e03823 --- /dev/null +++ b/playwright-tests/pages/MobileDetailsPage.ts @@ -0,0 +1,54 @@ +import { type Locator, type Page } from '@playwright/test'; +import { BasePage } from './BasePage'; +import { VehicleLookupType } from 'safelite-playwright-core'; +import { ProgressBarPercentages } from 'framework/localTypes/Enums'; +import { IVehicleDetails } from 'safelite-playwright-core'; +import { VinLookupPage } from './VinLookupPage'; +import { VehicleLookupAddressPage } from './VehicleLookupAddressPage'; +import { VehicleLookupLicensePage } from './VehicleLookupLicensePage'; +import { step } from 'framework/localTypes/Step'; +import { ITestData } from 'framework/TestData'; +import { faker } from '@faker-js/faker'; + +export class MobileDetailsPage extends BasePage { + readonly page: Page; + readonly streetAddressInputBox: Locator; + readonly CityInputBox: Locator; + readonly YesButton: Locator; + readonly NoButton: Locator; + + + constructor(page: Page) { + super(page); + this.page = page; + this.streetAddressInputBox = page.locator('#streetAddress'); + this.CityInputBox = page.locator('#city'); + this.YesButton = page.locator('label[buttonlabel="Yes"]'); + this.NoButton = page.locator('label[buttonlabel="No"]'); + } + + async enterMobileDetails(testData: Partial) { + const { appointmentDetails, customerDetails } = testData; + if (appointmentDetails?.serviceAddress) { + await this.streetAddressInputBox.fill(appointmentDetails.serviceAddress!.street); + await this.CityInputBox.fill(appointmentDetails.serviceAddress!.city); + } + else + { + console.error('ServiceLocationPage >> Please supply an address') + } + + if (faker.datatype.boolean()) { + await this.YesButton.check(); + } else { + await this.NoButton.check(); + } + } + + @step("MobileDetailsPage >> Enter service address: ") + async handleMobileDetailsPage(testData: Partial) { + await this.validateProgressBar(ProgressBarPercentages.MobileDetailsPage); + await this.enterMobileDetails(testData); + await this.nextPage(); + } +} diff --git a/playwright-tests/pages/PaymentMethodPage.ts b/playwright-tests/pages/PaymentMethodPage.ts index 87bf89c5e..2ba68dcc3 100644 --- a/playwright-tests/pages/PaymentMethodPage.ts +++ b/playwright-tests/pages/PaymentMethodPage.ts @@ -206,7 +206,7 @@ export class PaymentMethodPage extends BasePage { break; case PaymentType.AfterPay: await this.payInFourButton.click(); - await this.nextPage(); + await this.continueButton.click(); // Capture popup const afterpayPopup = await browserContext.waitForEvent('page'); diff --git a/playwright-tests/pages/SchedulePage.ts b/playwright-tests/pages/SchedulePage.ts index 0966e9984..d4d00b6f0 100644 --- a/playwright-tests/pages/SchedulePage.ts +++ b/playwright-tests/pages/SchedulePage.ts @@ -1,6 +1,6 @@ import { expect, type Locator, type Page } from '@playwright/test'; import { BasePage } from './BasePage'; -import { IAppointmentDetails } from 'safelite-playwright-core'; +import { IAppointmentDetails, ServiceLocation } from 'safelite-playwright-core'; import { formatDate, formatTime } from 'safelite-playwright-core'; import { AppointmentTimeslot } from 'safelite-playwright-core'; import { ProgressBarPercentages } from 'framework/localTypes/Enums'; @@ -10,6 +10,18 @@ import { ITestData } from 'framework/TestData'; export class SchedulePage extends BasePage { readonly page: Page; + readonly inShopButton: Locator; + readonly mobileButton: Locator; + readonly RecalWarningMessage1: Locator; + readonly RecalWarningMessage2: Locator; + readonly militaryWarningMessage: Locator; + readonly changeZipButton: Locator; + readonly updateZipTextBox: Locator; + readonly saveZipButton: Locator; + readonly changeShopLocationLink: Locator; + readonly selectAShopOptions: Locator; + readonly yourSafeliteShop: Locator; + readonly firstAvailableDate: Locator; readonly firstAvailableTime: Locator; readonly modalContinueButton: Locator; @@ -18,11 +30,28 @@ export class SchedulePage extends BasePage { readonly viewMoreDatesLink: Locator; readonly appointmentDuration: Locator; readonly timeSlots: Locator; + readonly allDayDropOffButton: Locator; + readonly pickATimeButton: Locator; constructor(page: Page) { super(page); this.page = page; - this.firstAvailableDate = this.page.locator('.selectable-day').locator('nth=0'); + + this.inShopButton = this.page.getByText(/In-shop/); + this.mobileButton = this.page.locator('label[buttonlabel="Mobile"]'); + this.RecalWarningMessage1 = this.page.getByText(/We're not able to provide mobile service/); + this.RecalWarningMessage2 = this.page.getByText(/advanced safety system recalibration needs to be done in our shop./); + this.militaryWarningMessage = this.page.locator('[class*="widget-name-AlertMilitaryBaseZipWidget"]'); + this.changeZipButton = this.page.locator('a:has(span.sr-only:has-text("edit zip code"))'); + this.updateZipTextBox = this.page.locator('#serviceZipCode').filter({ visible: true }); + this.saveZipButton = this.page.getByText('Save ZIP code', { exact: true }); + this.changeShopLocationLink = this.page.locator(".shop-question a").filter({ hasText: "Change shop location " }); + this.selectAShopOptions = this.page.locator('[class="shop-question"]'); + this.yourSafeliteShop = this.page.locator("fieldset:has(#chooseShop) label"); + + this.allDayDropOffButton = this.page.locator("label[buttonlabel='Drop off all day']"); + this.pickATimeButton = this.page.locator("label[buttonlabel='Pick a time']"); + this.firstAvailableDate = this.page.locator('.selectable-day').filter({ visible: true}).locator('nth=0'); this.firstAvailableTime = this.page.locator('label').filter({ hasText: /AM|PM/ }).locator('div').locator('nth=0'); this.modalContinueButton = this.page.getByRole('dialog').getByRole('button', { name: 'Continue' }); this.dropOffButton = this.page.getByText('Drop off your vehicle', { exact: true }); @@ -32,6 +61,49 @@ export class SchedulePage extends BasePage { this.timeSlots = this.page.locator('fieldset[aria-labelledby=\'chooseTimeSlot\'] label'); } + async selectLocation(testData: Partial) { + const { appointmentDetails, customerDetails } = testData; + + switch(appointmentDetails?.serviceLocation) { + case ServiceLocation.Mobile: + await this.scheduleMobile(testData); + break; + case ServiceLocation.InShop: + case ServiceLocation.DropOff: + await this.scheduleInShop(appointmentDetails); + break; + } + } + + async scheduleInShop(appointmentDetails?: IAppointmentDetails) { + await this.inShopButton.click(); + if (appointmentDetails && appointmentDetails.shopAddress) { + const zipCodeMatch = appointmentDetails.shopAddress.match(/\b\d{5}$/); + if (zipCodeMatch) { + const zipCode = zipCodeMatch[0]; + // Enter the ZIP code into the updateZipTextBox + await this.changeZipButton.click(); + await this.page.waitForTimeout(500); + await this.updateZipTextBox.fill(zipCode); + await this.saveZipButton.click(); + } + + await this.inShopButton.click(); + // await this.selectAShopOptions.locator(`[buttonbodycopy="${appointmentDetails.shopAddress}"]`).scrollIntoViewIfNeeded().then(() => this.selectAShopOptions.locator(`[buttonbodycopy="${appointmentDetails.shopAddress}"]`).click()); + } + + if (appointmentDetails && (appointmentDetails.shopAddress === "" || appointmentDetails.shopAddress === undefined )) { + appointmentDetails.shopAddress = await this.yourSafeliteShop.getAttribute("buttonbodycopy") || ""; + } + } + + async scheduleMobile(testData: Partial) { + const { appointmentDetails, customerDetails } = testData; + if (appointmentDetails?.serviceAddress) { + await this.mobileButton.click(); + } + } + async scheduleAppointment(appointmentDetails: IAppointmentDetails) { const formattedDate = formatDate(appointmentDetails.appointmentDate!); const formattedTime = formatTime(appointmentDetails.appointmentDate!); @@ -49,26 +121,60 @@ export class SchedulePage extends BasePage { async scheduleFirstAppointment(testData: Partial) { const { appointmentDetails, customerDetails } = testData; + // await this.page.waitForTimeout(1000); + await this.page.waitForSelector('.date-picker', { state: 'visible' }); + await this.page.locator('#date-picker-fieldset .loader').filter({visible: true}).waitFor({ state: 'hidden' }); while (!(await this.firstAvailableDate.isVisible())) { - if (appointmentDetails?.appointmentTimeSlot == AppointmentTimeslot.EarlyBird) { + if (appointmentDetails?.appointmentTimeSlot === AppointmentTimeslot.EarlyBird) { await this.mockScheduleResponseForEarlyBird(customerDetails!); } await this.viewMoreDatesLink.click(); } + switch(appointmentDetails?.serviceLocation) { + case ServiceLocation.InShop: + await this.firstAvailableDate.click().then(async () => { + customerDetails!.apptDate = `${await this.firstAvailableDate.getAttribute("id")}` + }); + if (await this.pickATimeButton.isVisible()) { + await this.pickATimeButton.click(); + } + break; + case ServiceLocation.DropOff: + const inshopAvailableDates = this.page.locator('.selectable-day').filter({ visible: true}).all(); + for (const inshopAvailableDate of await inshopAvailableDates) { + await inshopAvailableDate.click(); + if (await this.allDayDropOffButton.isVisible()) { + customerDetails!.apptDate = `${await inshopAvailableDate.getAttribute("id")}`; + break; + } + } + break; + case ServiceLocation.Mobile: + if (appointmentDetails?.appointmentTimeSlot === AppointmentTimeslot.EarlyBird) { + await this.page.locator(`.selectable-days, [id='${customerDetails?.apptDate}-mobile']`).click(); + } else { + await this.firstAvailableDate.click().then(async () => { + customerDetails!.apptDate = `${await this.firstAvailableDate.getAttribute("id")}`.replace("-mobile", ""); + }); + } + break; + } + if (appointmentDetails?.appointmentTimeSlot == AppointmentTimeslot.EarlyBird) { - await this.page.locator(`.selectable-days, [id='${customerDetails?.apptDate}']`).click(); const earlyBirdTimeSlot = this.timeSlots.filter({ hasText: "Earlybird" }).first(); await earlyBirdTimeSlot.click().then(async () => { customerDetails!.apptTime = await this.getFormattedTimeSlot(earlyBirdTimeSlot); + }) + } + else if (appointmentDetails?.serviceLocation == ServiceLocation.DropOff) + { + await this.allDayDropOffButton.click().then(async () => { + customerDetails!.apptTime = await this.getFormattedTimeSlot(this.allDayDropOffButton); }); } else { - 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); @@ -80,7 +186,6 @@ export class SchedulePage extends BasePage { // appointmentmentDetails.serviceLocation === ServiceLocation.DropOff ? await this.dropOffButton.click() : await this.firstAvailableTime.click(); customerDetails!.apptDuration = (await this.appointmentDuration.innerText()).replace("Duration: ", ""); - await this.nextPage(); } async getFormattedTimeSlot(timeSlot: Locator) { @@ -103,8 +208,10 @@ export class SchedulePage extends BasePage { @step("SchedulePage >> Schedule appointment: ") async handleSchedulePage(testData: Partial) { - + const { appointmentDetails } = testData; await this.validateProgressBar(ProgressBarPercentages.SchedulePage); + await this.selectLocation(testData); await this.scheduleFirstAppointment(testData); + await this.nextPage(); } -} \ No newline at end of file +} diff --git a/playwright-tests/pages/ServicePackagesPage.ts b/playwright-tests/pages/ServicePackagesPage.ts index 71f246da5..34818f285 100644 --- a/playwright-tests/pages/ServicePackagesPage.ts +++ b/playwright-tests/pages/ServicePackagesPage.ts @@ -1,6 +1,6 @@ import { expect, type Locator, type Page } from '@playwright/test'; import { BasePage } from './BasePage'; -import { ServicePackage, VehicleDamage } from 'safelite-playwright-core'; +import { AppointmentTimeslot, ServicePackage, VehicleDamage } from 'safelite-playwright-core'; import { ProgressBarPercentages } from 'framework/localTypes/Enums'; import { PaymentMethod } from "framework/localTypes/Enums"; import { step } from 'framework/localTypes/Step'; @@ -189,7 +189,7 @@ export class ServicePackagesPage extends BasePage { @step("ServicePackagePage >> Select Payment Method and Service Type: ") async handleServicePackagePage(testData: Partial) { - const { customerDetails, paymentMethod, paymentDetails, servicePackage, isCanNotRecal, isDynamicRecal, hasOemEndorsement, vehicleDamage } = testData; + const { customerDetails, paymentMethod, paymentDetails, servicePackage, isCanNotRecal, isDynamicRecal, hasOemEndorsement, vehicleDamage, appointmentDetails } = testData; await this.validateProgressBar(ProgressBarPercentages.ServicePackagePage); // Define repair damage types (vs. replacement types) @@ -235,6 +235,10 @@ export class ServicePackagesPage extends BasePage { if (hasOemEndorsement) { await this.verifyOEMPart(); } + + if (appointmentDetails?.appointmentTimeSlot === AppointmentTimeslot.EarlyBird) { + await this.mockScheduleResponseForEarlyBird(customerDetails!); + } await this.nextPage(); } diff --git a/playwright-tests/tests/0000__M.test.ts b/playwright-tests/tests/0000__M.test.ts index 86cc54c81..204648276 100644 --- a/playwright-tests/tests/0000__M.test.ts +++ b/playwright-tests/tests/0000__M.test.ts @@ -1,5 +1,5 @@ import { Page } from "@playwright/test"; -import { addSmokeTagToRandomTest, Flow } from 'safelite-playwright-core'; +import { addSmokeTagToRandomTest, Flow, ServiceLocation } from 'safelite-playwright-core'; import { ValidationOptions } from 'safelite-playwright-core'; import heavyTruckTests from "./alert-validation/alert0001_HeavyTruck"; import repairAndReplaceTests from "./alert-validation/alert0002_RepairAndReplace"; @@ -288,14 +288,19 @@ async function runWorkflow(page: Page, testCase: TestCase) { //============================= SERVICE SCHEDULING ============================= // Select service location - let serviceLocationPage = testCase.pages.serviceLocationPage; - await serviceLocationPage.handleServiceLocationPage(testCase.testData); + // let serviceLocationPage = testCase.pages.serviceLocationPage; + // await serviceLocationPage.handleServiceLocationPage(testCase.testData); // Schedule appointment let schedulePage = testCase.pages.schedulePage; await schedulePage.handleSchedulePage(testCase.testData); + if (testCase.testData.appointmentDetails?.serviceLocation === ServiceLocation.Mobile) { + let mobileDetailsPage = testCase.pages.mobileDetailsPage; + await mobileDetailsPage.handleMobileDetailsPage(testCase.testData); + } + // Enter contact details let contactDetailsPage = testCase.pages.contactDetailsPage; await contactDetailsPage.handleContactDetailsPage(testCase.testData); @@ -376,12 +381,14 @@ export async function handleInsuranceFlow(testCase: TestCase) { // 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 + // Schedule appointment let schedulePage = testCase.pages.schedulePage; - await schedulePage.nextPage(); + await schedulePage.handleSchedulePage(testCase.testData); + + if (testCase.testData.appointmentDetails?.serviceLocation === ServiceLocation.Mobile) { + let mobileDetailsPage = testCase.pages.mobileDetailsPage; + await mobileDetailsPage.handleMobileDetailsPage(testCase.testData); + } //customer dertails let contactDetailsPage = testCase.pages.contactDetailsPage; await contactDetailsPage.nextPage(); diff --git a/playwright-tests/tests/CashRepairInShopAfterPay.ts b/playwright-tests/tests/CashRepairInShopAfterPay.ts index bd5ff6abd..e328ba7e8 100644 --- a/playwright-tests/tests/CashRepairInShopAfterPay.ts +++ b/playwright-tests/tests/CashRepairInShopAfterPay.ts @@ -31,7 +31,6 @@ const cashRepairInShopAfterPayData : Partial = { // Override appointment details appointmentDetails: { ...getDefaultTestData().appointmentDetails!, - shopAddress: "6826 Sawmill Rd, Columbus, OH 43235" }, // Use predefined payment data diff --git a/playwright-tests/tests/CashReplaceGlassPromoInshop.ts b/playwright-tests/tests/CashReplaceGlassPromoInshop.ts index 8d3679f1b..c7922e144 100644 --- a/playwright-tests/tests/CashReplaceGlassPromoInshop.ts +++ b/playwright-tests/tests/CashReplaceGlassPromoInshop.ts @@ -15,7 +15,17 @@ const cashReplaceGlassPromoInshopData: Partial = { // CASH Client paymentMethod: PaymentMethod.SelfPay, - + + customerDetails: { + ...getDefaultTestData().customerDetails!, + address: { + street: '4076 Spectacle Dr', + city: 'Columbus', + state: 'Ohio', + postalCode: '43235', + } + }, + // Flag for recalibration vehicle isRecalVehicle: true, diff --git a/playwright-tests/tests/CashReplaceMultiSlidingGlassDropoff.ts b/playwright-tests/tests/CashReplaceMultiSlidingGlassDropoff.ts index d2a54d58f..2da4c6f5e 100644 --- a/playwright-tests/tests/CashReplaceMultiSlidingGlassDropoff.ts +++ b/playwright-tests/tests/CashReplaceMultiSlidingGlassDropoff.ts @@ -34,7 +34,8 @@ const cashReplaceMultiSlidingGlassDropoffData: Partial = { // Override for drop-off service appointmentDetails: { serviceLocation: ServiceLocation.DropOff, - appointmentDate: getDefaultTestData().appointmentDetails?.appointmentDate + appointmentDate: getDefaultTestData().appointmentDetails?.appointmentDate, + shopAddress: "6826 Sawmill Rd, Columbus, OH 43235" }, // Override vehicle details diff --git a/playwright-tests/tests/CashReplaceSwitchToInsuranceProgressiveNoComp.ts b/playwright-tests/tests/CashReplaceSwitchToInsuranceProgressiveNoComp.ts index a6494792a..91e997986 100644 --- a/playwright-tests/tests/CashReplaceSwitchToInsuranceProgressiveNoComp.ts +++ b/playwright-tests/tests/CashReplaceSwitchToInsuranceProgressiveNoComp.ts @@ -1,9 +1,10 @@ //Imports here import { ITestData } from 'framework/TestData' -import { ServiceLocation } from "safelite-playwright-core"; +import { Flow, 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'; +import { PaymentMethod } from 'framework/localTypes/Enums'; // Set the seed for consistent data generation setFakerSeedFromTestName("CashReplaceSwitchToInsuranceProgressiveNoComp"); @@ -13,6 +14,10 @@ const cashReplaceSwitchToInsuranceProgressiveNoCompData: Partial = { ...getDefaultTestData(), isCashInsuranceFlow: true, + flow: Flow.Managed, + + // CASH Client + paymentMethod: PaymentMethod.SelfPay, // Override customer details based on provided ZIP code customerDetails: { diff --git a/playwright-tests/tests/CashReplaceWiperDropoff.ts b/playwright-tests/tests/CashReplaceWiperDropoff.ts index 695eaba9a..8080603f6 100644 --- a/playwright-tests/tests/CashReplaceWiperDropoff.ts +++ b/playwright-tests/tests/CashReplaceWiperDropoff.ts @@ -48,7 +48,8 @@ const cashReplaceWiperDropoffData: Partial = { // Override for drop-off service appointmentDetails: { serviceLocation: ServiceLocation.DropOff, - appointmentDate: getDefaultTestData().appointmentDetails?.appointmentDate + appointmentDate: getDefaultTestData().appointmentDetails?.appointmentDate, + shopAddress: "6826 Sawmill Rd, Columbus, OH 43235" }, // Payment at service diff --git a/src/layouts/schedule/schedule.vue b/src/layouts/schedule/schedule.vue index 6b214f2e2..0e68cb458 100644 --- a/src/layouts/schedule/schedule.vue +++ b/src/layouts/schedule/schedule.vue @@ -1169,7 +1169,7 @@ export default { if (this.preSelectedDate) this.selectedDate = this.preSelectedDate; - if (!this.selectedDate) { + if (!this.preSelectedDate) { // if no date is preselected on load, then select the first available let selectedDateMobile = this.getSelectedDateForMobile(); let selectedDateInshop = this.getSelectedDateForInshop(); @@ -1656,6 +1656,17 @@ export default { AppointmentTypeStrings.IN_SHOP_OR_DROP_OFF) && this.selectedProvider ) { + this.selectedTimeSlotInfo = { + timeSlot: { + date: null, + routeCode: null, + startTime: null, + endTime: null, + jobMaxMinutes: null, + jobMinMinutes: null, + }, + isPremiumAppointment: null, + }; this.lastSelectedInshopOrDropoffProvider = this.selectedProvider; } this.appointmentType = AppointmentTypeStrings.MOBILE; diff --git a/src/layouts/schedule/time-slot-question/time-slot-question.vue b/src/layouts/schedule/time-slot-question/time-slot-question.vue index df37d4e09..3c83bd039 100644 --- a/src/layouts/schedule/time-slot-question/time-slot-question.vue +++ b/src/layouts/schedule/time-slot-question/time-slot-question.vue @@ -187,10 +187,14 @@ export default { let appointmentTypeCmsWidgetName; if ( + this.selectedDate == null || this.appointmentType === AppointmentTypeStrings.IN_SHOP_OR_DROP_OFF || this.appointmentType === AppointmentTypeStrings.IN_SHOP || this.appointmentType === AppointmentTypeStrings.DROP_OFF ) { + if (!this.selectedAnswerForTimeSlots && !this.selectedAnswerForDropOffOrInshop) { + this.autoSelectTimeSlotIfOnlyOneIsAvailable(); + } return null; // This is planned to be used again for drop-off // Wrote this to be ready for that eventuality, is untested and no HTML work done yet @@ -205,6 +209,10 @@ export default { // ); // } } else { + if (!this.selectedAnswerForTimeSlots && this.selectedRouteCode) { + // Clearing selectedRouteCode if no time slot is selected + this.resetSelectedTimeSlot(); + } appointmentTypeCmsWidgetName = this.selectedRouteCode?.includes( PREMIUM_TIME_SLOT_ID_FLAG ) @@ -394,6 +402,8 @@ export default { this.setSelectedRouteCodeFromParent(); }, async setSelectedTimeSlot() { + this.selectedRouteCode = + this.selectedAnswerForTimeSlots || this.selectedAnswerForDropOffOrInshop; this.$emit( "update:modelValue", this.getSelectedTimeSlotInfoObject(this.selectedRouteCode) @@ -483,12 +493,13 @@ export default { }, autoSelectTimeSlotIfOnlyOneIsAvailable() { const numberOfOptions = this.timeSlotsForSelectedDate?.timeSlots?.length; - if (numberOfOptions === 1) { + if (this.appointmentType && numberOfOptions === 1) { if (this.availableTimeSlots.length > 0) { this.selectedAnswerForTimeSlots = this.availableTimeSlots[0].value; } else { this.selectedAnswerForDropOffOrInshop = this.answersForDropOffQuestion[0].value; } + this.setSelectedTimeSlot(); } }, addPremiumFlagToInput(routeCode) {