diff --git a/jest.config.js b/jest.config.js index 0cc955a8c..b192b8784 100644 --- a/jest.config.js +++ b/jest.config.js @@ -43,7 +43,7 @@ module.exports = { testMatch: ["**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)"], coverageThreshold: { global: { - statements: 66, + statements: 64, }, }, // Uncomment this to avoid the massive amount of warnings we are getting for onSubmit and onInvalidSubmit 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/constants/progress-bar-mapper.js b/src/constants/progress-bar-mapper.js index f177b6cf7..7947f6817 100644 --- a/src/constants/progress-bar-mapper.js +++ b/src/constants/progress-bar-mapper.js @@ -1,35 +1,35 @@ export const pageProgressMapper = { //Combine progress bar slide percent and button steps vehicle: { - percent: 7, - step: 1, - }, - "vehicle-damage": { percent: 10, step: 1, }, - estimate: { + "vehicle-damage": { percent: 14, step: 1, }, - "service-zip": { + estimate: { percent: 18, step: 1, }, + "service-zip": { + percent: 22, + step: 1, + }, "vin-lookup": { - percent: 18, + percent: 22, step: 1, }, "license-plate-lookup": { - percent: 18, + percent: 22, step: 1, }, "address-lookup": { - percent: 18, + percent: 22, step: 1, }, "address-vehicles": { - percent: 25, + percent: 26, step: 1, }, "part-questions": { @@ -49,7 +49,7 @@ export const pageProgressMapper = { step: 1, }, quote: { - percent: 39, //Must be 39 + percent: 39, //The first Step 2 must be 39 so the animated bar lines up with the dot step: 2, }, "insurance-company": { @@ -61,7 +61,7 @@ export const pageProgressMapper = { step: 2, }, schedule: { - percent: 70.5, //Must be 70.5 + percent: 70.5, //The first Step 3 must be 70.5 so the animated bar lines up with the dot step: 3, }, "mobile-details": { @@ -73,7 +73,7 @@ export const pageProgressMapper = { step: 3, }, "payment-method": { - percent: 92, //Must be 92 + percent: 92, //The first Step 4 must be 92 so the animated bar lines up with the dot step: 3, }, payment: { diff --git a/src/digital-components/date-picker/date-picker.vue b/src/digital-components/date-picker/date-picker.vue index 72bdcb093..fa8c9d218 100644 --- a/src/digital-components/date-picker/date-picker.vue +++ b/src/digital-components/date-picker/date-picker.vue @@ -7,7 +7,6 @@ @@ -1027,6 +1026,10 @@ export default { display: flex; flex-direction: column; + .duration-text-block { + text-align: left; + } + .date-picker-header { margin-bottom: 1.5rem; } @@ -1050,7 +1053,6 @@ export default { } .calendar-grid-container { margin: 0 auto 1rem auto; - max-width: 360px; position: relative; transition: height ease 2s, @@ -1188,8 +1190,6 @@ export default { display: flex; justify-content: center; align-items: center; - min-width: 2.5rem; - width: 2.5rem; height: 2.5rem; border: 2px solid transparent; @@ -1227,14 +1227,8 @@ export default { &.selectable-day { label { background-color: $blue-100; - min-width: 2.75rem; - width: 2.75rem; border-radius: 50%; cursor: pointer; - @include media-breakpoint-up(md) { - min-width: 3rem; - width: 3rem; - } &:hover { border: 2px solid $blue; } @@ -1413,18 +1407,13 @@ export default { line-height: 1.2; justify-content: center; padding: 0.25rem; + margin: 0.15rem; } &.selectable-day { label { color: $black; background-color: $blue-100; - min-width: 2.75rem; - width: 2.75rem; border-radius: 0.25rem; - @include media-breakpoint-up(md) { - min-width: 3rem; - width: 3rem; - } } } &.current-day { @@ -1432,7 +1421,6 @@ export default { font-weight: 600; font-family: "UrbanistSemibold"; color: $black; - font-size-adjust: 0.5; // needed for Averta fonts baseline alignment } } } @@ -1443,7 +1431,6 @@ export default { color: $black; font-weight: 400; font-family: "UrbanistSemibold"; - font-size-adjust: 0.5; // needed for Averta fonts baseline alignment &.price { font-weight: 400; diff --git a/src/experiment-components/donation-block.vue b/src/experiment-components/donation-block.vue index 34cd4178a..f93c96520 100644 --- a/src/experiment-components/donation-block.vue +++ b/src/experiment-components/donation-block.vue @@ -317,10 +317,18 @@ export default { } } .custom-secondary { - &:hover { + border-radius: 0.5rem; + color: $blue; + border: 1px solid $blue; + &:hover, + &:focus, + &:active { color: $blue; background: transparent; border: 1px solid $blue; + box-shadow: + 0 0 0 3px #ffffff, + 0 0 0 5.5px $blue; } } } diff --git a/src/experiment-components/service-package-radio-for-afterpay.vue b/src/experiment-components/service-package-radio-for-afterpay.vue index 120975d9b..d4ca90730 100644 --- a/src/experiment-components/service-package-radio-for-afterpay.vue +++ b/src/experiment-components/service-package-radio-for-afterpay.vue @@ -218,14 +218,17 @@ export default { &.has-subheader { & > .package-specs { - & > div:first-of-type { - display: flex; + display: inline-flex; + @include media-breakpoint-up(md) { + & > div:first-of-type { + display: flex; + } } } } &.has-package-discount { - min-height: 150px; + min-height: 170px; } &:before { @@ -267,10 +270,6 @@ export default { + .package-label { .package-specs { max-height: 1000px; - - .sub-label { - background-color: $green-200; - } } } + .package-label { @@ -281,11 +280,10 @@ export default { } } + .package-label { - background-color: $blue-100; border: 1px solid $blue; max-height: 500px; .special-save-box { - background-color: $green-200; + background-color: $green-100; } } + .package-label { @@ -336,12 +334,16 @@ export default { &.sub-label { color: $green; - background-color: $green-100; - padding: 0.25rem 0.5rem; - border-radius: 0.75rem; + + padding: 0.25rem 0; text-transform: uppercase; font-size: 0.75rem; margin-left: auto; + @include media-breakpoint-up(md) { + background-color: $green-100; + padding: 0.25rem 0.5rem; + border-radius: 0.75rem; + } } } span { @@ -429,14 +431,17 @@ export default { background-color: $green-100; display: flex; flex-direction: row; - margin: 0.5rem auto 1rem -1.25rem; - padding: 0.5rem 1rem; + margin: 0.25rem auto 0 -1.25rem; + padding: 0.25rem 1rem; border-radius: 0.25rem; span { color: $green; font-size: 0.875rem; font-weight: 600; } + @include media-breakpoint-up(md) { + margin: 1rem auto 0 -1.25rem; + } } .pricing-info { color: $green; @@ -447,6 +452,7 @@ export default { margin-left: 1.25rem; font-weight: 600; line-height: 20px; + font-size: 1.25rem; span.strikethrough-price { text-decoration: line-through; diff --git a/src/experiment-components/service-package-radio.vue b/src/experiment-components/service-package-radio.vue index bc68b5990..bee29afd8 100644 --- a/src/experiment-components/service-package-radio.vue +++ b/src/experiment-components/service-package-radio.vue @@ -318,7 +318,6 @@ export default { } } + .package-label { - background-color: $blue-100; border: 1px solid $blue; max-height: 500px; .special-save-box { diff --git a/src/fmg-components/layouts/questions-page-layout/questions-page-layout.vue b/src/fmg-components/layouts/questions-page-layout/questions-page-layout.vue index fca4b91f3..560fe87c6 100644 --- a/src/fmg-components/layouts/questions-page-layout/questions-page-layout.vue +++ b/src/fmg-components/layouts/questions-page-layout/questions-page-layout.vue @@ -19,10 +19,10 @@ v-if="showThisQuestionChain(questionsDatum, i)" :answerKey="questionsDatum.answerKey" :validationRules="validationRules" /> + + - - diff --git a/src/layouts/mobile-details/mobile-address-questions/mobile-address-questions.vue b/src/layouts/mobile-details/mobile-address-questions/mobile-address-questions.vue index 2e5dd8324..e28cbd298 100644 --- a/src/layouts/mobile-details/mobile-address-questions/mobile-address-questions.vue +++ b/src/layouts/mobile-details/mobile-address-questions/mobile-address-questions.vue @@ -44,7 +44,7 @@
-
+
-
+
-
-
-
- -
-
-
-
+ +
+
+
+
+ + +
+ + diff --git a/src/layouts/quote/quote.spec.js b/src/layouts/quote/quote.spec.js index c162017c1..f555b6c16 100644 --- a/src/layouts/quote/quote.spec.js +++ b/src/layouts/quote/quote.spec.js @@ -963,5 +963,6 @@ function setupMocks({ customMountOptions }) { const wrapper = shallowMount(quote, mountOptions); wrapper.vm.setCmsContent = jest.fn(); + wrapper.vm.getCmsContent = jest.fn(); return { wrapper }; } diff --git a/src/layouts/quote/quote.vue b/src/layouts/quote/quote.vue index d80184901..ff8bc0c61 100644 --- a/src/layouts/quote/quote.vue +++ b/src/layouts/quote/quote.vue @@ -4,7 +4,7 @@
-
+
@@ -78,7 +78,10 @@ :isForwardActionDisabled="!meta.valid" :isBackButtonHidden="shouldHideBackButton" @back-clicked="backButtonAction" - @ForwardClicked="forwardButtonAction" /> + @ForwardClicked="forwardButtonAction" + :overrideButtonText=" + isInsuranceSelected ? isInsuranceContinueButtonText : '' + " /> 2) { - return "col-xl-10"; + return "col-xl-12"; } else { return "col-xl-6"; } @@ -927,6 +933,9 @@ export default { } .funnel-sub-header { + :deep(h5) { + text-align: center; + } p { font-size: 1rem; } diff --git a/src/layouts/quote/service-package-question/service-package-radio/service-package-radio.vue b/src/layouts/quote/service-package-question/service-package-radio/service-package-radio.vue index 085e047b2..9518b42fa 100644 --- a/src/layouts/quote/service-package-question/service-package-radio/service-package-radio.vue +++ b/src/layouts/quote/service-package-question/service-package-radio/service-package-radio.vue @@ -246,7 +246,6 @@ export default { } } + .package-label { - background-color: $blue-100; border: 1px solid $blue; max-height: 500px; .special-save-box { diff --git a/src/layouts/return-user/return-user.vue b/src/layouts/return-user/return-user.vue index 86cde49c8..b0d9bfe90 100644 --- a/src/layouts/return-user/return-user.vue +++ b/src/layouts/return-user/return-user.vue @@ -117,4 +117,10 @@ export default { margin-top: 14rem; } } +:deep(.menu-modal-container) { + display: none; +} +:deep(.progress-bar-outer) { + opacity: 0; +} diff --git a/src/layouts/schedule/schedule.vue b/src/layouts/schedule/schedule.vue index 6b214f2e2..0be89d4dd 100644 --- a/src/layouts/schedule/schedule.vue +++ b/src/layouts/schedule/schedule.vue @@ -60,8 +60,8 @@ alertClass="alert-success" />
-
-
+
+
-
+
-
+ groupName="chooseShop" /> +
-
-
+
+