From da98a327ca63813d7bd8385c11b74424faf9dd74 Mon Sep 17 00:00:00 2001 From: Chloe Herd Date: Tue, 6 Jun 2023 14:19:09 -0400 Subject: [PATCH 01/60] Initial blocking out --- .../customer-review/customer-review.spec.js | 3 ++ .../customer-review/customer-review.vue | 38 +++++++++++++++++++ src/layouts/review/review.vue | 9 +++++ 3 files changed, 50 insertions(+) create mode 100644 src/layouts/review/review-sections/customer-review/customer-review.spec.js create mode 100644 src/layouts/review/review-sections/customer-review/customer-review.vue diff --git a/src/layouts/review/review-sections/customer-review/customer-review.spec.js b/src/layouts/review/review-sections/customer-review/customer-review.spec.js new file mode 100644 index 000000000..ea5ec2f2e --- /dev/null +++ b/src/layouts/review/review-sections/customer-review/customer-review.spec.js @@ -0,0 +1,3 @@ +describe("Customer review Block", () => { + test.todo("Add more tests as specific functionality is added."); +}); diff --git a/src/layouts/review/review-sections/customer-review/customer-review.vue b/src/layouts/review/review-sections/customer-review/customer-review.vue new file mode 100644 index 000000000..1f0b9e2d0 --- /dev/null +++ b/src/layouts/review/review-sections/customer-review/customer-review.vue @@ -0,0 +1,38 @@ + + + diff --git a/src/layouts/review/review.vue b/src/layouts/review/review.vue index 3f7e45639..8c6fbf411 100644 --- a/src/layouts/review/review.vue +++ b/src/layouts/review/review.vue @@ -41,6 +41,12 @@ cmsWidgetName="VehicleReviewWidget" :vehicle="vehicleInfo" @edit-clicked="editVehicle" /> + +
+ +
@@ -60,6 +66,7 @@ import vehicleBanner from "@/fmg-components/vehicle-banner/vehicle-banner"; import buttonMain from "@/ux-components/button-main/button-main"; import textBlock from "@/digital-components/text-block/text-block"; import vehicleReview from "@/layouts/review/review-sections/vehicle-review/vehicle-review"; +import customerReview from "@/layouts/review/review-sections/customer-review/customer-review"; import { fetchCmsContentForPage } from "@/helpers/cms-content-helper"; import { settleAllPromises } from "@/helpers/layout-helper"; @@ -99,6 +106,7 @@ export default { this.$route ); }, + editCustomerDetails() {}, }, computed: { subHeaderTitle() { @@ -121,6 +129,7 @@ export default { buttonMain, textBlock, vehicleReview, + customerReview, }, }; From aaba3ce7c1dae2ca9c65c802a82a9b0353069736 Mon Sep 17 00:00:00 2001 From: Chloe Herd Date: Wed, 26 Jul 2023 17:26:52 -0400 Subject: [PATCH 02/60] Extract logic for use in review component --- .../schedule/helpers/schedule-helper.js | 29 +++++++++++++ .../time-slot-modal-question.vue | 41 ++++--------------- 2 files changed, 38 insertions(+), 32 deletions(-) diff --git a/src/layouts/schedule/helpers/schedule-helper.js b/src/layouts/schedule/helpers/schedule-helper.js index 82c756b5b..930a5ee6e 100644 --- a/src/layouts/schedule/helpers/schedule-helper.js +++ b/src/layouts/schedule/helpers/schedule-helper.js @@ -45,3 +45,32 @@ export function sumDateString(dateString, daysToAdd) { date.setDate(date.getDate() + daysToAdd); return convertDateToDateString(date); } + +export function militaryToTwelveHourTime(timeString) { + // Expected input: "HH:MM" + let hours = parseInt(timeString.split(":")[0]); + const minutes = timeString.split(":")[1]; + const meridianNotation = hours > 11 ? "PM" : "AM"; + + if (hours > 12) { + hours -= 12; + } + + return `${hours}:${minutes} ${meridianNotation}`; +} + +export function getDisplayTextForDurationLength(durationMinimum, durationMaximum) { + const isLongAppointment = durationMaximum >= 120; + const isDurationRange = durationMinimum !== durationMaximum; + + const adjustedMinimum = isLongAppointment ? durationMinimum / 60 : durationMinimum; + const adjustedMaximum = isLongAppointment ? durationMaximum / 60 : durationMaximum; + + const durationText = isDurationRange + ? `${adjustedMinimum} - ${adjustedMaximum}` + : adjustedMinimum; + + const unitText = isLongAppointment ? "hours" : "minutes"; + + return `${durationText} ${unitText}`; +} diff --git a/src/layouts/schedule/time-slot-modal-question/time-slot-modal-question.vue b/src/layouts/schedule/time-slot-modal-question/time-slot-modal-question.vue index 13f33ae05..4ff62cc4d 100644 --- a/src/layouts/schedule/time-slot-modal-question/time-slot-modal-question.vue +++ b/src/layouts/schedule/time-slot-modal-question/time-slot-modal-question.vue @@ -47,7 +47,11 @@ import buttonQuestion from "@/digital-components/button-question/button-question import timeSlotModalListButton from "./time-slot-modal-list-button/time-slot-modal-list-button"; // Helpers -import { convertDateStringToDate } from "@/layouts/schedule/helpers/schedule-helper"; +import { + convertDateStringToDate, + militaryToTwelveHourTime, + getDisplayTextForDurationLength, +} from "@/layouts/schedule/helpers/schedule-helper"; import { deepClone } from "@/helpers/object-helper"; // Validation - TODO: Move this somewhere more global? @@ -263,7 +267,7 @@ export default { cmsWidgetFieldMappings.DURATION ); - const inshopDurationTime = this.getDisplayTextForDurationLength( + const inshopDurationTime = getDisplayTextForDurationLength( this.estimatedServiceMinutesMinimum, this.estimatedServiceMinutesMaximum ); @@ -346,33 +350,6 @@ export default { this.$emit("update:modelValue", this.selectedValue); this.closeModal(); }, - getDisplayTextForMilitaryTime(militaryTimeInput) { - // Expected input: "HH:MM" - let hours = parseInt(militaryTimeInput.split(":")[0]); - const minutes = militaryTimeInput.split(":")[1]; - const meridianNotation = hours > 11 ? "PM" : "AM"; - - if (hours > 12) { - hours -= 12; - } - - return `${hours}:${minutes} ${meridianNotation}`; - }, - getDisplayTextForDurationLength(durationMinimum, durationMaximum) { - const isLongAppointment = durationMaximum >= 120; - const isDurationRange = durationMinimum !== durationMaximum; - - const adjustedMinimum = isLongAppointment ? durationMinimum / 60 : durationMinimum; - const adjustedMaximum = isLongAppointment ? durationMaximum / 60 : durationMaximum; - - const durationText = isDurationRange - ? `${adjustedMinimum} - ${adjustedMaximum}` - : adjustedMinimum; - - const unitText = isLongAppointment ? "hours" : "minutes"; - - return `${durationText} ${unitText}`; - }, getRelevantDropOffCmsWidgetNameForSelectedTimeSlot( selectedTimeSlotId, isSameDayRelevant = false @@ -387,7 +364,7 @@ export default { }, getAvailableTimeSlotsForInshop(timeSlotsForSelectedDate) { return timeSlotsForSelectedDate.map((timeSlot) => { - const readableTime = this.getDisplayTextForMilitaryTime(timeSlot.startTime); + const readableTime = militaryToTwelveHourTime(timeSlot.startTime); return { value: timeSlot.id, buttonLabel: readableTime, @@ -415,9 +392,9 @@ export default { }, getAvailableTimeSlotsForMobile(timeSlotsForSelectedDate) { const availableTimeSlots = timeSlotsForSelectedDate.map((timeSlot) => { - const readableTime = `${this.getDisplayTextForMilitaryTime( + const readableTime = `${militaryToTwelveHourTime( timeSlot.startTime - )} - ${this.getDisplayTextForMilitaryTime(timeSlot.endTime)}`; + )} - ${militaryToTwelveHourTime(timeSlot.endTime)}`; return { value: timeSlot.id, buttonLabel: readableTime, From 6728235ed48d731acda42c43224a9d9cb763ac0d Mon Sep 17 00:00:00 2001 From: Chloe Herd Date: Wed, 26 Jul 2023 17:27:09 -0400 Subject: [PATCH 03/60] Schedule review first draft --- .../schedule-review/schedule-review.vue | 90 +++++++++++++++++++ src/layouts/review/review.vue | 16 ++++ 2 files changed, 106 insertions(+) create mode 100644 src/layouts/review/review-sections/schedule-review/schedule-review.vue diff --git a/src/layouts/review/review-sections/schedule-review/schedule-review.vue b/src/layouts/review/review-sections/schedule-review/schedule-review.vue new file mode 100644 index 000000000..65d922821 --- /dev/null +++ b/src/layouts/review/review-sections/schedule-review/schedule-review.vue @@ -0,0 +1,90 @@ + + + diff --git a/src/layouts/review/review.vue b/src/layouts/review/review.vue index 8780e75a7..34b64a88b 100644 --- a/src/layouts/review/review.vue +++ b/src/layouts/review/review.vue @@ -69,6 +69,14 @@ cmsWidgetName="ServiceLocationTitleWidget" :serviceLocation="serviceLocationInfo" @edit-clicked="editServiceLocation" /> + +
+ +
@@ -94,6 +102,7 @@ import vehicleReview from "@/layouts/review/review-sections/vehicle-review/vehic import damageReview from "@/layouts/review/review-sections/damage-review/damage-review"; import servicePackageReview from "@/layouts/review/review-sections/service-package-review/service-package-review"; import serviceLocationReview from "@/layouts/review/review-sections/service-location-review/service-location-review"; +import scheduleReview from "@/layouts/review/review-sections/schedule-review/schedule-review"; import { fetchCmsContentForPage } from "@/helpers/cms-content-helper"; import { settleAllPromises } from "@/helpers/layout-helper"; @@ -189,6 +198,12 @@ export default { serviceLocationInfo() { return this.$store.getters.order.serviceLocation; }, + appointmentType() { + return this.$store.getters.order.serviceLocation.appointmentType; + }, + scheduleInfo() { + return this.$store.getters.order.schedule; + }, }, components: { funnelHeader, @@ -200,6 +215,7 @@ export default { damageReview, servicePackageReview, serviceLocationReview, + scheduleReview, }, }; From b5edeb96325823ca1ccb4b25a3e0c45a35213a46 Mon Sep 17 00:00:00 2001 From: Chloe Herd Date: Thu, 27 Jul 2023 09:30:12 -0400 Subject: [PATCH 04/60] Add back-navigation --- src/layouts/review/review.vue | 6 ++++++ src/router/router-constants/navigation-scenarios.js | 1 + src/router/router-constants/routing-table.js | 4 ++++ 3 files changed, 11 insertions(+) diff --git a/src/layouts/review/review.vue b/src/layouts/review/review.vue index 34b64a88b..6a81dcbac 100644 --- a/src/layouts/review/review.vue +++ b/src/layouts/review/review.vue @@ -175,6 +175,12 @@ export default { this.$route ); }, + editSchedule() { + this.$router.navigateWithoutSaving( + this.navigationScenarios.CLICKED_SCHEDULE_EDIT, + this.$route + ); + }, }, computed: { subHeaderTitle() { diff --git a/src/router/router-constants/navigation-scenarios.js b/src/router/router-constants/navigation-scenarios.js index ae1c880ae..ce2f32134 100644 --- a/src/router/router-constants/navigation-scenarios.js +++ b/src/router/router-constants/navigation-scenarios.js @@ -51,6 +51,7 @@ const navigationScenarios = { CLICKED_DAMAGE_EDIT: "CLICKED_DAMAGE_EDIT", CLICKED_SERVICE_PACKAGE_EDIT: "CLICKED_SERVICE_PACKAGE_EDIT", CLICKED_SERVICE_LOCATION_EDIT: "CLICKED_SERVICE_LOCATION_EDIT", + CLICKED_SCHEDULE_EDIT: "CLICKED_SCHEDULE_EDIT", }; export { navigationScenarios }; diff --git a/src/router/router-constants/routing-table.js b/src/router/router-constants/routing-table.js index 017e1372a..f1f83b445 100644 --- a/src/router/router-constants/routing-table.js +++ b/src/router/router-constants/routing-table.js @@ -484,6 +484,10 @@ const routingTable = function (store) { scenario: navigationScenarios.CLICKED_SERVICE_LOCATION_EDIT, destinationFmgPageValue: fmgPageValues.SERVICE_LOCATION, }, + { + scenario: navigationScenarios.CLICKED_SCHEDULE_EDIT, + destinationFmgPageValue: fmgPageValues.SCHEDULE, + }, ], }, ]; From 8bbbdf909a4c8cbbfd56580b36f43d239307b995 Mon Sep 17 00:00:00 2001 From: Chloe Herd Date: Thu, 27 Jul 2023 09:30:23 -0400 Subject: [PATCH 05/60] Formatting --- .../review-sections/schedule-review/schedule-review.vue | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/layouts/review/review-sections/schedule-review/schedule-review.vue b/src/layouts/review/review-sections/schedule-review/schedule-review.vue index 65d922821..3436cb7c2 100644 --- a/src/layouts/review/review-sections/schedule-review/schedule-review.vue +++ b/src/layouts/review/review-sections/schedule-review/schedule-review.vue @@ -80,7 +80,9 @@ export default { ); }, renderedMobileWindow() { - return `${militaryToTwelveHourTime(this.schedule?.startTime)} - ${militaryToTwelveHourTime(this.schedule?.endTime)}`; + return `${militaryToTwelveHourTime( + this.schedule?.startTime + )} - ${militaryToTwelveHourTime(this.schedule?.endTime)}`; }, }, components: { From a4785fa1c5374bf3b5b1ff2667f353d5ac699fac Mon Sep 17 00:00:00 2001 From: Chloe Herd Date: Thu, 27 Jul 2023 13:56:58 -0400 Subject: [PATCH 06/60] Add jobMinMinutes to store and use on review page --- .../review-sections/schedule-review/schedule-review.vue | 2 +- src/layouts/schedule/schedule.vue | 1 + .../time-slot-modal-question/time-slot-modal-question.vue | 3 +++ src/store/index.js | 5 +++++ 4 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/layouts/review/review-sections/schedule-review/schedule-review.vue b/src/layouts/review/review-sections/schedule-review/schedule-review.vue index 3436cb7c2..1cdfdea22 100644 --- a/src/layouts/review/review-sections/schedule-review/schedule-review.vue +++ b/src/layouts/review/review-sections/schedule-review/schedule-review.vue @@ -75,7 +75,7 @@ export default { }, renderedEstimatedDuration() { return getDisplayTextForDurationLength( - this.schedule?.jobMaxMinutes, + this.schedule?.jobMinMinutes, this.schedule?.jobMaxMinutes ); }, diff --git a/src/layouts/schedule/schedule.vue b/src/layouts/schedule/schedule.vue index d15e9acec..02fab79a9 100644 --- a/src/layouts/schedule/schedule.vue +++ b/src/layouts/schedule/schedule.vue @@ -463,6 +463,7 @@ export default { startTime: null, endTime: null, jobMaxMinutes: null, + jobMinMinutes: null, }; } }, diff --git a/src/layouts/schedule/time-slot-modal-question/time-slot-modal-question.vue b/src/layouts/schedule/time-slot-modal-question/time-slot-modal-question.vue index 4ff62cc4d..8b2e63fd3 100644 --- a/src/layouts/schedule/time-slot-modal-question/time-slot-modal-question.vue +++ b/src/layouts/schedule/time-slot-modal-question/time-slot-modal-question.vue @@ -92,6 +92,7 @@ export default { startTime: null, endTime: null, jobMaxMinutes: null, + jobMinMinutes: null, }), }, cmsWidgetName: String, @@ -449,6 +450,7 @@ export default { startTime: timeSlot.startTime, endTime: timeSlot.endTime, jobMaxMinutes: this.estimatedServiceMinutesMaximum.toString(), + jobMinMinutes: this.estimatedServiceMinutesMinimum.toString(), }; } @@ -458,6 +460,7 @@ export default { endTime: null, routeCode: null, jobMaxMinutes: null, + jobMinMinutes: null, }; }, }, diff --git a/src/store/index.js b/src/store/index.js index fb86b61c3..ec0a324c0 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -91,6 +91,7 @@ const getDefaultState = () => { endTime: null, routeCode: null, jobMaxMinutes: null, + jobMinMinutes: null, }, referralNumber: null, referralDate: null, @@ -279,6 +280,7 @@ export const mutations = { state.order.schedule.endTime = scheduleInfo.endTime; state.order.schedule.routeCode = scheduleInfo.routeCode; state.order.schedule.jobMaxMinutes = scheduleInfo.jobMaxMinutes; + state.order.schedule.jobMinMinutes = scheduleInfo.jobMinMinutes; } }, updateCustomerDetails(state, detailsInfo) { @@ -365,6 +367,7 @@ export const mutations = { state.order.schedule.endTime = null; state.order.schedule.routeCode = null; state.order.schedule.jobMaxMinutes = null; + state.order.schedule.jobMinMinutes = null; //premium appointment fee used on schedule page also needs reset when schedule is reset const supportingItems = state.order.lineItems.supportingItems; @@ -506,6 +509,7 @@ export const mutations = { state.order.schedule.endTime = sessionInformation.order.schedule?.endTime; state.order.schedule.routeCode = sessionInformation.order.schedule?.routeCode; state.order.schedule.jobMaxMinutes = sessionInformation.order.schedule?.jobMaxMinutes; + state.order.schedule.jobMinMinutes = sessionInformation.order.schedule?.jobMinMinutes; }, updateExperiments(state, experiments) { state.applicationUser.experiments = experiments; @@ -1464,6 +1468,7 @@ export const actions = { endTime: order.schedule?.endTime, routeCode: order.schedule?.routeCode, jobMaxMinutes: order.schedule?.jobMaxMinutes, + jobMinMinutes: order.schedule?.jobMinMinutes, }, existingPromoCode: null, referralCorrelationId: order.referralCorrelationId, From 2a746bd7be971a875dfc94e2fe2fecaf82352a3a Mon Sep 17 00:00:00 2001 From: Chloe Herd Date: Fri, 28 Jul 2023 13:23:27 -0400 Subject: [PATCH 07/60] Move copy structure to cms + state getters. --- .../schedule-review/schedule-review.vue | 61 ++----------------- src/layouts/review/review.vue | 6 +- .../schedule/helpers/schedule-helper.js | 1 + src/store/index.js | 32 ++++++++++ 4 files changed, 42 insertions(+), 58 deletions(-) diff --git a/src/layouts/review/review-sections/schedule-review/schedule-review.vue b/src/layouts/review/review-sections/schedule-review/schedule-review.vue index 1cdfdea22..654676829 100644 --- a/src/layouts/review/review-sections/schedule-review/schedule-review.vue +++ b/src/layouts/review/review-sections/schedule-review/schedule-review.vue @@ -1,22 +1,17 @@ diff --git a/src/layouts/review/review.vue b/src/layouts/review/review.vue index 72847998c..d99ba1cda 100644 --- a/src/layouts/review/review.vue +++ b/src/layouts/review/review.vue @@ -89,6 +89,8 @@
+ + From 17f149af4300ba793d7f8eee5a58447aad4e210f Mon Sep 17 00:00:00 2001 From: Chloe Herd Date: Thu, 10 Aug 2023 17:13:38 -0400 Subject: [PATCH 27/60] Add sms opt-in and disclaimer --- .../customer-details-modal-question.vue | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/layouts/review/review-sections/customer-review/customer-details-modal-question/customer-details-modal-question.vue b/src/layouts/review/review-sections/customer-review/customer-details-modal-question/customer-details-modal-question.vue index 8133e7685..f02ecd3b4 100644 --- a/src/layouts/review/review-sections/customer-review/customer-details-modal-question/customer-details-modal-question.vue +++ b/src/layouts/review/review-sections/customer-review/customer-details-modal-question/customer-details-modal-question.vue @@ -38,6 +38,11 @@ ref="phoneNumber" isRequired validation-rules="" /> + + @@ -48,6 +53,8 @@ import modal from "@/digital-components/modal/modal"; import textboxQuestion from "@/digital-components/textbox-question/textbox-question"; import phoneNumberQuestion from "@/digital-components/phone-number-question/phone-number-question"; +import checkboxQuestion from "@/digital-components/checkbox-question/checkbox-question"; +import textBlock from "@/digital-components/text-block/text-block"; export default { name: "customer-details-modal-question", @@ -85,6 +92,8 @@ export default { modal, textboxQuestion, phoneNumberQuestion, + checkboxQuestion, + textBlock, }, }; From 943b5c8d762d9b69a198d32e1a570db018ef3f2e Mon Sep 17 00:00:00 2001 From: Sneha Date: Fri, 11 Aug 2023 14:54:24 +0530 Subject: [PATCH 28/60] CSR-1425 Removing existing YMMS --- src/constants/store-actions.js | 4 - .../heritage-integration/navigation-helper.js | 18 +- .../navigation-helper.spec.js | 102 +------ .../make-question/make-question.spec.js | 79 ------ .../make-question/make-question.vue | 59 ---- src/layouts/vehicle-make/vehicle-make.spec.js | 228 ---------------- src/layouts/vehicle-make/vehicle-make.vue | 95 ------- .../model-question/model-question.spec.js | 79 ------ .../model-question/model-question.vue | 60 ---- .../vehicle-model/vehicle-model.spec.js | 147 ---------- src/layouts/vehicle-model/vehicle-model.vue | 98 ------- .../style-question/style-question.spec.js | 79 ------ .../style-question/style-question.vue | 61 ----- .../vehicle-style/vehicle-style.spec.js | 256 ------------------ src/layouts/vehicle-style/vehicle-style.vue | 137 ---------- src/layouts/vehicle-year/vehicle-year.spec.js | 122 --------- src/layouts/vehicle-year/vehicle-year.vue | 110 -------- .../year-question/year-question.spec.js | 78 ------ .../year-question/year-question.vue | 55 ---- src/router/router-constants/fmgPage-values.js | 4 - .../router-constants/navigation-scenarios.js | 6 - src/router/router-constants/routing-table.js | 49 +--- src/store/index.js | 82 ------ src/store/store.spec.js | 162 ----------- 24 files changed, 14 insertions(+), 2156 deletions(-) delete mode 100644 src/layouts/vehicle-make/make-question/make-question.spec.js delete mode 100644 src/layouts/vehicle-make/make-question/make-question.vue delete mode 100644 src/layouts/vehicle-make/vehicle-make.spec.js delete mode 100644 src/layouts/vehicle-make/vehicle-make.vue delete mode 100644 src/layouts/vehicle-model/model-question/model-question.spec.js delete mode 100644 src/layouts/vehicle-model/model-question/model-question.vue delete mode 100644 src/layouts/vehicle-model/vehicle-model.spec.js delete mode 100644 src/layouts/vehicle-model/vehicle-model.vue delete mode 100644 src/layouts/vehicle-style/style-question/style-question.spec.js delete mode 100644 src/layouts/vehicle-style/style-question/style-question.vue delete mode 100644 src/layouts/vehicle-style/vehicle-style.spec.js delete mode 100644 src/layouts/vehicle-style/vehicle-style.vue delete mode 100644 src/layouts/vehicle-year/vehicle-year.spec.js delete mode 100644 src/layouts/vehicle-year/vehicle-year.vue delete mode 100644 src/layouts/vehicle-year/year-question/year-question.spec.js delete mode 100644 src/layouts/vehicle-year/year-question/year-question.vue diff --git a/src/constants/store-actions.js b/src/constants/store-actions.js index c4efe9d45..f23a167e1 100644 --- a/src/constants/store-actions.js +++ b/src/constants/store-actions.js @@ -58,10 +58,6 @@ const storeActions = { RESET_STATE: "resetState", // SAVE COMPONENT STATE - SAVE_VEHICLE_YEAR: "saveVehicleYear", - SAVE_VEHICLE_MAKE: "saveVehicleMake", - SAVE_VEHICLE_MODEL: "saveVehicleModel", - SAVE_VEHICLE_STYLE: "saveVehicleStyle", SAVE_VEHICLE: "saveVehicle", SAVE_VEHICLE_DAMAGE: "saveVehicleDamage", SAVE_VIN_LOOKUP: "saveVinLookup", diff --git a/src/helpers/heritage-integration/navigation-helper.js b/src/helpers/heritage-integration/navigation-helper.js index 913fbcb1b..d522a5e6d 100644 --- a/src/helpers/heritage-integration/navigation-helper.js +++ b/src/helpers/heritage-integration/navigation-helper.js @@ -102,9 +102,6 @@ async function getLatestPageForRedirection() { // If this is a non-CTA navigation, determine where to send the user based on page prerequisites. // This also works if a user has a 'fmg' start_type query string but no current order. // That shouldn't happen, but it's possible. - const vehicleMakeComponent = await getLazyLoadedComponent(fmgPageValues.VEHICLE_MAKE); - const vehicleModelComponent = await getLazyLoadedComponent(fmgPageValues.VEHICLE_MODEL); - const vehicleStyleComponent = await getLazyLoadedComponent(fmgPageValues.VEHICLE_STYLE); const vehicleDamageComponent = await getLazyLoadedComponent(fmgPageValues.VEHICLE_DAMAGE); const estimateComponent = await getLazyLoadedComponent(fmgPageValues.ESTIMATE); const vinLookupComponent = await getLazyLoadedComponent(fmgPageValues.VIN_LOOKUP); @@ -118,14 +115,8 @@ async function getLatestPageForRedirection() { const skipVin = await skipVinLookup(); - if (!vehicleMakeComponent.methods.arePagePrerequisitesValid()) { - return fmgPageValues.VEHICLE_YEAR; - } else if (!vehicleModelComponent.methods.arePagePrerequisitesValid()) { - return fmgPageValues.VEHICLE_MAKE; - } else if (!vehicleStyleComponent.methods.arePagePrerequisitesValid()) { - return fmgPageValues.VEHICLE_MODEL; - } else if (!vehicleDamageComponent.methods.arePagePrerequisitesValid()) { - return fmgPageValues.VEHICLE_STYLE; + if (!vehicleDamageComponent.methods.arePagePrerequisitesValid()) { + return fmgPageValues.VEHICLE; } else if (!estimateComponent.methods.arePagePrerequisitesValid()) { return fmgPageValues.VEHICLE_DAMAGE; } else { @@ -163,10 +154,7 @@ function overrideYmmsDirectionIfNeeded(toRoute) { if (store.getters.payment.insuranceCoverage.isVerified) { switch (fmgPageValue) { - case fmgPageValues.VEHICLE_YEAR: - case fmgPageValues.VEHICLE_MAKE: - case fmgPageValues.VEHICLE_MODEL: - case fmgPageValues.VEHICLE_STYLE: { + case fmgPageValues.VEHICLE: { return fmgPageValues.VEHICLE_DAMAGE; } default: { diff --git a/src/helpers/heritage-integration/navigation-helper.spec.js b/src/helpers/heritage-integration/navigation-helper.spec.js index d08ce92ec..cb0664f78 100644 --- a/src/helpers/heritage-integration/navigation-helper.spec.js +++ b/src/helpers/heritage-integration/navigation-helper.spec.js @@ -20,7 +20,7 @@ jest.mock("@/router/dynamic-routing/component-loader.js", () => ({ })); describe("getPageToRouteExistingOrderTo", () => { - test("should return vehicle-year", async () => { + test("should return vehicle", async () => { // Arrange const toRoute = { query: {}, @@ -31,75 +31,7 @@ describe("getPageToRouteExistingOrderTo", () => { // Mock out the lazy load calls for all components. mockLazyLoadComponentReturnValues({ - [fmgPageValues.VEHICLE_MAKE]: false, - }); - - // Act - const result = await getPageToRouteExistingOrderTo(toRoute, false); - - //Assert - expect(result).toBe(fmgPageValues.VEHICLE_YEAR); - }); - - test("should return vehicle-make", async () => { - // Arrange - const toRoute = { - query: {}, - }; - - store.commit(storeMutations.UPDATE_IS_REPAIR, false); - store.commit(storeMutations.UPDATE_MAKE, "acura"); - - // Mock out the lazy load calls for all components. - mockLazyLoadComponentReturnValues({ - [fmgPageValues.VEHICLE_MAKE]: true, - [fmgPageValues.VEHICLE_MODEL]: false, - }); - - // Act - const result = await getPageToRouteExistingOrderTo(toRoute, false); - - //Assert - expect(result).toBe(fmgPageValues.VEHICLE_MAKE); - }); - - test("should return vehicle-model", async () => { - // Arrange - const toRoute = { - query: {}, - }; - - store.commit(storeMutations.UPDATE_IS_REPAIR, false); - store.commit(storeMutations.UPDATE_MAKE, "acura"); - - // Mock out the lazy load calls for all components. - mockLazyLoadComponentReturnValues({ - [fmgPageValues.VEHICLE_MAKE]: true, - [fmgPageValues.VEHICLE_MODEL]: true, - [fmgPageValues.VEHICLE_STYLE]: false, - }); - - // Act - const result = await getPageToRouteExistingOrderTo(toRoute, false); - - //Assert - expect(result).toBe(fmgPageValues.VEHICLE_MODEL); - }); - - test("should return vehicle-style", async () => { - // Arrange - const toRoute = { - query: {}, - }; - - store.commit(storeMutations.UPDATE_IS_REPAIR, false); - store.commit(storeMutations.UPDATE_MAKE, "acura"); - - // Mock out the lazy load calls for all components. - mockLazyLoadComponentReturnValues({ - [fmgPageValues.VEHICLE_MAKE]: true, - [fmgPageValues.VEHICLE_MODEL]: true, - [fmgPageValues.VEHICLE_STYLE]: true, + [fmgPageValues.VEHICLE]: true, [fmgPageValues.VEHICLE_DAMAGE]: false, }); @@ -107,7 +39,7 @@ describe("getPageToRouteExistingOrderTo", () => { const result = await getPageToRouteExistingOrderTo(toRoute, false); //Assert - expect(result).toBe(fmgPageValues.VEHICLE_STYLE); + expect(result).toBe(fmgPageValues.VEHICLE); }); test("should return vehicle-damage", async () => { @@ -121,9 +53,7 @@ describe("getPageToRouteExistingOrderTo", () => { // Mock out the lazy load calls for all components. mockLazyLoadComponentReturnValues({ - [fmgPageValues.VEHICLE_MAKE]: true, - [fmgPageValues.VEHICLE_MODEL]: true, - [fmgPageValues.VEHICLE_STYLE]: true, + [fmgPageValues.VEHICLE]: true, [fmgPageValues.VEHICLE_DAMAGE]: true, [fmgPageValues.ESTIMATE]: false, }); @@ -156,9 +86,7 @@ describe("getPageToRouteExistingOrderTo", () => { // Mock out the lazy load calls for all components. mockLazyLoadComponentReturnValues({ - [fmgPageValues.VEHICLE_MAKE]: true, - [fmgPageValues.VEHICLE_MODEL]: true, - [fmgPageValues.VEHICLE_STYLE]: true, + [fmgPageValues.VEHICLE]: true, [fmgPageValues.VEHICLE_DAMAGE]: true, [fmgPageValues.ESTIMATE]: true, [fmgPageValues.CAPABILITY_QUESTIONS]: false, @@ -186,9 +114,7 @@ describe("getPageToRouteExistingOrderTo", () => { // Mock out the lazy load calls for all components. mockLazyLoadComponentReturnValues({ - [fmgPageValues.VEHICLE_MAKE]: true, - [fmgPageValues.VEHICLE_MODEL]: true, - [fmgPageValues.VEHICLE_STYLE]: true, + [fmgPageValues.VEHICLE]: true, [fmgPageValues.VEHICLE_DAMAGE]: true, [fmgPageValues.ESTIMATE]: true, [fmgPageValues.CAPABILITY_QUESTIONS]: false, @@ -216,9 +142,7 @@ describe("getPageToRouteExistingOrderTo", () => { // Mock out the lazy load calls for all components. mockLazyLoadComponentReturnValues({ - [fmgPageValues.VEHICLE_MAKE]: true, - [fmgPageValues.VEHICLE_MODEL]: true, - [fmgPageValues.VEHICLE_STYLE]: true, + [fmgPageValues.VEHICLE]: true, [fmgPageValues.VEHICLE_DAMAGE]: true, [fmgPageValues.ESTIMATE]: true, [fmgPageValues.CAPABILITY_QUESTIONS]: true, @@ -246,9 +170,7 @@ describe("getPageToRouteExistingOrderTo", () => { // Mock out the lazy load calls for all components. mockLazyLoadComponentReturnValues({ - [fmgPageValues.VEHICLE_MAKE]: true, - [fmgPageValues.VEHICLE_MODEL]: true, - [fmgPageValues.VEHICLE_STYLE]: true, + [fmgPageValues.VEHICLE]: true, [fmgPageValues.VEHICLE_DAMAGE]: true, [fmgPageValues.ESTIMATE]: true, [fmgPageValues.CAPABILITY_QUESTIONS]: false, @@ -276,9 +198,7 @@ describe("getPageToRouteExistingOrderTo", () => { // Mock out the lazy load calls for all components. mockLazyLoadComponentReturnValues({ - [fmgPageValues.VEHICLE_MAKE]: true, - [fmgPageValues.VEHICLE_MODEL]: true, - [fmgPageValues.VEHICLE_STYLE]: true, + [fmgPageValues.VEHICLE]: true, [fmgPageValues.VEHICLE_DAMAGE]: true, [fmgPageValues.ESTIMATE]: true, [fmgPageValues.CAPABILITY_QUESTIONS]: false, @@ -306,9 +226,7 @@ describe("getPageToRouteExistingOrderTo", () => { // Mock out the lazy load calls for all components. mockLazyLoadComponentReturnValues({ - [fmgPageValues.VEHICLE_MAKE]: true, - [fmgPageValues.VEHICLE_MODEL]: true, - [fmgPageValues.VEHICLE_STYLE]: true, + [fmgPageValues.VEHICLE]: true, [fmgPageValues.VEHICLE_DAMAGE]: true, [fmgPageValues.ESTIMATE]: true, [fmgPageValues.CAPABILITY_QUESTIONS]: false, diff --git a/src/layouts/vehicle-make/make-question/make-question.spec.js b/src/layouts/vehicle-make/make-question/make-question.spec.js deleted file mode 100644 index 7025c118c..000000000 --- a/src/layouts/vehicle-make/make-question/make-question.spec.js +++ /dev/null @@ -1,79 +0,0 @@ -import makeQuestion from "@/layouts/vehicle-make/make-question/make-question"; -import { shallowMount } from "@vue/test-utils"; -import { getMountOptions } from "@/helpers/unit-test-helper.js"; -import store from "@/store"; -jest.mock( - "@/store", - () => { - return {}; - }, - { virtual: true } -); - -describe("make-question.vue", () => { - test("Selected make is emitted upon selection.", async () => { - //Arrange - const { wrapper } = setupMocks({ modelValueProp: "honda" }); - const makeToSelect = "ford"; - - //Act - wrapper.setValue({ selectedMake: makeToSelect }); - await wrapper.vm.$nextTick(); - - //Assert - expect(wrapper.emitted()["update:modelValue"][0]).toEqual([{ selectedMake: "ford" }]); - }); -}); - -describe("make-question.vue", () => { - test("Data from store api are used as radio question answers.", async () => { - //Arrange - const { wrapper, cmsContent } = setupMocks({ - dataFromStoreApi: ["honda", "ford", "dodge"], - }); - - //Act - const initialData = makeQuestion.methods.loadInitialData.call(wrapper.vm); - makeQuestion.methods.initializeComponent.call(wrapper.vm, initialData); - - //Assert - const buttonQuestionComponent = await wrapper.findComponent({ - name: "buttonQuestion", - }); - expect(buttonQuestionComponent.attributes("answers")).toBe("honda,ford,dodge"); - }); -}); - -function setupMocks({ - modelValueProp = "1900", - cmsQuestionText = "CMS text goes here", - dataFromStoreApi = [], -}) { - //Mock store - store.dispatch = jest.fn(() => dataFromStoreApi); - store.getters = { vehicle: { year: 2019 } }; - const mountOptions = getMountOptions({ - store: { - dispatch: store.dispatch, - getters: store.getters, - }, - }); - - //Mock props - const mockMixin = { - methods: { - getCmsContent: jest.fn(), - }, - }; - mountOptions.propsData = { - modelValue: modelValueProp, - }; - mountOptions.mixins = [mockMixin]; - const wrapper = shallowMount(makeQuestion, mountOptions); - - //Mock CMS content - const cmsContent = { - QuestionText: cmsQuestionText, - }; - return { wrapper, cmsContent }; -} diff --git a/src/layouts/vehicle-make/make-question/make-question.vue b/src/layouts/vehicle-make/make-question/make-question.vue deleted file mode 100644 index 2d3551c53..000000000 --- a/src/layouts/vehicle-make/make-question/make-question.vue +++ /dev/null @@ -1,59 +0,0 @@ - - - diff --git a/src/layouts/vehicle-make/vehicle-make.spec.js b/src/layouts/vehicle-make/vehicle-make.spec.js deleted file mode 100644 index 3b169a9b9..000000000 --- a/src/layouts/vehicle-make/vehicle-make.spec.js +++ /dev/null @@ -1,228 +0,0 @@ -// Supporting Files -import { shallowMount } from "@vue/test-utils"; -import { getMountOptions } from "@/helpers/unit-test-helper.js"; -import { settleAllPromises } from "@/helpers/layout-helper.js"; -import { nextTick } from "vue"; -import { fetchCmsContentForPage } from "@/helpers/cms-content-helper"; -import baseMixin from "@/mixins/base-mixin.js"; -import store from "@/store"; - -// Components -import vehicleMake from "@/layouts/vehicle-make/vehicle-make.vue"; -import makeQuestion from "@/layouts/vehicle-make/make-question/make-question"; - -jest.mock("@/store", () => ({ - commit: jest.fn(), - dispatch: jest.fn(), - // getters: jest.fn().mockImplementation(() => ({ - // vehicle: { - // year: 2019, - // }, - // })), -})); - -// Mock fetchCmsContentForPage -jest.mock("@/helpers/cms-content-helper", () => ({ - fetchCmsContentForPage: jest.fn(), -})); - -// Mock our module for promises. -jest.mock("@/helpers/layout-helper.js", () => ({ - settleAllPromises: jest.fn(), -})); - -describe("vehicle-make.vue", () => { - test("Make question component is initized with api data", async (done) => { - //Arrange - const makeQuestionInitialData = ["honda", "ford", "dodge"]; - const { wrapper, apiPromise } = setupMocks({ - makeQuestionInitialData: makeQuestionInitialData, - }); - - //Act - vehicleMake.beforeRouteEnter.call( - wrapper.vm, - { query: { fmgPage: "vehicle-make" } }, - undefined, - (c) => c(wrapper.vm) - ); - - //Assert - apiPromise.finally(() => { - expect(makeQuestion.methods.initializeComponent).toHaveBeenCalledWith( - makeQuestionInitialData - ); - done(); - }); - }); -}); - -describe("vehicle-make.vue", () => { - test("BackButtonAction triggers a router.navigateWithoutSaving change", async (done) => { - //Arrange - const { wrapper, apiPromise } = setupMocks({ - pageHeaderWidgetHeaderText: "Select a make to get started", - mountOptionsMockData: { - router: { - navigate: jest.fn(), - navigateWithoutSaving: jest.fn(), - }, - }, - }); - - //Act - vehicleMake.beforeRouteEnter.call( - wrapper.vm, - { query: { fmgPage: "vehicle-make" } }, - undefined, - (c) => c(wrapper.vm) - ); - wrapper.vm.backButtonAction(); - await nextTick(); - - //Assert - apiPromise.finally(() => { - expect(wrapper.vm.$router.navigateWithoutSaving).toHaveBeenCalled(); - done(); - }); - }); -}); - -describe("vehicle-make.vue", () => { - describe("arePagePrerequisitesValue", () => { - test("Year set, arePagePrerequisitesValid should be true", async () => { - //Arrange - const { wrapper } = setupMocks({ - vehicleData: { - year: 2019, - }, - }); - - //Act - vehicleMake.beforeRouteEnter.call( - wrapper.vm, - { query: { fmgPage: "vehicle-make" } }, - undefined, - (c) => c(wrapper.vm) - ); - - let arePagePrerequisitesValid = wrapper.vm.arePagePrerequisitesValid(); - - //Assert - expect(arePagePrerequisitesValid).toBe(true); - }); - - test("Year not set, arePagePrerequisitesValid should be false", async () => { - //Arrange - store.getters.vehicle.year = jest.fn().mockReturnValueOnce(undefined); - const { wrapper } = setupMocks({}); - - //Act - let arePagePrerequisitesValid = wrapper.vm.arePagePrerequisitesValid(); - - //Assert - expect(arePagePrerequisitesValid).toBe(false); - }); - }); - - test("selectedMake changes => save make in store", async () => { - //Arrange - const { wrapper } = setupMocks({ - mountOptionsMockData: { - router: { - navigate: jest.fn(), - navigateWithSaving: jest.fn(), - }, - }, - }); - - // Act - await wrapper.setData({ - selectedMake: "Make", - }); - await wrapper.vm.$nextTick(); - - // Assert - expect(wrapper.vm.dispatchStoreAction).toHaveBeenCalledTimes(1); - expect(wrapper.vm.dispatchStoreAction).toHaveBeenCalledWith( - "saveVehicleMake", - "Make", - false - ); - }); - - test("selectedMake changes => navigate with saving", async () => { - //Arrange - const { wrapper } = setupMocks({ - mountOptionsMockData: { - router: { - navigate: jest.fn(), - navigateWithSaving: jest.fn(), - }, - route: { - fmgPage: "test", - }, - }, - }); - - // Act - await wrapper.setData({ - selectedMake: "Make", - }); - - // Assert - expect(wrapper.vm.$router.navigateWithSaving).toHaveBeenCalledTimes(1); - expect(wrapper.vm.$router.navigateWithSaving).toHaveBeenCalledWith( - "SELECTED_MAKE", - expect.anything() - ); - }); -}); - -function setupMocks({ - vehicleMakeQuestionCmsContent = {}, - makeQuestionInitialData = {}, - pageHeaderWidgetHeaderText = {}, - mountOptionsMockData = {}, - vehicleData = {}, -}) { - //Mock api responses - const apiResponses = { - cmsContent: { - FunnelSubHeaderWidget: pageHeaderWidgetHeaderText, - VehicleMakeQuestion: vehicleMakeQuestionCmsContent, - VehicleBannerWidget: { - GenericVehicleImage: - "https://digitalconsumercms-dev.safelite.com/images/default-source/default-album/blurred-image.jpg?sfvrsn=a6ce3034_3", - }, - FunnelHeaderWidget: { - LogoImage: - "https://digitalconsumercms-dev.safelite.com/images/default-source/default-album/safelite-logo.svg?sfvrsn=45e7ed06_3", - }, - }, - makeQuestionInitialData: makeQuestionInitialData, - }; - - const apiPromise = Promise.resolve(apiResponses); - - store.getters = { - vehicle: vehicleData, - }; - - fetchCmsContentForPage.mockImplementation(() => Promise.resolve()); - settleAllPromises.mockImplementation(() => apiPromise); - - //Mock make question methods - makeQuestion.methods = { - loadInitialData: jest.fn(), - initializeComponent: jest.fn(), - }; - - const mountOptions = getMountOptions(mountOptionsMockData); - const wrapper = shallowMount(vehicleMake, mountOptions); - const makeQuestionWrapper = wrapper.findComponent({ name: "makeQuestion" }); - makeQuestionWrapper.vm.initializeComponent = makeQuestion.methods.initializeComponent; - wrapper.vm.setCmsContent = baseMixin.methods.setCmsContent; - - return { wrapper, apiPromise }; -} diff --git a/src/layouts/vehicle-make/vehicle-make.vue b/src/layouts/vehicle-make/vehicle-make.vue deleted file mode 100644 index a50440e35..000000000 --- a/src/layouts/vehicle-make/vehicle-make.vue +++ /dev/null @@ -1,95 +0,0 @@ - - - diff --git a/src/layouts/vehicle-model/model-question/model-question.spec.js b/src/layouts/vehicle-model/model-question/model-question.spec.js deleted file mode 100644 index 16ca638d9..000000000 --- a/src/layouts/vehicle-model/model-question/model-question.spec.js +++ /dev/null @@ -1,79 +0,0 @@ -import modelQuestion from "@/layouts/vehicle-model/model-question/model-question"; -import { shallowMount } from "@vue/test-utils"; -import { getMountOptions } from "@/helpers/unit-test-helper.js"; -import store from "@/store"; -jest.mock( - "@/store", - () => { - return {}; - }, - { virtual: true } -); - -describe("model-question.vue", () => { - test("Selected model is emitted upon selection.", async () => { - //Arrange - const { wrapper } = setupMocks({ modelValueProp: "Accord" }); - const modelToSelect = "Civic"; - - //Act - wrapper.setValue({ selectedModel: modelToSelect }); - await wrapper.vm.$nextTick(); - - //Assert - expect(wrapper.emitted()["update:modelValue"][0]).toEqual([{ selectedModel: "Civic" }]); - }); -}); - -describe("model-question.vue", () => { - test("Data from store api are used as radio question answers.", async () => { - //Arrange - const { wrapper, cmsContent } = setupMocks({ - dataFromStoreApi: ["accord", "civic", "insight"], - }); - - //Act - const initialData = modelQuestion.methods.loadInitialData.call(wrapper.vm); - modelQuestion.methods.initializeComponent.call(wrapper.vm, initialData); - - //Assert - const buttonQuestionComponent = await wrapper.findComponent({ - name: "buttonQuestion", - }); - expect(buttonQuestionComponent.attributes("answers")).toBe("accord,civic,insight"); - }); -}); - -function setupMocks({ - modelValueProp = "1900", - cmsQuestionText = "CMS text goes here", - dataFromStoreApi = [], -}) { - //Mock store - store.dispatch = jest.fn(() => dataFromStoreApi); - store.getters = { vehicle: { year: 2019, make: "honda" } }; - const mountOptions = getMountOptions({ - store: { - dispatch: store.dispatch, - getters: store.getters, - }, - }); - - //Mock props - const mockMixin = { - methods: { - getCmsContent: jest.fn(), - }, - }; - mountOptions.propsData = { - modelValue: modelValueProp, - }; - mountOptions.mixins = [mockMixin]; - const wrapper = shallowMount(modelQuestion, mountOptions); - - //Mock CMS content - const cmsContent = { - QuestionText: cmsQuestionText, - }; - return { wrapper, cmsContent }; -} diff --git a/src/layouts/vehicle-model/model-question/model-question.vue b/src/layouts/vehicle-model/model-question/model-question.vue deleted file mode 100644 index 5ca926abc..000000000 --- a/src/layouts/vehicle-model/model-question/model-question.vue +++ /dev/null @@ -1,60 +0,0 @@ - - - diff --git a/src/layouts/vehicle-model/vehicle-model.spec.js b/src/layouts/vehicle-model/vehicle-model.spec.js deleted file mode 100644 index 33b74482d..000000000 --- a/src/layouts/vehicle-model/vehicle-model.spec.js +++ /dev/null @@ -1,147 +0,0 @@ -// Components -import vehicleModel from "@/layouts/vehicle-model/vehicle-model.vue"; -import modelQuestion from "@/layouts/vehicle-model/model-question/model-question"; - -// Supporting files -import { settleAllPromises } from "@/helpers/layout-helper.js"; -import { shallowMount } from "@vue/test-utils"; -import { getMountOptions } from "@/helpers/unit-test-helper.js"; -import { nextTick } from "vue"; -import { fetchCmsContentForPage } from "@/helpers/cms-content-helper"; -import baseMixin from "@/mixins/base-mixin.js"; - -// Mock our module for promises. -jest.mock("@/helpers/layout-helper.js", () => ({ - settleAllPromises: jest.fn(), -})); - -// Mock fetchCmsContentForPage -jest.mock("@/helpers/cms-content-helper", () => ({ - fetchCmsContentForPage: jest.fn(), -})); - -// Mock Store -jest.mock("@/store", () => ({ - commit: jest.fn(), - dispatch: jest.fn(), - getters: { - vehicle: { - make: "Acura", - }, - }, -})); - -describe("vehicle-model.vue", () => { - test("Model question component is initized with api data", async (done) => { - //Arange - const modelQuestionInitialData = ["accord", "civic", "insight"]; - const { wrapper, apiPromise } = setupMocks({ - modelQuestionInitialData: modelQuestionInitialData, - }); - //Act - vehicleModel.beforeRouteEnter.call( - wrapper.vm, - { query: { fmgPage: "vehicle-model" } }, - undefined, - (c) => c(wrapper.vm) - ); - //Assert - apiPromise.finally(() => { - expect(modelQuestion.methods.initializeComponent).toHaveBeenCalledWith( - modelQuestionInitialData - ); - done(); - }); - }); -}); - -describe("vehicle-model.vue", () => { - test("BackButtonAction triggers a router.navigateWithoutSaving change", async (done) => { - //Arrange - const { wrapper, apiPromise } = setupMocks({ - pageHeaderWidgetHeaderText: "Select a model to get started", - mountOptionsMockData: { - router: { - navigate: jest.fn(), - navigateWithoutSaving: jest.fn(), - }, - }, - }); - //Act - vehicleModel.beforeRouteEnter.call( - wrapper.vm, - { query: { fmgPage: "vehicle-model" } }, - undefined, - (c) => c(wrapper.vm) - ); - wrapper.vm.backButtonAction(); - await nextTick(); - //Assert - apiPromise.finally(() => { - expect(wrapper.vm.$router.navigateWithoutSaving).toHaveBeenCalled(); - done(); - }); - }); -}); -describe("vehicle-model.vue", () => { - test("Make set, arePagePrerequisitesValid should be true ", async () => { - //Arrange - const { wrapper } = setupMocks({}); - - //Act - vehicleModel.beforeRouteEnter.call( - wrapper.vm, - { query: { fmgPage: "vehicle-model" } }, - undefined, - (c) => c(wrapper.vm) - ); - - let arePagePrerequisitesValid = wrapper.vm.arePagePrerequisitesValid(); - await nextTick(); - - //Assert - expect(arePagePrerequisitesValid).toBe(true); - }); -}); - -function setupMocks({ - buttonQuestionContent = {}, - modelQuestionInitialData = {}, - pageHeaderWidgetHeaderText = {}, - mountOptionsMockData = {}, -}) { - //Mock api responses - const apiResponses = { - cmsContent: { - FunnelSubHeaderWidget: pageHeaderWidgetHeaderText, - VehicleModelQuestion: buttonQuestionContent, - VehicleBannerWidget: { - GenericVehicleImage: - "https://digitalconsumercms-dev.safelite.com/images/default-source/default-album/blurred-image.jpg?sfvrsn=a6ce3034_3", - }, - FunnelHeaderWidget: { - LogoImage: - "https://digitalconsumercms-dev.safelite.com/images/default-source/default-album/safelite-logo.svg?sfvrsn=45e7ed06_3", - }, - }, - modelQuestionInitialData: modelQuestionInitialData, - }; - const apiPromise = Promise.resolve(apiResponses); - - settleAllPromises.mockImplementation(() => apiPromise); - fetchCmsContentForPage.mockImplementation(() => Promise.resolve()); - - //Mock model question methods - modelQuestion.methods = { - loadInitialData: jest.fn(), - initializeComponent: jest.fn(), - }; - const mountOptions = getMountOptions(mountOptionsMockData); - const wrapper = shallowMount(vehicleModel, mountOptions); - wrapper.vm.setCmsContent = baseMixin.methods.setCmsContent; - - const modelQuestionWrapper = wrapper.findComponent({ name: "modelQuestion" }); - modelQuestionWrapper.vm.initializeComponent = modelQuestion.methods.initializeComponent; - - return { wrapper, apiPromise }; -} diff --git a/src/layouts/vehicle-model/vehicle-model.vue b/src/layouts/vehicle-model/vehicle-model.vue deleted file mode 100644 index d15c170c6..000000000 --- a/src/layouts/vehicle-model/vehicle-model.vue +++ /dev/null @@ -1,98 +0,0 @@ - - - diff --git a/src/layouts/vehicle-style/style-question/style-question.spec.js b/src/layouts/vehicle-style/style-question/style-question.spec.js deleted file mode 100644 index c02301316..000000000 --- a/src/layouts/vehicle-style/style-question/style-question.spec.js +++ /dev/null @@ -1,79 +0,0 @@ -import styleQuestion from "@/layouts/vehicle-style/style-question/style-question"; -import { shallowMount } from "@vue/test-utils"; -import { getMountOptions } from "@/helpers/unit-test-helper.js"; -import store from "@/store"; -jest.mock( - "@/store", - () => { - return {}; - }, - { virtual: true } -); - -describe("style-question.vue", () => { - test("Selected style is emitted upon selection.", async () => { - //Arrange - const { wrapper } = setupMocks({ modelValueProp: "2 Door" }); - const styleToSelect = "4 Door"; - - //Act - wrapper.setValue({ selectedStyle: styleToSelect }); - await wrapper.vm.$nextTick(); - - //Assert - expect(wrapper.emitted()["update:modelValue"][0]).toEqual([{ selectedStyle: "4 Door" }]); - }); -}); - -describe("style-question.vue", () => { - test("Data from store api are used as radio question answers.", async () => { - //Arrange - const { wrapper, cmsContent } = setupMocks({ - dataFromStoreApi: ["2 Door", "4 Door"], - }); - - //Act - const initialData = styleQuestion.methods.loadInitialData.call(wrapper.vm); - styleQuestion.methods.initializeComponent.call(wrapper.vm, initialData); - - //Assert - const buttonQuestionComponent = await wrapper.findComponent({ - name: "buttonQuestion", - }); - expect(buttonQuestionComponent.attributes("answers")).toBe("2 Door,4 Door"); - }); -}); - -function setupMocks({ - modelValueProp = "1900", - cmsQuestionText = "CMS text goes here", - dataFromStoreApi = [], -}) { - //Mock store - store.dispatch = jest.fn(() => dataFromStoreApi); - store.getters = { vehicle: { year: 2019, make: "honda", model: "civc" } }; - const mountOptions = getMountOptions({ - store: { - dispatch: store.dispatch, - getters: store.getters, - }, - }); - - //Mock props - const mockMixin = { - methods: { - getCmsContent: jest.fn(), - }, - }; - mountOptions.propsData = { - modelValue: modelValueProp, - }; - mountOptions.mixins = [mockMixin]; - const wrapper = shallowMount(styleQuestion, mountOptions); - - //Mock CMS content - const cmsContent = { - QuestionText: cmsQuestionText, - }; - return { wrapper, cmsContent }; -} diff --git a/src/layouts/vehicle-style/style-question/style-question.vue b/src/layouts/vehicle-style/style-question/style-question.vue deleted file mode 100644 index 0bfd00f7c..000000000 --- a/src/layouts/vehicle-style/style-question/style-question.vue +++ /dev/null @@ -1,61 +0,0 @@ - - - diff --git a/src/layouts/vehicle-style/vehicle-style.spec.js b/src/layouts/vehicle-style/vehicle-style.spec.js deleted file mode 100644 index f7dacb6b4..000000000 --- a/src/layouts/vehicle-style/vehicle-style.spec.js +++ /dev/null @@ -1,256 +0,0 @@ -// Components -import vehicleStyle from "@/layouts/vehicle-style/vehicle-style.vue"; -import styleQuestion from "@/layouts/vehicle-style/style-question/style-question"; - -// Supporting files -import { settleAllPromises } from "@/helpers/layout-helper.js"; -import { nextTick } from "vue"; -import { shallowMount } from "@vue/test-utils"; -import { getMountOptions } from "@/helpers/unit-test-helper.js"; -import { storeActions } from "@/constants/store-actions"; -import { fetchCmsContentForPage } from "@/helpers/cms-content-helper"; -import baseMixin from "@/mixins/base-mixin.js"; -import router from "@/router"; -import store from "@/store"; -import { storeMutations } from "@/constants/store-mutations"; - -// Mock our module for promises. -jest.mock("@/helpers/layout-helper.js", () => ({ - settleAllPromises: jest.fn(), -})); - -// Mock fetchCmsContentForPage -jest.mock("@/helpers/cms-content-helper", () => ({ - fetchCmsContentForPage: jest.fn(), -})); - -// Mock fetchCmsContentForPage -jest.mock("@/router", () => ({ - overrideNavigation: jest.fn(), -})); - -describe("vehicle-style.vue", () => { - beforeEach(() => { - jest.clearAllMocks(); - }); - - test("Style question component is initized with api data", async (done) => { - //Arrange - const styleQuestionInitialData = ["2 Door", "4 Door"]; - const { wrapper, apiPromise } = setupMocks({ - styleQuestionInitialData: styleQuestionInitialData, - }); - - //Act - vehicleStyle.beforeRouteEnter.call( - wrapper.vm, - { query: { fmgPage: "vehicle-style" } }, - undefined, - (c) => c(wrapper.vm) - ); - - //Assert - apiPromise.finally(() => { - expect(styleQuestion.methods.initializeComponent).toHaveBeenCalledWith( - styleQuestionInitialData - ); - done(); - }); - }); - - test("BackButtonAction triggers a router.navigateWithoutSaving change", async (done) => { - //Arrange - const { wrapper, apiPromise } = setupMocks({ - pageHeaderWidgetHeaderText: "Select a style to get started", - mountOptionsMockData: { - router: { - navigate: jest.fn(), - navigateWithSaving: jest.fn(), - navigateWithoutSaving: jest.fn(), - }, - }, - }); - - //Act - vehicleStyle.beforeRouteEnter.call( - wrapper.vm, - { query: { fmgPage: "vehicle-style" } }, - undefined, - (c) => c(wrapper.vm) - ); - wrapper.vm.backButtonAction(); - await nextTick(); - - //Assert - apiPromise.finally(() => { - expect(wrapper.vm.$router.navigateWithoutSaving).toHaveBeenCalled(); - done(); - }); - }); - - test("setVehicle triggers a dispatchStoreAction commit", async (done) => { - //Arrange - const { wrapper, apiPromise } = setupMocks({ - pageHeaderWidgetHeaderText: "Select a style to get started", - mountOptionsMockData: { - actionList: [ - { - actionName: storeActions.SET_VEHICLE, - data: "mockData", - }, - ], - }, - }); - - //Act - vehicleStyle.beforeRouteEnter.call( - wrapper.vm, - { query: { fmgPage: "vehicle-style" } }, - undefined, - (c) => c(wrapper.vm) - ); - wrapper.vm.setVehicle(); - await nextTick(); - - //Assert - apiPromise.finally(() => { - expect(wrapper.vm.dispatchStoreAction).toHaveBeenCalled(); - done(); - }); - }); - - test("Model set, arePagePrerequisitesValid should be true ", async () => { - //Arrange - const { wrapper } = setupMocks({}); - - //Act - vehicleStyle.beforeRouteEnter.call( - wrapper.vm, - { query: { fmgPage: "vehicle-style" } }, - undefined, - (c) => c(wrapper.vm) - ); - - let arePagePrerequisitesValid = wrapper.vm.arePagePrerequisitesValid(); - await nextTick(); - - //Assert - expect(arePagePrerequisitesValid).toBe(true); - }); - - test("there is only one vehicle style => autoselect and move to vehicle damage", async () => { - //Arrange - const { wrapper } = setupMocks({ - styleQuestionInitialData: ["2 door sedan"], - }); - - // Act - await vehicleStyle.beforeRouteEnter.call( - wrapper.vm, - { query: { fmgPage: "vehicle-style" } }, - undefined, - (c) => c(wrapper.vm) - ); - - // Assert - expect(store.commit).toHaveBeenCalledWith(storeMutations.UPDATE_STYLE, "2 door sedan"); - expect(router.overrideNavigation).toHaveBeenCalled(); - }); - - test("there is only one vehicle style and vehicle-damage was visited => don't autoselect or move to vehicle damage", async () => { - //Arrange - const { wrapper } = setupMocks({ - styleQuestionInitialData: ["2 door sedan"], - mountOptionsMockData: { - store: { - getters: { - applicationUser: { - pageData: { - "part-questions": null, - "vehicle-make": {}, - "vehicle-model": {}, - "vehicle-style": {}, - "vehicle-damage": {}, - }, - }, - }, - }, - }, - }); - - // Act - await vehicleStyle.beforeRouteEnter.call( - wrapper.vm, - { query: { fmgPage: "vehicle-style" } }, - undefined, - (c) => c(wrapper.vm) - ); - - // Assert - expect(store.commit).not.toHaveBeenCalledWith(storeMutations.UPDATE_STYLE, "2 door sedan"); - expect(router.overrideNavigation).not.toHaveBeenCalled(); - }); -}); - -function setupMocks({ - vehicleStyleQuestionCmsContent = {}, - styleQuestionInitialData = {}, - pageHeaderWidgetHeaderText = {}, - mountOptionsMockData = {}, -}) { - //Mock api responses - const apiResponses = { - cmsContent: { - FunnelSubHeaderWidget: pageHeaderWidgetHeaderText, - VehicleStyleQuestion: vehicleStyleQuestionCmsContent, - VehicleBannerWidget: { - GenericVehicleImage: - "https://digitalconsumercms-dev.safelite.com/images/default-source/default-album/blurred-image.jpg?sfvrsn=a6ce3034_3", - }, - FunnelHeaderWidget: { - LogoImage: - "https://digitalconsumercms-dev.safelite.com/images/default-source/default-album/safelite-logo.svg?sfvrsn=45e7ed06_3", - }, - }, - styleQuestionInitialData: styleQuestionInitialData, - }; - - const apiPromise = Promise.resolve(apiResponses); - - settleAllPromises.mockImplementation(() => apiPromise); - fetchCmsContentForPage.mockImplementation(() => Promise.resolve()); - - //Mock style question methods - styleQuestion.methods = { - loadInitialData: jest.fn(), - initializeComponent: jest.fn(), - }; - - store.commit = jest.fn(); - store.dispatch = jest.fn(); - store.getters = mountOptionsMockData.store?.getters ?? { - vehicle: { - model: "TL", - }, - applicationUser: { - pageData: { - "part-questions": null, - "vehicle-make": {}, - "vehicle-model": {}, - "vehicle-style": {}, - }, - }, - }; - - const mountOptions = getMountOptions({ - ...mountOptionsMockData, - store, - }); - const wrapper = shallowMount(vehicleStyle, mountOptions); - wrapper.vm.setCmsContent = baseMixin.methods.setCmsContent; - - const styleQuestionWrapper = wrapper.findComponent({ name: "styleQuestion" }); - styleQuestionWrapper.vm.initializeComponent = styleQuestion.methods.initializeComponent; - - return { wrapper, apiPromise }; -} diff --git a/src/layouts/vehicle-style/vehicle-style.vue b/src/layouts/vehicle-style/vehicle-style.vue deleted file mode 100644 index 2d2a4a534..000000000 --- a/src/layouts/vehicle-style/vehicle-style.vue +++ /dev/null @@ -1,137 +0,0 @@ - - - diff --git a/src/layouts/vehicle-year/vehicle-year.spec.js b/src/layouts/vehicle-year/vehicle-year.spec.js deleted file mode 100644 index ad024f131..000000000 --- a/src/layouts/vehicle-year/vehicle-year.spec.js +++ /dev/null @@ -1,122 +0,0 @@ -import { shallowMount, flushPromises } from "@vue/test-utils"; -import { getMountOptions } from "@/helpers/unit-test-helper.js"; -import { settleAllPromises } from "@/helpers/layout-helper.js"; -import { nextTick } from "vue"; -import { storeMutations } from "@/constants/store-mutations"; -import { storeActions } from "@/constants/store-actions"; -import { fetchCmsContentForPage } from "@/helpers/cms-content-helper"; -import baseMixin from "@/mixins/base-mixin.js"; - -import vehicleYear from "@/layouts/vehicle-year/vehicle-year.vue"; -import yearQuestion from "@/layouts/vehicle-year/year-question/year-question"; - -import store from "@/store"; - -jest.mock("@/store", () => ({ - commit: jest.fn(), - dispatch: jest.fn(), - getters: { - applicationUser: { - experiments: [], - }, - }, -})); - -// Mock our module for promises. -jest.mock("@/helpers/layout-helper.js", () => ({ - settleAllPromises: jest.fn(), -})); - -// Mock fetchCmsContentForPage -jest.mock("@/helpers/cms-content-helper", () => ({ - fetchCmsContentForPage: jest.fn(), -})); - -describe("vehicle-year.vue", () => { - test("Year question component is initized with api data", async (done) => { - //Arrange - const yearQuestionInitialData = ["2023", "2022", "2021"]; - const { wrapper, apiPromise } = setupMocks({ - yearQuestionInitialData: yearQuestionInitialData, - }); - - //Act - vehicleYear.beforeRouteEnter.call( - wrapper.vm, - { query: { fmgPage: "vehicle-year" } }, - undefined, - (c) => c(wrapper.vm) - ); - - //Assert - apiPromise.finally(() => { - expect(yearQuestion.methods.initializeComponent).toHaveBeenCalledWith( - yearQuestionInitialData - ); - done(); - }); - }); -}); - -describe("vehicle-year.vue", () => { - test("arePagePrerequisitesValid should be true ", async () => { - //Arrange - const { wrapper } = setupMocks({}); - - //Act - vehicleYear.beforeRouteEnter.call( - wrapper.vm, - { query: { fmgPage: "vehicle-make" } }, - undefined, - (c) => c(wrapper.vm) - ); - - let arePagePrerequisitesValid = wrapper.vm.arePagePrerequisitesValid(); - await nextTick(); - - //Assert - expect(arePagePrerequisitesValid).toBe(true); - }); -}); - -function setupMocks({ - vehicleYearQuestionCmsContent = {}, - yearQuestionInitialData = {}, - pageHeaderWidgetHeaderText = {}, - mountOptionsMockData = {}, -}) { - //Mock api responses - const apiResponses = { - cmsContent: { - FunnelSubHeaderWidget: { HeaderText: pageHeaderWidgetHeaderText }, - VehicleYearQuestion: vehicleYearQuestionCmsContent, - VehicleBannerWidget: { - GenericVehicleImage: - "https://digitalconsumercms-dev.safelite.com/images/default-source/default-album/blurred-image.jpg?sfvrsn=a6ce3034_3", - }, - FunnelHeaderWidget: { - LogoImage: - "https://digitalconsumercms-dev.safelite.com/images/default-source/default-album/safelite-logo.svg?sfvrsn=45e7ed06_3", - }, - }, - yearQuestionInitialData: yearQuestionInitialData, - }; - const apiPromise = Promise.resolve(apiResponses); - - settleAllPromises.mockImplementation(() => apiPromise); - fetchCmsContentForPage.mockImplementation(() => Promise.resolve()); - - //Mock year question methods - yearQuestion.methods = { - loadInitialData: jest.fn(), - initializeComponent: jest.fn(), - }; - - const mountOptions = getMountOptions(mountOptionsMockData); - const wrapper = shallowMount(vehicleYear, mountOptions); - const yearQuestionWrapper = wrapper.findComponent({ name: "yearQuestion" }); - yearQuestionWrapper.vm.initializeComponent = yearQuestion.methods.initializeComponent; - wrapper.vm.setCmsContent = baseMixin.methods.setCmsContent; - - return { wrapper, apiPromise }; -} diff --git a/src/layouts/vehicle-year/vehicle-year.vue b/src/layouts/vehicle-year/vehicle-year.vue deleted file mode 100644 index 5b166151a..000000000 --- a/src/layouts/vehicle-year/vehicle-year.vue +++ /dev/null @@ -1,110 +0,0 @@ - - - diff --git a/src/layouts/vehicle-year/year-question/year-question.spec.js b/src/layouts/vehicle-year/year-question/year-question.spec.js deleted file mode 100644 index f6a1e5e71..000000000 --- a/src/layouts/vehicle-year/year-question/year-question.spec.js +++ /dev/null @@ -1,78 +0,0 @@ -import yearQuestion from "@/layouts/vehicle-year/year-question/year-question"; -import { shallowMount } from "@vue/test-utils"; -import { getMountOptions } from "@/helpers/unit-test-helper.js"; -import store from "@/store"; -jest.mock( - "@/store", - () => { - return {}; - }, - { virtual: true } -); - -describe("year-question.vue", () => { - test("Selected year is emitted upon selection.", async () => { - //Arrange - const { wrapper } = setupMocks({ modelValueProp: "2020" }); - const yearToSelect = "2021"; - - //Act - wrapper.setValue({ modelValue: yearToSelect }); - await wrapper.vm.$nextTick(); - - //Assert - expect(wrapper.emitted()["update:modelValue"][0]).toEqual([{ modelValue: "2021" }]); - }); -}); - -describe("year-question.vue", () => { - test("Data from store api are used as radio question answers.", async () => { - //Arrange - const { wrapper, cmsContent } = setupMocks({ - dataFromStoreApi: ["2023", "2022", "2021"], - }); - - //Act - const initialData = yearQuestion.methods.loadInitialData.call(wrapper.vm); - yearQuestion.methods.initializeComponent.call(wrapper.vm, initialData); - - //Assert - const buttonQuestionComponent = await wrapper.findComponent({ - name: "buttonQuestion", - }); - expect(buttonQuestionComponent.attributes("answers")).toBe("2023,2022,2021"); - }); -}); - -function setupMocks({ - modelValueProp = "1900", - cmsQuestionText = "CMS text goes here", - dataFromStoreApi = [], -}) { - //Mock store - store.dispatch = jest.fn(() => dataFromStoreApi); - const mountOptions = getMountOptions({ - store: { - dispatch: store.dispatch, - }, - }); - - //Mock props - const mockMixin = { - methods: { - getCmsContent: jest.fn(), - }, - }; - mountOptions.propsData = { - modelValue: modelValueProp, - }; - mountOptions.mixins = [mockMixin]; - - const wrapper = shallowMount(yearQuestion, mountOptions); - - //Mock CMS content - const cmsContent = { - QuestionText: cmsQuestionText, - }; - return { wrapper, cmsContent }; -} diff --git a/src/layouts/vehicle-year/year-question/year-question.vue b/src/layouts/vehicle-year/year-question/year-question.vue deleted file mode 100644 index 6d8110216..000000000 --- a/src/layouts/vehicle-year/year-question/year-question.vue +++ /dev/null @@ -1,55 +0,0 @@ - - - diff --git a/src/router/router-constants/fmgPage-values.js b/src/router/router-constants/fmgPage-values.js index fc8841c13..ba931f77d 100644 --- a/src/router/router-constants/fmgPage-values.js +++ b/src/router/router-constants/fmgPage-values.js @@ -1,8 +1,4 @@ const fmgPageValues = { - VEHICLE_YEAR: "vehicle-year", - VEHICLE_MAKE: "vehicle-make", - VEHICLE_MODEL: "vehicle-model", - VEHICLE_STYLE: "vehicle-style", VEHICLE: "vehicle", VEHICLE_DAMAGE: "vehicle-damage", ADDRESS_LOOKUP: "address-lookup", diff --git a/src/router/router-constants/navigation-scenarios.js b/src/router/router-constants/navigation-scenarios.js index ce2f32134..bf89f4f3f 100644 --- a/src/router/router-constants/navigation-scenarios.js +++ b/src/router/router-constants/navigation-scenarios.js @@ -12,12 +12,6 @@ const navigationScenarios = { CLICKED_FORWARD: "CLICKED_FORWARD", CLICKED_FORWARD_WITH_CASH: "CLICKED_FORWARD_WITH_CASH", - // YMMS - SELECTED_YEAR: "SELECTED_YEAR", - SELECTED_MODEL: "SELECTED_MODEL", - SELECTED_MAKE: "SELECTED_MAKE", - SELECTED_STYLE: "SELECTED_STYLE", - // Vin selection CLICKED_BACK_WITH_VIN: "CLICKED_BACK_WITH_VIN", CLICKED_FORWARD_WITH_VIN: "CLICKED_FORWARD_WITH_VIN", diff --git a/src/router/router-constants/routing-table.js b/src/router/router-constants/routing-table.js index f1f83b445..b90806e94 100644 --- a/src/router/router-constants/routing-table.js +++ b/src/router/router-constants/routing-table.js @@ -13,54 +13,7 @@ const routingTable = function (store) { }, ], }, - { - fmgPageValue: fmgPageValues.VEHICLE_YEAR, - maps: [ - { - scenario: navigationScenarios.SELECTED_YEAR, - destinationFmgPageValue: fmgPageValues.VEHICLE_MAKE, - }, - ], - }, - { - fmgPageValue: fmgPageValues.VEHICLE_MAKE, - maps: [ - { - scenario: navigationScenarios.SELECTED_MAKE, - destinationFmgPageValue: fmgPageValues.VEHICLE_MODEL, - }, - { - scenario: navigationScenarios.CLICKED_BACK, - destinationFmgPageValue: fmgPageValues.VEHICLE_YEAR, - }, - ], - }, - { - fmgPageValue: fmgPageValues.VEHICLE_MODEL, - maps: [ - { - scenario: navigationScenarios.SELECTED_MODEL, - destinationFmgPageValue: fmgPageValues.VEHICLE_STYLE, - }, - { - scenario: navigationScenarios.CLICKED_BACK, - destinationFmgPageValue: fmgPageValues.VEHICLE_MAKE, - }, - ], - }, - { - fmgPageValue: fmgPageValues.VEHICLE_STYLE, - maps: [ - { - scenario: navigationScenarios.SELECTED_STYLE, - destinationFmgPageValue: fmgPageValues.VEHICLE_DAMAGE, - }, - { - scenario: navigationScenarios.CLICKED_BACK, - destinationFmgPageValue: fmgPageValues.VEHICLE_MODEL, - }, - ], - }, + { fmgPageValue: fmgPageValues.VEHICLE_DAMAGE, maps: [ diff --git a/src/store/index.js b/src/store/index.js index 635d685b4..4345daf01 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -1568,88 +1568,6 @@ export const actions = { // Business domain actions // Vehicle - saveVehicleYear(context, year) { - //Reset dependent state when changing - if (context.state.order.vehicle.year !== year) { - context.commit(storeMutations.UPDATE_MAKE, null); - context.commit(storeMutations.UPDATE_MODEL, null); - context.commit(storeMutations.UPDATE_STYLE, null); - context.commit(storeMutations.UPDATE_CAR_ID, null); - context.commit(storeMutations.UPDATE_VEHICLE_CATEGORY, null); - context.commit(storeMutations.UPDATE_VEHICLE_VIN, null); - context.commit(storeMutations.UPDATE_VEHICLE_IMAGE_URL, null); - context.commit(storeMutations.UPDATE_VEHICLE_IMAGE_VIF_NUMBER, null); - context.commit(storeMutations.UPDATE_VEHICLE_IMAGE_COLOR, null); - - context.dispatch(storeActions.RESET_DAMAGE_STATE_AND_DEPENDENCIES); - context.dispatch(storeActions.RESET_REGISTRATION_STATE_AND_DEPENDENCIES); - context.dispatch(storeActions.RESET_PARTS_STATE_AND_DEPENDENCIES); - - //Save new values - context.commit(storeMutations.UPDATE_YEAR, year); - } - }, - - saveVehicleMake(context, make) { - //Reset dependent state when changing - if (context.state.order.vehicle.make !== make) { - context.commit(storeMutations.UPDATE_MODEL, null); - context.commit(storeMutations.UPDATE_STYLE, null); - context.commit(storeMutations.UPDATE_CAR_ID, null); - context.commit(storeMutations.UPDATE_VEHICLE_CATEGORY, null); - context.commit(storeMutations.UPDATE_VEHICLE_VIN, null); - context.commit(storeMutations.UPDATE_VEHICLE_IMAGE_URL, null); - context.commit(storeMutations.UPDATE_VEHICLE_IMAGE_VIF_NUMBER, null); - context.commit(storeMutations.UPDATE_VEHICLE_IMAGE_COLOR, null); - - context.dispatch(storeActions.RESET_DAMAGE_STATE_AND_DEPENDENCIES); - context.dispatch(storeActions.RESET_REGISTRATION_STATE_AND_DEPENDENCIES); - context.dispatch(storeActions.RESET_PARTS_STATE_AND_DEPENDENCIES); - - //Save new values - context.commit(storeMutations.UPDATE_MAKE, make); - } - }, - - saveVehicleModel(context, model) { - //Reset dependent state when changing - if (context.state.order.vehicle.model !== model) { - context.commit(storeMutations.UPDATE_STYLE, null); - context.commit(storeMutations.UPDATE_CAR_ID, null); - context.commit(storeMutations.UPDATE_VEHICLE_CATEGORY, null); - context.commit(storeMutations.UPDATE_VEHICLE_VIN, null); - context.commit(storeMutations.UPDATE_VEHICLE_IMAGE_URL, null); - context.commit(storeMutations.UPDATE_VEHICLE_IMAGE_VIF_NUMBER, null); - context.commit(storeMutations.UPDATE_VEHICLE_IMAGE_COLOR, null); - - context.dispatch(storeActions.RESET_DAMAGE_STATE_AND_DEPENDENCIES); - context.dispatch(storeActions.RESET_REGISTRATION_STATE_AND_DEPENDENCIES); - context.dispatch(storeActions.RESET_PARTS_STATE_AND_DEPENDENCIES); - - //Save new values - context.commit(storeMutations.UPDATE_MODEL, model); - } - }, - - saveVehicleStyle(context, style) { - //Reset dependent state when changing - if (context.state.order.vehicle.style !== style) { - context.commit(storeMutations.UPDATE_CAR_ID, null); - context.commit(storeMutations.UPDATE_VEHICLE_CATEGORY, null); - context.commit(storeMutations.UPDATE_VEHICLE_VIN, null); - context.commit(storeMutations.UPDATE_VEHICLE_IMAGE_URL, null); - context.commit(storeMutations.UPDATE_VEHICLE_IMAGE_VIF_NUMBER, null); - context.commit(storeMutations.UPDATE_VEHICLE_IMAGE_COLOR, null); - - context.dispatch(storeActions.RESET_DAMAGE_STATE_AND_DEPENDENCIES); - context.dispatch(storeActions.RESET_REGISTRATION_STATE_AND_DEPENDENCIES); - context.dispatch(storeActions.RESET_PARTS_STATE_AND_DEPENDENCIES); - - //Save new values - context.commit(storeMutations.UPDATE_STYLE, style); - } - }, - saveVehicle(context, { year, make, model, style, vehicle }) { context.dispatch(storeActions.RESET_PARTS_STATE_AND_DEPENDENCIES); diff --git a/src/store/store.spec.js b/src/store/store.spec.js index e072eb164..186cf2d31 100644 --- a/src/store/store.spec.js +++ b/src/store/store.spec.js @@ -1572,168 +1572,6 @@ describe("Actions", () => { expect(commit).toBeCalledWith(storeMutations.UPDATE_REGISTRATION, payload.registrationInfo); }); - it("saveVehicleYear, should wipe out vehicle info if year changes", () => { - // Arrange - const context = state; - - context.state = { - order: { - vehicle: { - year: "2015", - }, - }, - }; - - const commit = jest.fn(); - const dispatch = jest.fn(); - - context.commit = commit; - context.dispatch = dispatch; - - // Act - actions.saveVehicleYear(context, "2016"); - - // Assert - expect(dispatch).toHaveBeenNthCalledWith( - 1, - storeActions.RESET_DAMAGE_STATE_AND_DEPENDENCIES - ); - expect(dispatch).toHaveBeenNthCalledWith( - 2, - storeActions.RESET_REGISTRATION_STATE_AND_DEPENDENCIES - ); - - expect(commit).toBeCalledWith(storeMutations.UPDATE_MAKE, null); - expect(commit).toBeCalledWith(storeMutations.UPDATE_MODEL, null); - expect(commit).toBeCalledWith(storeMutations.UPDATE_STYLE, null); - expect(commit).toBeCalledWith(storeMutations.UPDATE_CAR_ID, null); - expect(commit).toBeCalledWith(storeMutations.UPDATE_VEHICLE_CATEGORY, null); - expect(commit).toBeCalledWith(storeMutations.UPDATE_VEHICLE_VIN, null); - expect(commit).toBeCalledWith(storeMutations.UPDATE_VEHICLE_IMAGE_URL, null); - expect(commit).toBeCalledWith(storeMutations.UPDATE_VEHICLE_IMAGE_VIF_NUMBER, null); - expect(commit).toBeCalledWith(storeMutations.UPDATE_VEHICLE_IMAGE_COLOR, null); - }); - - it("saveVehicleMake, should wipe out vehicle info if make changes", () => { - // Arrange - const context = state; - - context.state = { - order: { - vehicle: { - make: "Honda", - }, - }, - }; - - const commit = jest.fn(); - const dispatch = jest.fn(); - - context.commit = commit; - context.dispatch = dispatch; - - // Act - actions.saveVehicleMake(context, "Toyota"); - - // Assert - expect(dispatch).toHaveBeenNthCalledWith( - 1, - storeActions.RESET_DAMAGE_STATE_AND_DEPENDENCIES - ); - expect(dispatch).toHaveBeenNthCalledWith( - 2, - storeActions.RESET_REGISTRATION_STATE_AND_DEPENDENCIES - ); - - expect(commit).toBeCalledWith(storeMutations.UPDATE_MODEL, null); - expect(commit).toBeCalledWith(storeMutations.UPDATE_STYLE, null); - expect(commit).toBeCalledWith(storeMutations.UPDATE_CAR_ID, null); - expect(commit).toBeCalledWith(storeMutations.UPDATE_VEHICLE_CATEGORY, null); - expect(commit).toBeCalledWith(storeMutations.UPDATE_VEHICLE_VIN, null); - expect(commit).toBeCalledWith(storeMutations.UPDATE_VEHICLE_IMAGE_URL, null); - expect(commit).toBeCalledWith(storeMutations.UPDATE_VEHICLE_IMAGE_VIF_NUMBER, null); - expect(commit).toBeCalledWith(storeMutations.UPDATE_VEHICLE_IMAGE_COLOR, null); - }); - - it("saveVehicle model, should wipe out vehicle info if model changes", () => { - // Arrange - const context = state; - - context.state = { - order: { - vehicle: { - model: "Civic", - }, - }, - }; - - const commit = jest.fn(); - const dispatch = jest.fn(); - - context.commit = commit; - context.dispatch = dispatch; - - // Act - actions.saveVehicleModel(context, "Accord"); - - // Assert - expect(dispatch).toHaveBeenNthCalledWith( - 1, - storeActions.RESET_DAMAGE_STATE_AND_DEPENDENCIES - ); - expect(dispatch).toHaveBeenNthCalledWith( - 2, - storeActions.RESET_REGISTRATION_STATE_AND_DEPENDENCIES - ); - - expect(commit).toBeCalledWith(storeMutations.UPDATE_STYLE, null); - expect(commit).toBeCalledWith(storeMutations.UPDATE_CAR_ID, null); - expect(commit).toBeCalledWith(storeMutations.UPDATE_VEHICLE_CATEGORY, null); - expect(commit).toBeCalledWith(storeMutations.UPDATE_VEHICLE_VIN, null); - expect(commit).toBeCalledWith(storeMutations.UPDATE_VEHICLE_IMAGE_URL, null); - expect(commit).toBeCalledWith(storeMutations.UPDATE_VEHICLE_IMAGE_VIF_NUMBER, null); - expect(commit).toBeCalledWith(storeMutations.UPDATE_VEHICLE_IMAGE_COLOR, null); - }); - - it("saveVehicleStyle, should wipe out vehicle info if style changes", () => { - // Arrange - const context = state; - - context.state = { - order: { - vehicle: { - style: "Sedan", - }, - }, - }; - - const commit = jest.fn(); - const dispatch = jest.fn(); - - context.commit = commit; - context.dispatch = dispatch; - - // Act - actions.saveVehicleStyle(context, "SUV"); - - // Assert - expect(dispatch).toHaveBeenNthCalledWith( - 1, - storeActions.RESET_DAMAGE_STATE_AND_DEPENDENCIES - ); - expect(dispatch).toHaveBeenNthCalledWith( - 2, - storeActions.RESET_REGISTRATION_STATE_AND_DEPENDENCIES - ); - - expect(commit).toBeCalledWith(storeMutations.UPDATE_CAR_ID, null); - expect(commit).toBeCalledWith(storeMutations.UPDATE_VEHICLE_CATEGORY, null); - expect(commit).toBeCalledWith(storeMutations.UPDATE_VEHICLE_VIN, null); - expect(commit).toBeCalledWith(storeMutations.UPDATE_VEHICLE_IMAGE_URL, null); - expect(commit).toBeCalledWith(storeMutations.UPDATE_VEHICLE_IMAGE_VIF_NUMBER, null); - expect(commit).toBeCalledWith(storeMutations.UPDATE_VEHICLE_IMAGE_COLOR, null); - }); - it("saveVehicle, should save vehicle info", () => { // Arrange const context = state; From a8154dc8c640356764018c694b1935b256033f82 Mon Sep 17 00:00:00 2001 From: Adam Caouette Date: Mon, 14 Aug 2023 10:57:10 -0400 Subject: [PATCH 29/60] CSR-886: unit tests for Schedule page --- jest.config.js | 1 - .../address-lookup/address-lookup.spec.js | 1 - src/layouts/schedule/schedule.spec.js | 728 ++++++++++++++---- src/layouts/schedule/schedule.spec.js1 | 0 src/layouts/schedule/schedule.vue | 7 +- 5 files changed, 576 insertions(+), 161 deletions(-) create mode 100644 src/layouts/schedule/schedule.spec.js1 diff --git a/jest.config.js b/jest.config.js index 34a45f34a..633a99e67 100644 --- a/jest.config.js +++ b/jest.config.js @@ -17,7 +17,6 @@ module.exports = { "!src/ux-components/text-link/**/*.vue", "!src/layouts/vin-lookup/**/*.vue", //Temporary for Quote page testing "!src/common-components/funnel-header/menu-modal/**/*.vue", - "!src/layouts/schedule/*.vue", // Temp test exclusion while in development "!src/layouts/schedule/helpers/schedule-helper.js", // Temp test exclusion while in development "!src/layouts/review/*.vue", // Temp test exclusion while in development // END diff --git a/src/layouts/address-lookup/address-lookup.spec.js b/src/layouts/address-lookup/address-lookup.spec.js index 2c4b44950..63847588b 100644 --- a/src/layouts/address-lookup/address-lookup.spec.js +++ b/src/layouts/address-lookup/address-lookup.spec.js @@ -681,7 +681,6 @@ function setupMocks({ }, ], router: { - navigate: jest.fn(), navigate: jest.fn(), navigateWithSaving: jest.fn(), navigateWithoutSaving: jest.fn(), diff --git a/src/layouts/schedule/schedule.spec.js b/src/layouts/schedule/schedule.spec.js index 2c4bafc33..56b2ce13b 100644 --- a/src/layouts/schedule/schedule.spec.js +++ b/src/layouts/schedule/schedule.spec.js @@ -1,15 +1,77 @@ +// Components +import schedule from "@/layouts/schedule/schedule.vue"; + +// Supporting Files import { shallowMount } from "@vue/test-utils"; import { getMountOptions } from "@/helpers/unit-test-helper.js"; -import { applicationConfig } from "@/constants/application-config"; -import { storeActions } from "@/constants/store-actions"; -import schedule from "@/layouts/schedule/schedule.vue"; import store from "@/store"; -import * as navigateToHeritage from "@/helpers/heritage-integration/navigation-helper"; +import router from "@/router"; import { nextTick } from "vue"; +import baseMixin from "../../mixins/base-mixin"; -jest.mock("@/store", () => ({ - commit: jest.fn(), - dispatch: jest.fn(), +// Mock basemixin +jest.mock("@/mixins/base-mixin.js", () => ({ + methods: { + dispatchStoreAction: jest.fn().mockImplementation((storeAction) => { + if (storeAction === "getShopTimeSlots") { + return { + data: { + estimatedServiceMinutesMinimum: 90, + estimatedServiceMinutesMaximum: 120, + days: [ + { + date: "2023-12-01", + timeSlots: [ + { + id: "06747-01820-S-B*20424*7 AM", + startTime: "07:00", + endTime: "08:00", + offerPremium: false, + }, + ], + }, + ], + }, + }; + } + if (storeAction === "getMobilePremiumFee") { + return Promise.resolve({ + data: { + partNumber: "EARLY BIRD", + description: null, + partType: "EARLY BIRD", + laborAmount: 0, + sellingPrice: 14.99, + kitPrice: 0, + }, + }); + } + if (storeAction === "priceOrderItemsAndSaveServerData") { + return Promise.resolve([ + { + partNumber: "EARLY BIRD", + description: null, + partType: "EARLY BIRD", + laborAmount: 0, + sellingPrice: 14.99, + kitPrice: 0, + }, + ]); + } + if (storeAction === "saveSupportingItemsSuppressingStateResetting") { + return Promise.resolve([ + { + partNumber: "EARLY BIRD", + description: null, + partType: "EARLY BIRD", + laborAmount: 0, + sellingPrice: 14.99, + kitPrice: 0, + }, + ]); + } + }), + }, })); // Mock fetchCmsContentForPage @@ -18,50 +80,415 @@ jest.mock("@/helpers/cms-content-helper", () => ({ splitCopyOnCMSPlaceHolder: jest.fn(() => ["A", "B"]), })); -jest.mock( - "@/store", - () => { - return {}; - }, - { virtual: true } -); - -store.getters = { - order: { - schedule: { - date: "2020-01-01", +beforeEach(() => { + jest.restoreAllMocks(); + jest.clearAllMocks(); + store.getters = { + order: { + schedule: { + date: "2019-01-01", + startTime: "09:00", + endTime: "10:00", + routeCode: "000" + }, + lineItems: { + glassParts: [ + { + partNumber: "ABC123", + }, + ], + supportingItems: [], + }, + serviceLocation: { + appointmentType: "Inshop", + zipCode: "12345", + zipCodeCtu: "01234", + provider: { + providerNumber: "123", + }, + }, + damage: { + isRepair: false, + }, + referralNumber: "1234567", + }, + payment: { + isInsurance: true, }, lineItems: { glassParts: [], supportingItems: [], }, - serviceLocation: { - appointmentType: "Inshop", - }, - }, - lineItems: { - glassParts: [], - supportingItems: [], - }, -}; + }; +}); +afterEach(() => { + store.getters = {}; + jest.restoreAllMocks(); + jest.clearAllMocks(); +}); -describe("schedule.vue", () => { - test("Should navigateWithoutSaving", async () => { - //Arrange - const { wrapper } = setupMocks({ - customMountOptions: { - router: { - navigateWithSaving: jest.fn(), - }, - route: { schedule }, - }, +describe("schedule.vue...", () => { + describe("initial load", () => { + test("should pass arePagePrerequisitesValid with a mobile order and no providerNumber", () => { + //Arrange + const { wrapper } = setupMocks({}); + store.getters.order.serviceLocation.appointmentType = "Mobile"; + store.getters.order.serviceLocation.provider = null; + + //Act + const arePagePrerequisitesValid = wrapper.vm.arePagePrerequisitesValid(); + + //Assert + expect(arePagePrerequisitesValid).toBe(true); + }); + test("should pass arePagePrerequisitesValid with a inshop order and providerNumber", () => { + //Arrange + const { wrapper } = setupMocks({}); + + //Act + const arePagePrerequisitesValid = wrapper.vm.arePagePrerequisitesValid(); + + //Assert + expect(arePagePrerequisitesValid).toBe(true); + }); + test("should fail arePagePrerequisitesValid with a replace with no glass parts", async () => { + //Arrange + const { wrapper } = setupMocks({}); + store.getters.order.lineItems.glassParts = []; + + //Act + const arePagePrerequisitesValid2 = await wrapper.vm.arePagePrerequisitesValid(); + + //Assert + expect(arePagePrerequisitesValid2).toBe(false); + }); + test("should fail arePagePrerequisitesValid without isInsurance", () => { + //Arrange + const { wrapper } = setupMocks({}); + store.getters.payment.isInsurance = null; + + //Act + const arePagePrerequisitesValid = wrapper.vm.arePagePrerequisitesValid(); + + //Assert + expect(arePagePrerequisitesValid).toBe(false); }); + test("should return newShopTimeSlots when getAvailableDatesMethod is called", async () => { + //Arrange + const { wrapper } = setupMocks({}); + wrapper.vm.selectableDatesData = { + days: [], + }; + + //Act + const newShopTimeSlots = await wrapper.vm.getAvailableDatesMethod( + "2023-01-01", + "2023-01-31" + ); + + //Assert + expect(newShopTimeSlots).toStrictEqual({ + days: [ + { + date: "2023-12-01", + timeSlots: [ + { + endTime: "08:00", + id: "06747-01820-S-B*20424*7 AM", + offerPremium: false, + startTime: "07:00", + }, + ], + }, + ], + estimatedServiceMinutesMinimum: 90, + estimatedServiceMinutesMaximum: 120, + }); + }); + + test("should call API service in day ranges of 34 or less when getAvailableDatesMethod is called with large date ranges", async () => { + //Arrange + const { wrapper } = setupMocks({}); + wrapper.vm.selectableDatesData = { + days: [], + }; + + //Act + await wrapper.vm.getAvailableDates.call( + wrapper.vm, + "2023-01-01", + "2023-03-31", + "Inshop", + "123" + ); + + //Assert + expect(baseMixin.methods.dispatchStoreAction).toHaveBeenCalledTimes(3); + expect(baseMixin.methods.dispatchStoreAction).toHaveBeenCalledWith( + "getShopTimeSlots", + expect.anything(), + expect.anything() + ); + }); + + describe("beforeRouteEnter function... ", () => { + test("should call next() and call all functions within next", async () => { + //Arrange + const { wrapper } = setupMocks({}); + wrapper.vm.selectableDatesData = { + days: [], + }; + wrapper.vm.updateFooterButtonText = jest.fn(); + const nextFunction = jest.fn((c) => { + c(wrapper.vm); + }); + + //Act + await schedule.beforeRouteEnter.call( + wrapper.vm, + { query: { fmgPage: "schedule" } }, + undefined, + nextFunction + ); + + //Assert + expect(nextFunction).toHaveBeenCalled(); + expect(wrapper.vm.setCmsContent).toHaveBeenCalledWith("content"); + expect(wrapper.vm.$refs.datePicker.initializeComponent).toHaveBeenCalledWith( + expect.objectContaining({ + calendarViewDirection: "future", + }) + ); + expect(wrapper.vm.$refs.locationAlerts.initializeComponent).toHaveBeenCalled(); + expect(wrapper.vm.selectableDatesData).toStrictEqual( + expect.objectContaining({ + days: expect.any(Array), + estimatedServiceMinutesMaximum: expect.any(Number), + estimatedServiceMinutesMinimum: expect.any(Number) + }) + ); + expect(wrapper.vm.mobilePremiumAppointmentFee).toStrictEqual( + expect.objectContaining({ + partNumber: expect.any(String) + }) + ); + expect(wrapper.vm.updateFooterButtonText).toHaveBeenCalled(); + }); + + }); + + describe("computed properties...", () => { + + test("timeSlotsForSelectedDate should return timeslots if selected date is available", () => { + //Arrange + const { wrapper } = setupMocks({}); + wrapper.vm.selectableDatesData = { + days: [{ + "date": "2022-11-11", + "timeSlots": [ + { + "id": "1820I-01820-M-I*20425*AM", + "startTime": "08:00", + "endTime": "12:00", + "offerPremium": true + }, + { + "id": "1820I-01820-M-I*20425*PM", + "startTime": "12:00", + "endTime": "17:00", + "offerPremium": false + } + ] + }], + }; + wrapper.setData({ + selectedDate: "2022-11-11" + }); + + //Act + const testValue = wrapper.vm.timeSlotsForSelectedDate; + + //Assert + expect(testValue).toStrictEqual( + expect.objectContaining({ + "date": "2022-11-11" + }) + ); + + }); + + test("timeSlotsForSelectedDate should be null if no date has been selected", () => { + //Arrange + const { wrapper } = setupMocks({}); + wrapper.vm.selectableDatesData = { + days: [{ + "date": "2022-11-11", + "timeSlots": [ + { + "id": "1820I-01820-M-I*20425*AM", + "startTime": "08:00", + "endTime": "12:00", + "offerPremium": true + }, + { + "id": "1820I-01820-M-I*20425*PM", + "startTime": "12:00", + "endTime": "17:00", + "offerPremium": false + } + ] + }], + }; + wrapper.setData({ + selectedDate: undefined + }); + + //Act + const testValue = wrapper.vm.timeSlotsForSelectedDate; + + //Assert + expect(testValue).toBe(null) + + }); + + }); + }); + + describe("schedule page methods...", () => { + test("getServiceZipCtuCodeFromStore should return zipCodeCtu", () => { + //Arrange + const { wrapper } = setupMocks({}); + wrapper.vm.selectableDatesData = { + days: [], + }; + + //Act + const testValue = wrapper.vm.getServiceZipCtuCodeFromStore(); + + //Assert + expect(testValue).toStrictEqual( + "01234" + ); + + }); + + test("openInshopTimeSlotsModal should trigger openModal method", () => { + //Arrange + const { wrapper } = setupMocks({}); + wrapper.vm.selectableDatesData = { + days: [], + }; + + //Act + wrapper.vm.openInshopTimeSlotsModal(); + + //Assert + expect(wrapper.vm.$refs.timeSlotModalQuestion.openModal).toBeCalled(); + + }); + + test("getSelectedRouteCode should return schedule routeCode", () => { + //Arrange + const { wrapper } = setupMocks({}); + + wrapper.vm.selectableDatesData = { + days: [], + }; + + //Act + const testValue = wrapper.vm.getSelectedRouteCode(); + + //Assert + expect(testValue).toStrictEqual( + "000" + ); + + }); + + + + test("timeSlotModalClosed should null any selected date when there's no route code", () => { + //Arrange + const { wrapper } = setupMocks({}); + wrapper.vm.selectableDatesData = { + days: [], + }; + wrapper.setData({ + selectedDate: "1980-05-05" + }); + wrapper.setData({ + selectedTimeSlot: { + date: "2019-01-01", + startTime: "09:00", + endTime: "10:00", + routeCode: null + } + }); + + //Act + wrapper.vm.timeSlotModalClosed(); + + //Assert + expect(wrapper.vm.selectedDate).toBe(null); + + }); + + + test("getDisplayTextForMilitaryTime should return the correctly formatted string", () => { + //Arrange + const { wrapper } = setupMocks({}); + wrapper.vm.selectableDatesData = { + days: [], + }; + const timeInput1 = "15:00"; + const timeInput2 = "15:30"; + + //Act + const testOutput1 = wrapper.vm.getDisplayTextForMilitaryTime(timeInput1); + const testOutput2 = wrapper.vm.getDisplayTextForMilitaryTime(timeInput2); + const testOutput3 = wrapper.vm.getDisplayTextForMilitaryTime(timeInput1, true); + const testOutput4 = wrapper.vm.getDisplayTextForMilitaryTime(timeInput2, true); + + //Assert + expect(testOutput1).toBe("3:00 PM"); + expect(testOutput2).toBe("3:30 PM"); + expect(testOutput3).toBe("3 PM"); + expect(testOutput4).toBe("3:30 PM"); + + }); + + test("getDisplayTextForMilitaryTime should return the correctly formatted string", () => { + //Arrange + const { wrapper } = setupMocks({}); + wrapper.vm.selectableDatesData = { + days: [], + }; + wrapper.vm.$router.navigateWithoutSaving = jest.fn(); + wrapper.vm.$route = "testRoute"; + + //Act + wrapper.vm.backButtonAction(); + + //Assert + expect(wrapper.vm.$router.navigateWithoutSaving).toBeCalledWith("CLICKED_BACK", "testRoute"); + + }); + + + }); + + test("forwardButtonAction should call route method navigateWithoutSaving", async () => { + //Arrange + const { wrapper } = setupMocks({}); wrapper.vm.dispatchStoreAction = jest.fn(() => { return { data: [], }; }); + wrapper.vm.$router.navigateWithSaving = jest.fn(() => { + return {}; + }); //Act await wrapper.vm.forwardButtonAction(); @@ -69,137 +496,125 @@ describe("schedule.vue", () => { //Assert expect(wrapper.vm.$router.navigateWithSaving).toHaveBeenCalled(); }); - test("should pass arePagePrerequisitesValid with a mobile order and no providerNumber", () => { + + + test("for mobile appts, updateSupportingItems should call store action to save supporting items", async () => { //Arrange + store.getters.order.serviceLocation.appointmentType = "Mobile"; + store.getters.lineItems.supportingItems = [{ + "partNumber": "EARLY BIRD", + "description": null, + "partType": "EARLY BIRD", + "laborAmount": 0, + "sellingPrice": 0, + "kitPrice": 0 + }]; const { wrapper } = setupMocks({}); - store.getters = { - order: { - schedule: { - date: "2020-01-01", - }, - serviceLocation: { - zipCode: "12345", - zipCodeCtu: "value", - appointmentType: "Mobile", - }, - damage: { - isRepair: true, - }, - referralNumber: "1234567", - }, - payment: { - isInsurance: true, - }, - lineItems: { - supportingItems: [], - }, - }; + wrapper.vm.dispatchStoreAction = jest.fn(() => { + return { + data: [], + }; + }); + wrapper.vm.mobilePremiumAppointmentFee = 14.99; + wrapper.setData({ + selectedTimeSlot: { + date: "2019-01-01", + startTime: "09:00", + endTime: "10:00", + routeCode: null, + isPremiumAppointment: true + } + }); - let arePagePrerequisitesValid = wrapper.vm.arePagePrerequisitesValid(); + //Act + await wrapper.vm.updateSupportingItems(); + + //Assert + expect(wrapper.vm.dispatchStoreAction).toBeCalledWith( + "saveSupportingItemsSuppressingStateResetting", + expect.arrayContaining([ + expect.objectContaining({ + partType: "EARLY BIRD" + }) + ]), + expect.anything() + ); - expect(arePagePrerequisitesValid).toBe(true); }); - test("should pass arePagePrerequisitesValid with a inshop order and providerNumber", () => { + + test("for Inshop appts, updateSupportingItems should call store action to save supporting items WITHOUT the EARLY BIRD supporting item", async () => { //Arrange + store.getters.order.serviceLocation.appointmentType = "Inshop"; + store.getters.lineItems.supportingItems = [{ + "partNumber": "EARLY BIRD", + "description": null, + "partType": "EARLY BIRD", + "laborAmount": 0, + "sellingPrice": 0, + "kitPrice": 0 + }]; const { wrapper } = setupMocks({}); - store.getters = { - order: { - schedule: { - date: "2020-01-01", - }, - serviceLocation: { - zipCode: "12345", - zipCodeCtu: "value", - appointmentType: "Inshop", - provider: { - providerNumber: "5", - }, - }, - damage: { - isRepair: true, - }, - referralNumber: "1234567", - }, - payment: { - isInsurance: true, - }, - lineItems: { - supportingItems: [], - }, - }; + wrapper.vm.dispatchStoreAction = jest.fn(() => { + return { + data: [], + }; + }); + wrapper.vm.mobilePremiumAppointmentFee = 14.99; + wrapper.setData({ + selectedTimeSlot: { + date: "2019-01-01", + startTime: "09:00", + endTime: "10:00", + routeCode: null, + isPremiumAppointment: true + } + }); - let arePagePrerequisitesValid = wrapper.vm.arePagePrerequisitesValid(); + //Act + await wrapper.vm.updateSupportingItems(); + + //Assert + expect(wrapper.vm.dispatchStoreAction).toBeCalledWith( + "saveSupportingItemsSuppressingStateResetting", + expect.not.arrayContaining([ + expect.objectContaining({ + partType: "EARLY BIRD" + }) + ]), + expect.anything() + ); - expect(arePagePrerequisitesValid).toBe(true); }); - test("should fail arePagePrerequisitesValid with a replace with no glass parts", () => { + + test("if no EARLY BIRD supporting item, then updateSupportingItems should NOT call store action", async () => { //Arrange + store.getters.order.serviceLocation.appointmentType = "Mobile"; + store.getters.lineItems.supportingItems = []; const { wrapper } = setupMocks({}); - store.getters = { - order: { - schedule: { - date: "2020-01-01", - }, - serviceLocation: { - zipCode: "12345", - zipCodeCtu: "value", - appointmentType: "Inshop", - provider: { - providerNumber: "5", - }, - }, - damage: { - isRepair: false, - }, - referralNumber: "1234567", - }, - payment: { - isInsurance: true, - }, - lineItems: { - supportingItems: [], - glassParts: [], - }, - }; + wrapper.vm.dispatchStoreAction = jest.fn(() => { + return { + data: [], + }; + }); + wrapper.vm.mobilePremiumAppointmentFee = 14.99; + wrapper.setData({ + selectedTimeSlot: { + date: "2019-01-01", + startTime: "09:00", + endTime: "10:00", + routeCode: null, + isPremiumAppointment: false + } + }); - let arePagePrerequisitesValid = wrapper.vm.arePagePrerequisitesValid(); + //Act + await wrapper.vm.updateSupportingItems(); + + //Assert + expect(wrapper.vm.dispatchStoreAction).not.toBeCalled(); - expect(arePagePrerequisitesValid).toBe(false); }); - test("should fail arePagePrerequisitesValid without isInsurance", () => { - //Arrange - const { wrapper } = setupMocks({}); - store.getters = { - order: { - schedule: { - date: "2020-01-01", - }, - serviceLocation: { - zipCode: "12345", - zipCodeCtu: "value", - appointmentType: "Inshop", - provider: { - providerNumber: "5", - }, - }, - damage: { - isRepair: true, - }, - referralNumber: "1234567", - }, - payment: { - isInsurance: null, - }, - lineItems: { - supportingItems: [], - glassParts: [], - }, - }; - let arePagePrerequisitesValid = wrapper.vm.arePagePrerequisitesValid(); - - expect(arePagePrerequisitesValid).toBe(false); - }); }); const mockCmsContent = {}; @@ -210,6 +625,7 @@ function setupMocks({ customMountOptions }) { }); mountOptions.global.mocks["$store"] = store; + mountOptions.global.mocks["$router"] = router; mountOptions["attachTo"] = document.body; mountOptions.mixins = [ { @@ -223,6 +639,12 @@ function setupMocks({ customMountOptions }) { ]; const wrapper = shallowMount(schedule, mountOptions); + wrapper.vm.setCmsContent = jest.fn(); + wrapper.vm.$refs.datePicker.initializeComponent = jest.fn(); + wrapper.vm.$refs.locationAlerts.initializeComponent = jest.fn(); + wrapper.vm.$refs.funnelFooter.updateButtonText = jest.fn(); + wrapper.vm.$refs.timeSlotModalQuestion.openModal = jest.fn(); + return { wrapper }; } diff --git a/src/layouts/schedule/schedule.spec.js1 b/src/layouts/schedule/schedule.spec.js1 new file mode 100644 index 000000000..e69de29bb diff --git a/src/layouts/schedule/schedule.vue b/src/layouts/schedule/schedule.vue index 6a42b7a92..00b3e796b 100644 --- a/src/layouts/schedule/schedule.vue +++ b/src/layouts/schedule/schedule.vue @@ -320,6 +320,7 @@ export default { ); return newShopTimeSlots; }, + getAvailableDates, getServiceZipCtuCodeFromStore() { return store.getters.order.serviceLocation.zipCodeCtu; }, @@ -338,12 +339,6 @@ export default { getSupportingItems() { return store.getters.lineItems.supportingItems; }, - isMobilePremiumFeeOnOrderInVuex() { - const supportingItemsFromVuex = store.getters.lineItems.supportingItems; - return !!supportingItemsFromVuex.filter( - (lineItem) => lineItem.partType === PREMIUM_FEE_PART_TYPE - ).length; - }, timeSlotModalClosed() { // Clear the selectedDate if no timeSlot has been selected if (this.selectedTimeSlot.routeCode == null) { From 80e7248bd9424f89567c344faf7f9cb40a22f013 Mon Sep 17 00:00:00 2001 From: Adam Caouette Date: Mon, 14 Aug 2023 11:09:05 -0400 Subject: [PATCH 30/60] CSR-886: unit tests formatting updates --- src/layouts/schedule/schedule.spec.js | 184 ++++++++++++-------------- 1 file changed, 85 insertions(+), 99 deletions(-) diff --git a/src/layouts/schedule/schedule.spec.js b/src/layouts/schedule/schedule.spec.js index 56b2ce13b..b47036c10 100644 --- a/src/layouts/schedule/schedule.spec.js +++ b/src/layouts/schedule/schedule.spec.js @@ -89,7 +89,7 @@ beforeEach(() => { date: "2019-01-01", startTime: "09:00", endTime: "10:00", - routeCode: "000" + routeCode: "000", }, lineItems: { glassParts: [ @@ -135,7 +135,7 @@ describe("schedule.vue...", () => { store.getters.order.serviceLocation.appointmentType = "Mobile"; store.getters.order.serviceLocation.provider = null; - //Act + //Act const arePagePrerequisitesValid = wrapper.vm.arePagePrerequisitesValid(); //Assert @@ -265,45 +265,45 @@ describe("schedule.vue...", () => { expect.objectContaining({ days: expect.any(Array), estimatedServiceMinutesMaximum: expect.any(Number), - estimatedServiceMinutesMinimum: expect.any(Number) + estimatedServiceMinutesMinimum: expect.any(Number), }) ); expect(wrapper.vm.mobilePremiumAppointmentFee).toStrictEqual( expect.objectContaining({ - partNumber: expect.any(String) + partNumber: expect.any(String), }) ); expect(wrapper.vm.updateFooterButtonText).toHaveBeenCalled(); }); - }); describe("computed properties...", () => { - test("timeSlotsForSelectedDate should return timeslots if selected date is available", () => { //Arrange const { wrapper } = setupMocks({}); wrapper.vm.selectableDatesData = { - days: [{ - "date": "2022-11-11", - "timeSlots": [ - { - "id": "1820I-01820-M-I*20425*AM", - "startTime": "08:00", - "endTime": "12:00", - "offerPremium": true - }, - { - "id": "1820I-01820-M-I*20425*PM", - "startTime": "12:00", - "endTime": "17:00", - "offerPremium": false - } - ] - }], + days: [ + { + date: "2022-11-11", + timeSlots: [ + { + id: "1820I-01820-M-I*20425*AM", + startTime: "08:00", + endTime: "12:00", + offerPremium: true, + }, + { + id: "1820I-01820-M-I*20425*PM", + startTime: "12:00", + endTime: "17:00", + offerPremium: false, + }, + ], + }, + ], }; wrapper.setData({ - selectedDate: "2022-11-11" + selectedDate: "2022-11-11", }); //Act @@ -312,46 +312,45 @@ describe("schedule.vue...", () => { //Assert expect(testValue).toStrictEqual( expect.objectContaining({ - "date": "2022-11-11" + date: "2022-11-11", }) ); - }); test("timeSlotsForSelectedDate should be null if no date has been selected", () => { //Arrange const { wrapper } = setupMocks({}); wrapper.vm.selectableDatesData = { - days: [{ - "date": "2022-11-11", - "timeSlots": [ - { - "id": "1820I-01820-M-I*20425*AM", - "startTime": "08:00", - "endTime": "12:00", - "offerPremium": true - }, - { - "id": "1820I-01820-M-I*20425*PM", - "startTime": "12:00", - "endTime": "17:00", - "offerPremium": false - } - ] - }], + days: [ + { + date: "2022-11-11", + timeSlots: [ + { + id: "1820I-01820-M-I*20425*AM", + startTime: "08:00", + endTime: "12:00", + offerPremium: true, + }, + { + id: "1820I-01820-M-I*20425*PM", + startTime: "12:00", + endTime: "17:00", + offerPremium: false, + }, + ], + }, + ], }; wrapper.setData({ - selectedDate: undefined + selectedDate: undefined, }); //Act const testValue = wrapper.vm.timeSlotsForSelectedDate; //Assert - expect(testValue).toBe(null) - + expect(testValue).toBe(null); }); - }); }); @@ -367,10 +366,7 @@ describe("schedule.vue...", () => { const testValue = wrapper.vm.getServiceZipCtuCodeFromStore(); //Assert - expect(testValue).toStrictEqual( - "01234" - ); - + expect(testValue).toStrictEqual("01234"); }); test("openInshopTimeSlotsModal should trigger openModal method", () => { @@ -385,7 +381,6 @@ describe("schedule.vue...", () => { //Assert expect(wrapper.vm.$refs.timeSlotModalQuestion.openModal).toBeCalled(); - }); test("getSelectedRouteCode should return schedule routeCode", () => { @@ -400,14 +395,9 @@ describe("schedule.vue...", () => { const testValue = wrapper.vm.getSelectedRouteCode(); //Assert - expect(testValue).toStrictEqual( - "000" - ); - + expect(testValue).toStrictEqual("000"); }); - - test("timeSlotModalClosed should null any selected date when there's no route code", () => { //Arrange const { wrapper } = setupMocks({}); @@ -415,15 +405,15 @@ describe("schedule.vue...", () => { days: [], }; wrapper.setData({ - selectedDate: "1980-05-05" + selectedDate: "1980-05-05", }); wrapper.setData({ selectedTimeSlot: { date: "2019-01-01", startTime: "09:00", endTime: "10:00", - routeCode: null - } + routeCode: null, + }, }); //Act @@ -431,10 +421,8 @@ describe("schedule.vue...", () => { //Assert expect(wrapper.vm.selectedDate).toBe(null); - }); - test("getDisplayTextForMilitaryTime should return the correctly formatted string", () => { //Arrange const { wrapper } = setupMocks({}); @@ -455,7 +443,6 @@ describe("schedule.vue...", () => { expect(testOutput2).toBe("3:30 PM"); expect(testOutput3).toBe("3 PM"); expect(testOutput4).toBe("3:30 PM"); - }); test("getDisplayTextForMilitaryTime should return the correctly formatted string", () => { @@ -471,11 +458,11 @@ describe("schedule.vue...", () => { wrapper.vm.backButtonAction(); //Assert - expect(wrapper.vm.$router.navigateWithoutSaving).toBeCalledWith("CLICKED_BACK", "testRoute"); - + expect(wrapper.vm.$router.navigateWithoutSaving).toBeCalledWith( + "CLICKED_BACK", + "testRoute" + ); }); - - }); test("forwardButtonAction should call route method navigateWithoutSaving", async () => { @@ -497,18 +484,19 @@ describe("schedule.vue...", () => { expect(wrapper.vm.$router.navigateWithSaving).toHaveBeenCalled(); }); - test("for mobile appts, updateSupportingItems should call store action to save supporting items", async () => { //Arrange store.getters.order.serviceLocation.appointmentType = "Mobile"; - store.getters.lineItems.supportingItems = [{ - "partNumber": "EARLY BIRD", - "description": null, - "partType": "EARLY BIRD", - "laborAmount": 0, - "sellingPrice": 0, - "kitPrice": 0 - }]; + store.getters.lineItems.supportingItems = [ + { + partNumber: "EARLY BIRD", + description: null, + partType: "EARLY BIRD", + laborAmount: 0, + sellingPrice: 0, + kitPrice: 0, + }, + ]; const { wrapper } = setupMocks({}); wrapper.vm.dispatchStoreAction = jest.fn(() => { return { @@ -522,8 +510,8 @@ describe("schedule.vue...", () => { startTime: "09:00", endTime: "10:00", routeCode: null, - isPremiumAppointment: true - } + isPremiumAppointment: true, + }, }); //Act @@ -534,25 +522,26 @@ describe("schedule.vue...", () => { "saveSupportingItemsSuppressingStateResetting", expect.arrayContaining([ expect.objectContaining({ - partType: "EARLY BIRD" - }) + partType: "EARLY BIRD", + }), ]), expect.anything() ); - }); test("for Inshop appts, updateSupportingItems should call store action to save supporting items WITHOUT the EARLY BIRD supporting item", async () => { //Arrange store.getters.order.serviceLocation.appointmentType = "Inshop"; - store.getters.lineItems.supportingItems = [{ - "partNumber": "EARLY BIRD", - "description": null, - "partType": "EARLY BIRD", - "laborAmount": 0, - "sellingPrice": 0, - "kitPrice": 0 - }]; + store.getters.lineItems.supportingItems = [ + { + partNumber: "EARLY BIRD", + description: null, + partType: "EARLY BIRD", + laborAmount: 0, + sellingPrice: 0, + kitPrice: 0, + }, + ]; const { wrapper } = setupMocks({}); wrapper.vm.dispatchStoreAction = jest.fn(() => { return { @@ -566,8 +555,8 @@ describe("schedule.vue...", () => { startTime: "09:00", endTime: "10:00", routeCode: null, - isPremiumAppointment: true - } + isPremiumAppointment: true, + }, }); //Act @@ -578,12 +567,11 @@ describe("schedule.vue...", () => { "saveSupportingItemsSuppressingStateResetting", expect.not.arrayContaining([ expect.objectContaining({ - partType: "EARLY BIRD" - }) + partType: "EARLY BIRD", + }), ]), expect.anything() ); - }); test("if no EARLY BIRD supporting item, then updateSupportingItems should NOT call store action", async () => { @@ -603,8 +591,8 @@ describe("schedule.vue...", () => { startTime: "09:00", endTime: "10:00", routeCode: null, - isPremiumAppointment: false - } + isPremiumAppointment: false, + }, }); //Act @@ -612,9 +600,7 @@ describe("schedule.vue...", () => { //Assert expect(wrapper.vm.dispatchStoreAction).not.toBeCalled(); - }); - }); const mockCmsContent = {}; From 82a73565bd6d7e68c661cedf4c6e6a63fb4b4416 Mon Sep 17 00:00:00 2001 From: Scott Kiener Date: Tue, 15 Aug 2023 09:04:32 -0400 Subject: [PATCH 31/60] CSR-1582 | isInsurance is nullable & navigation changes Allow saveSession to send a null value for isInsurance Allow service packages to be auto selected based on if isInsurance is null Add in service location and schedule pages to navigation logic --- .../heritage-integration/navigation-helper.js | 13 ++++++++-- .../service-package-question.vue | 26 +------------------ src/store/index.js | 2 +- 3 files changed, 13 insertions(+), 28 deletions(-) diff --git a/src/helpers/heritage-integration/navigation-helper.js b/src/helpers/heritage-integration/navigation-helper.js index 913fbcb1b..db7881527 100644 --- a/src/helpers/heritage-integration/navigation-helper.js +++ b/src/helpers/heritage-integration/navigation-helper.js @@ -31,7 +31,8 @@ export async function getPageToRouteExistingOrderTo(toRoute = {}, existingHerita // Return that page, so that it can navigate like normal. if ( toRoute.query[queryStrings.FMG_PAGE] !== undefined && - toRoute.query[queryStrings.FMG_PAGE] !== fmgPageValues.QUOTE && + toRoute.query[queryStrings.FMG_PAGE] !== fmgPageValues.SERVICE_LOCATION && + toRoute.query[queryStrings.FMG_PAGE] !== fmgPageValues.SCHEDULE && !isVinRelatedPage(toRoute) ) { return overrideYmmsDirectionIfNeeded(toRoute); @@ -115,6 +116,8 @@ async function getLatestPageForRedirection() { fmgPageValues.CAPABILITY_QUESTIONS ); const quoteComponent = await getLazyLoadedComponent(fmgPageValues.QUOTE); + const serviceLocationComponent = await getLazyLoadedComponent(fmgPageValues.SERVICE_LOCATION); + const scheduleComponent = await getLazyLoadedComponent(fmgPageValues.SCHEDULE); const skipVin = await skipVinLookup(); @@ -129,7 +132,13 @@ async function getLatestPageForRedirection() { } else if (!estimateComponent.methods.arePagePrerequisitesValid()) { return fmgPageValues.VEHICLE_DAMAGE; } else { - if (quoteComponent.methods.arePagePrerequisitesValid()) { + if (scheduleComponent.methods.arePagePrerequisitesValid()) { + return fmgPageValues.SCHEDULE; + } else if (serviceLocationComponent.methods.arePagePrerequisitesValid()) { + // This should be reversed 45+ days after the 8.24 release (Sunday October 8th, 2023) + //return fmgPageValues.SERVICE_LOCATION; + return fmgPageValues.QUOTE; + } else if (quoteComponent.methods.arePagePrerequisitesValid()) { return fmgPageValues.QUOTE; } else if (capabilityQuestionsComponent.methods.arePagePrerequisitesValid()) { return fmgPageValues.CAPABILITY_QUESTIONS; diff --git a/src/layouts/quote/service-package-question/service-package-question.vue b/src/layouts/quote/service-package-question/service-package-question.vue index 29e6a9a9e..50cbfa128 100644 --- a/src/layouts/quote/service-package-question/service-package-question.vue +++ b/src/layouts/quote/service-package-question/service-package-question.vue @@ -44,7 +44,7 @@ export default { }, watch: { availableLineItems() { - if (this.allGlassPartsAndSupportingItemsHavePrices(this.$store.getters.lineItems)) { + if (this.$store.getters.payment.isInsurance != null) { this.selectDefaultPackage(); } }, @@ -230,30 +230,6 @@ export default { } this.selectedPackageName = lowestTierForPackage; }, - allGlassPartsAndSupportingItemsHavePrices(lineItems) { - if (lineItems?.glassParts) { - for (let i = 0; i < lineItems.glassParts.length; i++) { - if (this.priceIsNullOrZero(lineItems.glassParts[i])) { - return false; - } - } - } - if (lineItems?.supportingItems) { - for (let i = 0; i < lineItems.supportingItems.length; i++) { - if (this.priceIsNullOrZero(lineItems.supportingItems[i])) { - return false; - } - } - } - return true; - }, - priceIsNullOrZero(lineItem) { - return ( - (lineItem.kitPrice == null || lineItem.kitPrice == 0) && - (lineItem.laborAmount == null || lineItem.laborAmount == 0) && - (lineItem.sellingPrice == null || lineItem.sellingPrice == 0) - ); - }, getLowestTierForThisItem(vapsItem) { let lowestTierForThisItem = null; switch (vapsItem.partType) { diff --git a/src/store/index.js b/src/store/index.js index e91962a11..9b52e08a4 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -1429,7 +1429,7 @@ export const actions = { InsuranceCoverage: { isVerified: order.payment.insuranceCoverage.isVerified ?? false, }, - isInsurance: order.payment.isInsurance ?? false, + isInsurance: order.payment.isInsurance, parentAccountNumber: order.payment.parentAccountNumber, }, serviceLocation: { From b54fafb929e40bb8090540d9b2807ed45b83795b Mon Sep 17 00:00:00 2001 From: Scott Kiener Date: Tue, 15 Aug 2023 09:18:40 -0400 Subject: [PATCH 32/60] CSR-1582 | Unit tests and formatting --- .../service-package-question.spec.js | 116 +++--------------- 1 file changed, 16 insertions(+), 100 deletions(-) diff --git a/src/layouts/quote/service-package-question/service-package-question.spec.js b/src/layouts/quote/service-package-question/service-package-question.spec.js index af04ff36a..dc0d2005c 100644 --- a/src/layouts/quote/service-package-question/service-package-question.spec.js +++ b/src/layouts/quote/service-package-question/service-package-question.spec.js @@ -135,64 +135,9 @@ describe("service-package-question.vue", () => { expectedModifiedAnswers[packageNameKey].tierThree ); }); - it("should not select a default package if ANY glass part or supporting item has no prices", async () => { + it("should not select a default package if isInsurance is null", async () => { // Note, only the first WSREPAIR item has a 0 for laborAmount, this is enough to not try and select a default package - const wrapper = setupMocks({ - mountOptionsMockData: { - store: { - getters: { - lineItems: { - glassParts: [ - { - partNumber: "FW02627GBYNOEE", - description: "solar, 3rd visor band", - color: "Green Tint, Blue Shade", - partType: "WINDSHIELD", - canSafeliteRecalibrate: false, - requiresRecalibration: false, - requiresCapabilityQuestions: false, - recalibrationType: null, - childParts: null, - laborAmount: 5.0, - }, - ], - supportingItems: [ - { - partNumber: "SUPPLIES-REPAIR", - description: null, - partType: "REPAIR FEE", - laborAmount: 5.0, - }, - { - partNumber: "WSREPAIR", - description: null, - partType: "REPAIR FEE", - laborAmount: 0, - }, - { - partNumber: "WSREPAIR", - description: null, - partType: "REPAIR FEE", - laborAmount: 5.0, - }, - { - partNumber: "WSREPAIR", - description: null, - partType: "REPAIR FEE", - laborAmount: 5.0, - }, - ], - }, - order: { - damage: { - isRepair: false, - glassToReplace: [{ glassLocation: "Windshield" }], - }, - }, - }, - }, - }, - }); + const wrapper = setupMocks({}); // Act wrapper.setProps({ availableLineItems: null }); @@ -202,59 +147,24 @@ describe("service-package-question.vue", () => { // Assert expect(wrapper.vm.selectedPackageName).toBe(null); }); - it("should select a default package if ALL glass parts and supporting items have prices", async () => { + it("should select a default package if isInsurance is NOT null", async () => { const wrapper = setupMocks({ mountOptionsMockData: { store: { getters: { - lineItems: { - glassParts: [ - { - partNumber: "FW02627GBYNOEE", - description: "solar, 3rd visor band", - color: "Green Tint, Blue Shade", - partType: "WINDSHIELD", - canSafeliteRecalibrate: false, - requiresRecalibration: false, - requiresCapabilityQuestions: false, - recalibrationType: null, - childParts: null, - laborAmount: 5.0, - }, - ], - supportingItems: [ - { - partNumber: "SUPPLIES-REPAIR", - description: null, - partType: "REPAIR FEE", - laborAmount: 5.0, - }, - { - partNumber: "WSREPAIR", - description: null, - partType: "REPAIR FEE", - laborAmount: 5.0, - }, - { - partNumber: "WSREPAIR", - description: null, - partType: "REPAIR FEE", - laborAmount: 5.0, - }, - { - partNumber: "WSREPAIR", - description: null, - partType: "REPAIR FEE", - laborAmount: 5.0, - }, - ], - }, order: { damage: { isRepair: false, glassToReplace: [{ glassLocation: "Windshield" }], }, }, + lineItems: { + vaps: [], + }, + hasAnyNonWindshieldGlassParts: false, + payment: { + isInsurance: false, + }, }, }, }, @@ -329,6 +239,9 @@ describe("service-package-question.vue", () => { glassToReplace: [{ glassLocation: "Windshield" }], }, }, + payment: { + isInsurance: false, + }, }, }, }, @@ -758,6 +671,9 @@ function setupMocks({ mountOptionsMockData, props = mockProps }) { }, }, hasAnyNonWindshieldGlassParts: false, + payment: { + isInsurance: null, + }, }, }, }; From dc43455d92d206da25208d7b6514696ecdfd006b Mon Sep 17 00:00:00 2001 From: CarlNation Date: Tue, 15 Aug 2023 09:39:15 -0400 Subject: [PATCH 33/60] CSR-1564 CSR-1559 registration defaults CSR-1564 CSR-1559 registration defaults --- src/constants/store-mutations.js | 7 --- src/layouts/address-lookup/address-lookup.vue | 4 -- .../license-plate-lookup.vue | 2 - src/store/index.js | 43 ++----------------- src/store/store.spec.js | 2 +- 5 files changed, 5 insertions(+), 53 deletions(-) diff --git a/src/constants/store-mutations.js b/src/constants/store-mutations.js index 795eb62c9..fd568ead7 100644 --- a/src/constants/store-mutations.js +++ b/src/constants/store-mutations.js @@ -23,13 +23,6 @@ const storeMutations = { UPDATE_SUPPORTING_ITEMS: "updateSupportingItems", UPDATE_LINE_ITEMS_SERVER_DATA: "updateLineItemsServerData", - UPDATE_REGISTRATION_LICENSE_PLATE: "updateRegistrationLicensePlate", - UPDATE_REGISTRATION_ADDRESS: "updateRegistrationAddress", - UPDATE_REGISTRATION_CITY: "updateRegistrationCity", - UPDATE_REGISTRATION_STATE: "updateRegistrationState", - UPDATE_REGISTRATION_ZIP_CODE: "updateRegistrationZipCode", - UPDATE_REGISTRATION_FIRST_NAME: "updateRegistrationFirstName", - UPDATE_REGISTRATION_LAST_NAME: "updateRegistrationLastName", UPDATE_REGISTRATION: "updateRegistration", UPDATE_SERVICE_ZIP: "updateServiceZip", diff --git a/src/layouts/address-lookup/address-lookup.vue b/src/layouts/address-lookup/address-lookup.vue index fe3b00320..48ab0dd08 100644 --- a/src/layouts/address-lookup/address-lookup.vue +++ b/src/layouts/address-lookup/address-lookup.vue @@ -323,10 +323,6 @@ export default { registrationInfo: { firstName: this.customerQuestions.firstName, lastName: this.customerQuestions.lastName, - address: this.customerQuestions.addressQuestions.streetAddress, - city: this.customerQuestions.addressQuestions.city, - state: resultMap.serviceZipValidationResponse.state, - zipCode: this.customerQuestions.addressQuestions.zipCode, }, }, false diff --git a/src/layouts/license-plate-lookup/license-plate-lookup.vue b/src/layouts/license-plate-lookup/license-plate-lookup.vue index 49ff8ff26..326215243 100644 --- a/src/layouts/license-plate-lookup/license-plate-lookup.vue +++ b/src/layouts/license-plate-lookup/license-plate-lookup.vue @@ -292,8 +292,6 @@ export default { vehicleInfo: Object.assign(vinLookup.data.vehicle, { vin: vinLookup.data.vin }), registrationInfo: { licensePlate: this.licensePlate, - state: resultMap.registrationZipValidationResponse.state, - zipCode: this.registrationZipCode, }, }, false diff --git a/src/store/index.js b/src/store/index.js index b64a09aa7..c3b599138 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -39,12 +39,6 @@ const getDefaultState = () => { imageColor: null, registration: { licensePlate: null, - address: null, - city: null, - state: null, - zipCode: null, - firstName: null, - lastName: null, }, }, serviceLocation: { @@ -217,27 +211,6 @@ export const mutations = { updateInsuranceVerifiedStatus(state, isVerified) { state.order.payment.insuranceCoverage.isVerified = isVerified; }, - updateRegistrationLicensePlate(state, licensePlate) { - state.order.vehicle.registration.licensePlate = licensePlate; - }, - updateRegistrationAddress(state, registrationAddress) { - state.order.vehicle.registration.address = registrationAddress; - }, - updateRegistrationCity(state, registrationCity) { - state.order.vehicle.registration.city = registrationCity; - }, - updateRegistrationState(state, registrationState) { - state.order.vehicle.registration.state = registrationState; - }, - updateRegistrationZipCode(state, registrationZipCode) { - state.order.vehicle.registration.zipCode = registrationZipCode; - }, - updateRegistrationFirstName(state, firstName) { - state.order.vehicle.registration.firstName = firstName; - }, - updateRegistrationLastName(state, lastName) { - state.order.vehicle.registration.lastName = lastName; - }, updateCustomerEmailAddress(state, customerEmailAddress) { state.order.customer.emailAddress = customerEmailAddress; }, @@ -358,12 +331,8 @@ export const mutations = { }, resetRegistrationState(state) { state.order.vehicle.registration.licensePlate = null; - state.order.vehicle.registration.address = null; - state.order.vehicle.registration.city = null; - state.order.vehicle.registration.state = null; - state.order.vehicle.registration.zipCode = null; - state.order.vehicle.registration.firstName = null; - state.order.vehicle.registration.lastName = null; + state.order.customer.firstName = null; + state.order.customer.lastName = null; }, resetGlassPartsState(state) { state.order.lineItems.glassParts = null; @@ -1775,12 +1744,8 @@ export const actions = { ) { //Reset dependent state when changing if ( - registrationInfo?.address !== context.state.order.vehicle.registration?.address || - registrationInfo?.city !== context.state.order.vehicle.registration?.city || - registrationInfo?.state !== context.state.order.vehicle.registration?.state || - registrationInfo?.zipCode !== context.state.order.vehicle.registration?.zipCode || - registrationInfo?.firstName !== context.state.order.vehicle.registration?.firstName || - registrationInfo?.lastName !== context.state.order.vehicle.registration?.lastName + registrationInfo?.firstName !== context.state.order.customer?.firstName || + registrationInfo?.lastName !== context.state.order.customer?.lastName ) { context.dispatch(storeActions.RESET_REGISTRATION_STATE_AND_DEPENDENCIES); diff --git a/src/store/store.spec.js b/src/store/store.spec.js index e813cb21e..f70bbd3d1 100644 --- a/src/store/store.spec.js +++ b/src/store/store.spec.js @@ -1552,7 +1552,7 @@ describe("Actions", () => { isCarIdDifferent: true, isSelectedGlassAvailableForVehicle: false, vehicleInfo: { carId: "C010101", vin: "XXXXX" }, - registrationInfo: { zipCode: "80020", address: "123 Marys Ave" }, + registrationInfo: { firstName: "abc", lastName: "123" }, serviceLocationInfo: { state: "CO" }, customerEmail: "test@safelite.com", }; From ce6b6b16af006c371900b79514a545d6b3eb6871 Mon Sep 17 00:00:00 2001 From: Scott Kiener Date: Tue, 15 Aug 2023 09:51:38 -0400 Subject: [PATCH 34/60] CSR-1582 | Remove backwards compatibility code This won't be released until after Oct 8th --- src/helpers/heritage-integration/navigation-helper.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/helpers/heritage-integration/navigation-helper.js b/src/helpers/heritage-integration/navigation-helper.js index db7881527..61dd13688 100644 --- a/src/helpers/heritage-integration/navigation-helper.js +++ b/src/helpers/heritage-integration/navigation-helper.js @@ -135,9 +135,7 @@ async function getLatestPageForRedirection() { if (scheduleComponent.methods.arePagePrerequisitesValid()) { return fmgPageValues.SCHEDULE; } else if (serviceLocationComponent.methods.arePagePrerequisitesValid()) { - // This should be reversed 45+ days after the 8.24 release (Sunday October 8th, 2023) - //return fmgPageValues.SERVICE_LOCATION; - return fmgPageValues.QUOTE; + return fmgPageValues.SERVICE_LOCATION; } else if (quoteComponent.methods.arePagePrerequisitesValid()) { return fmgPageValues.QUOTE; } else if (capabilityQuestionsComponent.methods.arePagePrerequisitesValid()) { From 54d155be4d5865950d19c6be846b44fd70119cbf Mon Sep 17 00:00:00 2001 From: Chloe Herd Date: Tue, 15 Aug 2023 10:15:20 -0400 Subject: [PATCH 35/60] Populate fields and detect changes on submit. --- .../customer-details-modal-question.vue | 29 +++++++++++++++++-- src/layouts/review/review.vue | 4 ++- 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/src/layouts/review/review-sections/customer-review/customer-details-modal-question/customer-details-modal-question.vue b/src/layouts/review/review-sections/customer-review/customer-details-modal-question/customer-details-modal-question.vue index f02ecd3b4..5e8feef9a 100644 --- a/src/layouts/review/review-sections/customer-review/customer-details-modal-question/customer-details-modal-question.vue +++ b/src/layouts/review/review-sections/customer-review/customer-details-modal-question/customer-details-modal-question.vue @@ -68,11 +68,22 @@ export default { isSmsOptIn: false, }; }, - props: {}, + props: { + previousCustomerValues: Object, + }, computed: { modal() { return this.$refs.CustomerDetailsModal; }, + haveCustomerDetailsChanged() { + return ( + this.firstName !== this.previousCustomerValues?.firstName || + this.lastName !== this.previousCustomerValues?.lastName || + this.emailAddress !== this.previousCustomerValues?.emailAddress || + this.phoneNumber !== this.previousCustomerValues?.phoneNumber || + this.isSmsOptIn !== this.previousCustomerValues?.isSmsOptIn + ); + }, }, methods: { openModal() { @@ -81,12 +92,24 @@ export default { closeModal() { this.modal.closeModal(); }, - onModalOpened() {}, + onModalOpened() { + this.firstName = this.previousCustomerValues?.firstName ?? ""; + this.lastName = this.previousCustomerValues?.lastName ?? ""; + this.emailAddress = this.previousCustomerValues?.emailAddress ?? ""; + this.phoneNumber = this.previousCustomerValues?.phoneNumber ?? ""; + this.isSmsOptIn = this.previousCustomerValues?.isSmsOptIn ?? false; + }, onModalClosed() {}, setModalStatus(isOpened) { this.isModalOpened = isOpened; }, - setContactDetails() {}, + async setContactDetails() { + if (this.haveCustomerDetailsChanged) { + console.log("change detected"); + } + + this.closeModal(); + }, }, components: { modal, diff --git a/src/layouts/review/review.vue b/src/layouts/review/review.vue index d99ba1cda..fe14e8f7e 100644 --- a/src/layouts/review/review.vue +++ b/src/layouts/review/review.vue @@ -89,7 +89,9 @@
- + Date: Tue, 15 Aug 2023 13:22:15 -0400 Subject: [PATCH 36/60] Commit changed values to store on submit. --- .../customer-details-modal-question.vue | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/layouts/review/review-sections/customer-review/customer-details-modal-question/customer-details-modal-question.vue b/src/layouts/review/review-sections/customer-review/customer-details-modal-question/customer-details-modal-question.vue index 5e8feef9a..3ce86e39b 100644 --- a/src/layouts/review/review-sections/customer-review/customer-details-modal-question/customer-details-modal-question.vue +++ b/src/layouts/review/review-sections/customer-review/customer-details-modal-question/customer-details-modal-question.vue @@ -105,7 +105,17 @@ export default { }, async setContactDetails() { if (this.haveCustomerDetailsChanged) { - console.log("change detected"); + await this.dispatchStoreAction( + this.storeActions.SAVE_CUSTOMER_DETAILS, + { + firstName: this.firstName, + lastName: this.lastName, + emailAddress: this.emailAddress, + phoneNumber: this.phoneNumber, + isSmsOptIn: this.isSmsOptIn, + }, + false + ); } this.closeModal(); From 4f53a1fa45f76aab0a3d700198d2800967b73dec Mon Sep 17 00:00:00 2001 From: Chloe Herd Date: Tue, 15 Aug 2023 13:22:48 -0400 Subject: [PATCH 37/60] Compute cms without reloading page. --- .../review-sections/customer-review/customer-review.vue | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/layouts/review/review-sections/customer-review/customer-review.vue b/src/layouts/review/review-sections/customer-review/customer-review.vue index 678dcf0b6..d8777d9e4 100644 --- a/src/layouts/review/review-sections/customer-review/customer-review.vue +++ b/src/layouts/review/review-sections/customer-review/customer-review.vue @@ -36,7 +36,10 @@ export default { return this.customer?.phoneNumber; }, smsOptIn() { - return this.getCmsContent(this.cmsWidgetName, "SubheaderText"); + const rawCmsText = this.getCmsContent(this.cmsWidgetName, "SubheaderText"); + const joinerText = this.customer?.isSmsOptIn ? "in to" : "out of"; + + return rawCmsText.replace("{custom:smsOptInJoiner}", joinerText); }, }, components: { From 24042ba11125e5052abfbb653f527c56c07f2a3b Mon Sep 17 00:00:00 2001 From: Chloe Herd Date: Tue, 15 Aug 2023 14:10:02 -0400 Subject: [PATCH 38/60] Add tests for customer-review --- .../customer-review/customer-review.spec.js | 160 +++++++++++++++++- 1 file changed, 158 insertions(+), 2 deletions(-) diff --git a/src/layouts/review/review-sections/customer-review/customer-review.spec.js b/src/layouts/review/review-sections/customer-review/customer-review.spec.js index ea5ec2f2e..1bcbbe83b 100644 --- a/src/layouts/review/review-sections/customer-review/customer-review.spec.js +++ b/src/layouts/review/review-sections/customer-review/customer-review.spec.js @@ -1,3 +1,159 @@ -describe("Customer review Block", () => { - test.todo("Add more tests as specific functionality is added."); +import { shallowMount } from "@vue/test-utils"; +import { getMountOptions } from "@/helpers/unit-test-helper.js"; + +import customerReview from "@/layouts/review/review-sections/customer-review/customer-review"; + +const testConstants = { + cms: { + header: { + text: "Header", + }, + sms: { + template: "Test {custom:smsOptInJoiner}", + expected: { + ifTrue: "Test in to", + ifFalse: "Test out of", + }, + }, + }, + customer: { + firstName: "First", + lastName: "Last", + phoneNumber: "111-111-1111", + emailAddress: "builddigitaltest@safelite.com", + isSmsOptIn: false, + }, + displayContent: { + fullName: "First Last", + phoneNumber: "111-111-1111", + emailAddress: "builddigitaltest@safelite.com", + smsOptIn: "Test out of", + }, +}; + +let cmsContent; + +describe("Customer Review Block", () => { + beforeEach(() => { + cmsContent = { + CustomerWidget: { + HeaderText: testConstants.cms.header.text, + SubheaderText: testConstants.cms.sms.template, + }, + }; + }); + + test("Should display header text from cms", async () => { + // Arrange + let props = generateDefaultProps(); + + const { wrapper } = setupMocks({ + propsData: props, + }); + + // Act + await wrapper.vm.$nextTick(); + + // Assert + expect(wrapper.vm.header).toEqual(testConstants.cms.header.text); + }); + + describe("SMS Opt In Text", () => { + test("Should render correctly when opt in is true:", async () => { + // Arrange + let props = generateDefaultProps(); + props.customer.isSmsOptIn = true; + + const { wrapper } = setupMocks({ + propsData: props, + }); + + // Act + await wrapper.vm.$nextTick(); + + // Assert + expect(wrapper.vm.smsOptIn).toEqual(testConstants.cms.sms.expected.ifTrue); + }); + test("Should render correctly when opt in is false:", async () => { + // Arrange + let props = generateDefaultProps(); + props.customer.isSmsOptIn = false; + + const { wrapper } = setupMocks({ + propsData: props, + }); + + // Act + await wrapper.vm.$nextTick(); + + // Assert + expect(wrapper.vm.smsOptIn).toEqual(testConstants.cms.sms.expected.ifFalse); + }); + test("Should render correctly when opt in is null:", async () => { + // Arrange + let props = generateDefaultProps(); + props.customer.isSmsOptIn = null; + + const { wrapper } = setupMocks({ + propsData: props, + }); + + // Act + await wrapper.vm.$nextTick(); + + // Assert + expect(wrapper.vm.smsOptIn).toEqual(testConstants.cms.sms.expected.ifFalse); + }); + }); + + test("Should render correct display content", async () => { + // Arrange + let props = generateDefaultProps(); + + const { wrapper } = setupMocks({ + propsData: props, + }); + + // Act + await wrapper.vm.$nextTick(); + + // Assert + expect(wrapper.vm.displayContent).toEqual([ + testConstants.displayContent.fullName, + testConstants.displayContent.emailAddress, + testConstants.displayContent.phoneNumber, + testConstants.displayContent.smsOptIn, + ]); + }); }); + +function generateDefaultProps() { + return { + cmsWidgetName: "CustomerWidget", + customer: { + firstName: testConstants.customer.firstName, + lastName: testConstants.customer.lastName, + phoneNumber: testConstants.customer.phoneNumber, + emailAddress: testConstants.customer.emailAddress, + isSmsOptIn: testConstants.customer.isSmsOptIn, + }, + }; +} + +function setupMocks(customMountOptions) { + const mountOptions = getMountOptions(customMountOptions); + + const mockMixin = { + methods: { + getCmsContent: jest.fn((widgetName, cmsFieldName) => { + return cmsContent?.[widgetName]?.[cmsFieldName] ?? ""; + }), + }, + }; + + mountOptions.global.mixins = [mockMixin]; + + const wrapper = shallowMount(customerReview, mountOptions); + wrapper.vm.setCmsContent = jest.fn(); + return { wrapper }; +} From cba95f7e60181aae7e1f9784665b1ade4a00a5bb Mon Sep 17 00:00:00 2001 From: Chloe Herd Date: Tue, 15 Aug 2023 15:57:41 -0400 Subject: [PATCH 39/60] Add tests for modal --- .../customer-details-modal-question.spec.js | 148 ++++++++++++++++++ 1 file changed, 148 insertions(+) create mode 100644 src/layouts/review/review-sections/customer-review/customer-details-modal-question/customer-details-modal-question.spec.js diff --git a/src/layouts/review/review-sections/customer-review/customer-details-modal-question/customer-details-modal-question.spec.js b/src/layouts/review/review-sections/customer-review/customer-details-modal-question/customer-details-modal-question.spec.js new file mode 100644 index 000000000..b87653c73 --- /dev/null +++ b/src/layouts/review/review-sections/customer-review/customer-details-modal-question/customer-details-modal-question.spec.js @@ -0,0 +1,148 @@ +import { shallowMount } from "@vue/test-utils"; +import { getMountOptions } from "@/helpers/unit-test-helper.js"; + +import customerDetailsModalQuestion from "@/layouts/review/review-sections/customer-review/customer-details-modal-question/customer-details-modal-question"; + +const testConstants = { + previousCustomerValues: { + firstName: "First", + lastName: "Last", + emailAddress: "builddigitaltest@safelite.com", + phoneNumber: "111-111-1111", + isSmsOptIn: false, + }, + newValues: { + firstName: "New First", + lastName: "New Last", + emailAddress: "builddigitaltest@safelite.com - new", + phoneNumber: "222-222-2222", + isSmsOptIn: true, + }, +}; + +let cmsContent; + +describe("Customer Details Modal", () => { + beforeEach(() => { + cmsContent = {}; + }); + + describe("Submit", () => { + test("Should push to store if a field has changed", async () => { + // Arrange + let props = generateDefaultProps(); + + const { wrapper } = setupMocks({ + propsData: props, + }); + + // Act + wrapper.vm.onModalOpened(); + + wrapper.vm.firstName = testConstants.newValues.firstName; + + await wrapper.vm.setContactDetails(); + await wrapper.vm.$nextTick(); + + // Assert + expect(wrapper.vm.dispatchStoreAction).toHaveBeenCalled(); + }); + + test("Should not push to store if no fields have changed", async () => { + // Arrange + let props = generateDefaultProps(); + + const { wrapper } = setupMocks({ + propsData: props, + }); + + // Act + wrapper.vm.onModalOpened(); + + await wrapper.vm.setContactDetails(); + await wrapper.vm.$nextTick(); + + // Assert + expect(wrapper.vm.dispatchStoreAction).not.toHaveBeenCalled(); + }); + }); + + describe("Default values", () => { + test("Should populate on open", () => { + // Arrange + let props = generateDefaultProps(); + + const { wrapper } = setupMocks({ + propsData: props, + }); + + // Act + wrapper.vm.onModalOpened(); + + // Assert + expect(wrapper.vm.firstName).toBe(testConstants.previousCustomerValues.firstName); + expect(wrapper.vm.lastName).toBe(testConstants.previousCustomerValues.lastName); + expect(wrapper.vm.emailAddress).toBe(testConstants.previousCustomerValues.emailAddress); + expect(wrapper.vm.phoneNumber).toBe(testConstants.previousCustomerValues.phoneNumber); + expect(wrapper.vm.isSmsOptIn).toBe(testConstants.previousCustomerValues.isSmsOptIn); + }); + + test("Should replace old values on open", async () => { + // Arrange + let props = generateDefaultProps(); + + const { wrapper } = setupMocks({ + propsData: props, + }); + + // Act + wrapper.vm.firstName = testConstants.newValues.firstName; + wrapper.vm.lastName = testConstants.newValues.lastName; + wrapper.vm.emailAddress = testConstants.newValues.emailAddress; + wrapper.vm.phoneNumber = testConstants.newValues.phoneNumber; + wrapper.vm.isSmsOptIn = testConstants.newValues.isSmsOptIn; + + wrapper.vm.onModalOpened(); + + // Assert + expect(wrapper.vm.firstName).toBe(testConstants.previousCustomerValues.firstName); + expect(wrapper.vm.lastName).toBe(testConstants.previousCustomerValues.lastName); + expect(wrapper.vm.emailAddress).toBe(testConstants.previousCustomerValues.emailAddress); + expect(wrapper.vm.phoneNumber).toBe(testConstants.previousCustomerValues.phoneNumber); + expect(wrapper.vm.isSmsOptIn).toBe(testConstants.previousCustomerValues.isSmsOptIn); + }); + }); +}); + +function generateDefaultProps() { + return { + previousCustomerValues: { + firstName: testConstants.previousCustomerValues.firstName, + lastName: testConstants.previousCustomerValues.lastName, + emailAddress: testConstants.previousCustomerValues.emailAddress, + phoneNumber: testConstants.previousCustomerValues.phoneNumber, + isSmsOptIn: testConstants.previousCustomerValues.isSmsOptIn, + }, + }; +} + +function setupMocks(customMountOptions) { + const mountOptions = getMountOptions(customMountOptions); + + const mockMixin = { + methods: { + getCmsContent: jest.fn((widgetName, cmsFieldName) => { + return cmsContent?.[widgetName]?.[cmsFieldName] ?? ""; + }), + }, + }; + + mountOptions.global.mixins = [mockMixin]; + + const wrapper = shallowMount(customerDetailsModalQuestion, mountOptions); + wrapper.vm.setCmsContent = jest.fn(); + wrapper.vm.openModal = jest.fn(); + wrapper.vm.closeModal = jest.fn(); + wrapper.vm.dispatchStoreAction = jest.fn(); + return { wrapper }; +} From 985577202aa90c324032c2912ece343c411a61d1 Mon Sep 17 00:00:00 2001 From: Chloe Herd Date: Tue, 15 Aug 2023 15:59:22 -0400 Subject: [PATCH 40/60] Check for closing modal as well. --- .../customer-details-modal-question.spec.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/layouts/review/review-sections/customer-review/customer-details-modal-question/customer-details-modal-question.spec.js b/src/layouts/review/review-sections/customer-review/customer-details-modal-question/customer-details-modal-question.spec.js index b87653c73..0368effff 100644 --- a/src/layouts/review/review-sections/customer-review/customer-details-modal-question/customer-details-modal-question.spec.js +++ b/src/layouts/review/review-sections/customer-review/customer-details-modal-question/customer-details-modal-question.spec.js @@ -46,6 +46,7 @@ describe("Customer Details Modal", () => { // Assert expect(wrapper.vm.dispatchStoreAction).toHaveBeenCalled(); + expect(wrapper.vm.closeModal).toHaveBeenCalled(); }); test("Should not push to store if no fields have changed", async () => { @@ -64,6 +65,7 @@ describe("Customer Details Modal", () => { // Assert expect(wrapper.vm.dispatchStoreAction).not.toHaveBeenCalled(); + expect(wrapper.vm.closeModal).toHaveBeenCalled(); }); }); From 183e183987093317e0582acdb4cea6a25522990a Mon Sep 17 00:00:00 2001 From: Chloe Herd Date: Tue, 15 Aug 2023 16:40:45 -0400 Subject: [PATCH 41/60] Add form validation --- .../customer-details-modal-question.spec.js | 2 +- .../customer-details-modal-question.vue | 24 +++++++++++++++---- 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/src/layouts/review/review-sections/customer-review/customer-details-modal-question/customer-details-modal-question.spec.js b/src/layouts/review/review-sections/customer-review/customer-details-modal-question/customer-details-modal-question.spec.js index 0368effff..a8e0a6f7b 100644 --- a/src/layouts/review/review-sections/customer-review/customer-details-modal-question/customer-details-modal-question.spec.js +++ b/src/layouts/review/review-sections/customer-review/customer-details-modal-question/customer-details-modal-question.spec.js @@ -14,7 +14,7 @@ const testConstants = { newValues: { firstName: "New First", lastName: "New Last", - emailAddress: "builddigitaltest@safelite.com - new", + emailAddress: "builddigitaltest2@safelite.com", phoneNumber: "222-222-2222", isSmsOptIn: true, }, diff --git a/src/layouts/review/review-sections/customer-review/customer-details-modal-question/customer-details-modal-question.vue b/src/layouts/review/review-sections/customer-review/customer-details-modal-question/customer-details-modal-question.vue index 3ce86e39b..0b08abee7 100644 --- a/src/layouts/review/review-sections/customer-review/customer-details-modal-question/customer-details-modal-question.vue +++ b/src/layouts/review/review-sections/customer-review/customer-details-modal-question/customer-details-modal-question.vue @@ -16,28 +16,28 @@ v-model="firstName" ref="firstName" customInputId="firstName" - validation-rules="" /> + validation-rules="first-name-required" /> + validation-rules="last-name-required" /> + validation-rules="email-address-required|email-address-format" /> + validation-rules="phone-number-required" /> Date: Tue, 15 Aug 2023 16:46:25 -0400 Subject: [PATCH 42/60] Removed test navigation scenario to fix url --- src/router/index.js | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/router/index.js b/src/router/index.js index 6d812f847..e8fbf4d26 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -31,11 +31,6 @@ import { applicationConfig } from "../constants/application-config"; import review from "@/layouts/review/review"; import paymentMethod from "@/layouts/payment-method/payment-method"; const routes = [ - { - path: "/review", // This is a temporary route for testing. - name: "review", - component: review, - }, { path: "/payment-method", // This is a temporary route for testing. name: "payment-method", From 52cc88dbcae2493ad7cf1276f0a50b683e2c99cb Mon Sep 17 00:00:00 2001 From: Chloe Herd Date: Wed, 16 Aug 2023 17:40:57 -0400 Subject: [PATCH 43/60] Move customer-details-modal-question --- .../customer-details-modal-question.spec.js | 2 +- .../customer-details-modal-question.vue | 0 src/layouts/review/review.vue | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) rename src/layouts/review/{review-sections/customer-review => }/customer-details-modal-question/customer-details-modal-question.spec.js (96%) rename src/layouts/review/{review-sections/customer-review => }/customer-details-modal-question/customer-details-modal-question.vue (100%) diff --git a/src/layouts/review/review-sections/customer-review/customer-details-modal-question/customer-details-modal-question.spec.js b/src/layouts/review/customer-details-modal-question/customer-details-modal-question.spec.js similarity index 96% rename from src/layouts/review/review-sections/customer-review/customer-details-modal-question/customer-details-modal-question.spec.js rename to src/layouts/review/customer-details-modal-question/customer-details-modal-question.spec.js index a8e0a6f7b..abd264cef 100644 --- a/src/layouts/review/review-sections/customer-review/customer-details-modal-question/customer-details-modal-question.spec.js +++ b/src/layouts/review/customer-details-modal-question/customer-details-modal-question.spec.js @@ -1,7 +1,7 @@ import { shallowMount } from "@vue/test-utils"; import { getMountOptions } from "@/helpers/unit-test-helper.js"; -import customerDetailsModalQuestion from "@/layouts/review/review-sections/customer-review/customer-details-modal-question/customer-details-modal-question"; +import customerDetailsModalQuestion from "@/layouts/review/customer-details-modal-question/customer-details-modal-question"; const testConstants = { previousCustomerValues: { diff --git a/src/layouts/review/review-sections/customer-review/customer-details-modal-question/customer-details-modal-question.vue b/src/layouts/review/customer-details-modal-question/customer-details-modal-question.vue similarity index 100% rename from src/layouts/review/review-sections/customer-review/customer-details-modal-question/customer-details-modal-question.vue rename to src/layouts/review/customer-details-modal-question/customer-details-modal-question.vue diff --git a/src/layouts/review/review.vue b/src/layouts/review/review.vue index fe14e8f7e..0c9fa1533 100644 --- a/src/layouts/review/review.vue +++ b/src/layouts/review/review.vue @@ -115,7 +115,7 @@ import serviceLocationReview from "@/layouts/review/review-sections/service-loca import scheduleReview from "@/layouts/review/review-sections/schedule-review/schedule-review"; import customerReview from "@/layouts/review/review-sections/customer-review/customer-review"; -import customerDetailsModalQuestion from "@/layouts/review/review-sections/customer-review/customer-details-modal-question/customer-details-modal-question.vue"; +import customerDetailsModalQuestion from "@/layouts/review/customer-details-modal-question/customer-details-modal-question.vue"; import { fetchCmsContentForPage } from "@/helpers/cms-content-helper"; import { settleAllPromises } from "@/helpers/layout-helper"; From b5c783afbcd9d8ac9d9821cda1e21b18f6199ab1 Mon Sep 17 00:00:00 2001 From: sheena Date: Thu, 17 Aug 2023 16:35:22 +0530 Subject: [PATCH 44/60] csr-1584 updated the text --- src/layouts/estimate/estimate.vue | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/src/layouts/estimate/estimate.vue b/src/layouts/estimate/estimate.vue index 97b684d0f..22c2cc2e5 100644 --- a/src/layouts/estimate/estimate.vue +++ b/src/layouts/estimate/estimate.vue @@ -7,11 +7,8 @@
- -
+ From 24d6c8399b9a1d91e8b3bf12c4da7a9a49933edf Mon Sep 17 00:00:00 2001 From: sheena Date: Thu, 17 Aug 2023 16:39:34 +0530 Subject: [PATCH 45/60] Update estimate.vue --- src/layouts/estimate/estimate.vue | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/layouts/estimate/estimate.vue b/src/layouts/estimate/estimate.vue index 22c2cc2e5..dff601165 100644 --- a/src/layouts/estimate/estimate.vue +++ b/src/layouts/estimate/estimate.vue @@ -7,8 +7,8 @@
-
-
+ From 8a1bd85fd57cc8228b99033ec947609f3ad40ef2 Mon Sep 17 00:00:00 2001 From: CarlNation Date: Thu, 17 Aug 2023 09:00:20 -0400 Subject: [PATCH 46/60] api model changes api model changes --- src/constants/endpoints.js | 2 +- src/store/index.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/constants/endpoints.js b/src/constants/endpoints.js index 05a55cc5c..373779380 100644 --- a/src/constants/endpoints.js +++ b/src/constants/endpoints.js @@ -119,7 +119,7 @@ const endpoints = { method: "GET", }, SaveSession: { - url: "/order/api/v1/order/save-session", + url: "/order/api/v1/order/save-session/fmg", method: "POST", }, LoadSession: { diff --git a/src/store/index.js b/src/store/index.js index 6bdcffafc..2116e1658 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -476,7 +476,7 @@ export const mutations = { state.order.customer.emailAddress = sessionInformation.order.customer.emailAddress; state.order.customer.firstName = sessionInformation.order.customer.firstName; state.order.customer.lastName = sessionInformation.order.customer.lastName; - state.order.customer.phoneNumber = sessionInformation.order.customer.phoneNumber; + state.order.customer.phoneNumber = sessionInformation.order.customer.servicePhoneNumber; state.order.customer.isSmsOptIn = sessionInformation.order.customer.isSmsOptIn; state.order.existingPromoCode = sessionInformation.order.existingPromoCode; @@ -1430,7 +1430,7 @@ export const actions = { firstName: order.customer.firstName, lastName: order.customer.lastName, isSmsOptIn: order.customer.isSmsOptIn, - phoneNumber: order.customer.phoneNumber, + servicePhoneNumber: order.customer.phoneNumber, }, damage: { numberOfChips: damage.numberOfChips, From d5e47707982c0307fc00a1f5e642e38cb5cfaa4a Mon Sep 17 00:00:00 2001 From: Chloe Herd Date: Thu, 17 Aug 2023 10:07:40 -0400 Subject: [PATCH 47/60] Change modal to back-nav --- .../customer-details-modal-question.spec.js | 150 ------------------ .../customer-details-modal-question.vue | 148 ----------------- src/layouts/review/review.vue | 12 +- .../router-constants/navigation-scenarios.js | 1 + src/router/router-constants/routing-table.js | 4 + 5 files changed, 9 insertions(+), 306 deletions(-) delete mode 100644 src/layouts/review/customer-details-modal-question/customer-details-modal-question.spec.js delete mode 100644 src/layouts/review/customer-details-modal-question/customer-details-modal-question.vue diff --git a/src/layouts/review/customer-details-modal-question/customer-details-modal-question.spec.js b/src/layouts/review/customer-details-modal-question/customer-details-modal-question.spec.js deleted file mode 100644 index abd264cef..000000000 --- a/src/layouts/review/customer-details-modal-question/customer-details-modal-question.spec.js +++ /dev/null @@ -1,150 +0,0 @@ -import { shallowMount } from "@vue/test-utils"; -import { getMountOptions } from "@/helpers/unit-test-helper.js"; - -import customerDetailsModalQuestion from "@/layouts/review/customer-details-modal-question/customer-details-modal-question"; - -const testConstants = { - previousCustomerValues: { - firstName: "First", - lastName: "Last", - emailAddress: "builddigitaltest@safelite.com", - phoneNumber: "111-111-1111", - isSmsOptIn: false, - }, - newValues: { - firstName: "New First", - lastName: "New Last", - emailAddress: "builddigitaltest2@safelite.com", - phoneNumber: "222-222-2222", - isSmsOptIn: true, - }, -}; - -let cmsContent; - -describe("Customer Details Modal", () => { - beforeEach(() => { - cmsContent = {}; - }); - - describe("Submit", () => { - test("Should push to store if a field has changed", async () => { - // Arrange - let props = generateDefaultProps(); - - const { wrapper } = setupMocks({ - propsData: props, - }); - - // Act - wrapper.vm.onModalOpened(); - - wrapper.vm.firstName = testConstants.newValues.firstName; - - await wrapper.vm.setContactDetails(); - await wrapper.vm.$nextTick(); - - // Assert - expect(wrapper.vm.dispatchStoreAction).toHaveBeenCalled(); - expect(wrapper.vm.closeModal).toHaveBeenCalled(); - }); - - test("Should not push to store if no fields have changed", async () => { - // Arrange - let props = generateDefaultProps(); - - const { wrapper } = setupMocks({ - propsData: props, - }); - - // Act - wrapper.vm.onModalOpened(); - - await wrapper.vm.setContactDetails(); - await wrapper.vm.$nextTick(); - - // Assert - expect(wrapper.vm.dispatchStoreAction).not.toHaveBeenCalled(); - expect(wrapper.vm.closeModal).toHaveBeenCalled(); - }); - }); - - describe("Default values", () => { - test("Should populate on open", () => { - // Arrange - let props = generateDefaultProps(); - - const { wrapper } = setupMocks({ - propsData: props, - }); - - // Act - wrapper.vm.onModalOpened(); - - // Assert - expect(wrapper.vm.firstName).toBe(testConstants.previousCustomerValues.firstName); - expect(wrapper.vm.lastName).toBe(testConstants.previousCustomerValues.lastName); - expect(wrapper.vm.emailAddress).toBe(testConstants.previousCustomerValues.emailAddress); - expect(wrapper.vm.phoneNumber).toBe(testConstants.previousCustomerValues.phoneNumber); - expect(wrapper.vm.isSmsOptIn).toBe(testConstants.previousCustomerValues.isSmsOptIn); - }); - - test("Should replace old values on open", async () => { - // Arrange - let props = generateDefaultProps(); - - const { wrapper } = setupMocks({ - propsData: props, - }); - - // Act - wrapper.vm.firstName = testConstants.newValues.firstName; - wrapper.vm.lastName = testConstants.newValues.lastName; - wrapper.vm.emailAddress = testConstants.newValues.emailAddress; - wrapper.vm.phoneNumber = testConstants.newValues.phoneNumber; - wrapper.vm.isSmsOptIn = testConstants.newValues.isSmsOptIn; - - wrapper.vm.onModalOpened(); - - // Assert - expect(wrapper.vm.firstName).toBe(testConstants.previousCustomerValues.firstName); - expect(wrapper.vm.lastName).toBe(testConstants.previousCustomerValues.lastName); - expect(wrapper.vm.emailAddress).toBe(testConstants.previousCustomerValues.emailAddress); - expect(wrapper.vm.phoneNumber).toBe(testConstants.previousCustomerValues.phoneNumber); - expect(wrapper.vm.isSmsOptIn).toBe(testConstants.previousCustomerValues.isSmsOptIn); - }); - }); -}); - -function generateDefaultProps() { - return { - previousCustomerValues: { - firstName: testConstants.previousCustomerValues.firstName, - lastName: testConstants.previousCustomerValues.lastName, - emailAddress: testConstants.previousCustomerValues.emailAddress, - phoneNumber: testConstants.previousCustomerValues.phoneNumber, - isSmsOptIn: testConstants.previousCustomerValues.isSmsOptIn, - }, - }; -} - -function setupMocks(customMountOptions) { - const mountOptions = getMountOptions(customMountOptions); - - const mockMixin = { - methods: { - getCmsContent: jest.fn((widgetName, cmsFieldName) => { - return cmsContent?.[widgetName]?.[cmsFieldName] ?? ""; - }), - }, - }; - - mountOptions.global.mixins = [mockMixin]; - - const wrapper = shallowMount(customerDetailsModalQuestion, mountOptions); - wrapper.vm.setCmsContent = jest.fn(); - wrapper.vm.openModal = jest.fn(); - wrapper.vm.closeModal = jest.fn(); - wrapper.vm.dispatchStoreAction = jest.fn(); - return { wrapper }; -} diff --git a/src/layouts/review/customer-details-modal-question/customer-details-modal-question.vue b/src/layouts/review/customer-details-modal-question/customer-details-modal-question.vue deleted file mode 100644 index 0b08abee7..000000000 --- a/src/layouts/review/customer-details-modal-question/customer-details-modal-question.vue +++ /dev/null @@ -1,148 +0,0 @@ - - - diff --git a/src/layouts/review/review.vue b/src/layouts/review/review.vue index 0c9fa1533..be0af585e 100644 --- a/src/layouts/review/review.vue +++ b/src/layouts/review/review.vue @@ -89,10 +89,6 @@
- - diff --git a/src/router/router-constants/navigation-scenarios.js b/src/router/router-constants/navigation-scenarios.js index ce2f32134..10339a6a0 100644 --- a/src/router/router-constants/navigation-scenarios.js +++ b/src/router/router-constants/navigation-scenarios.js @@ -52,6 +52,7 @@ const navigationScenarios = { CLICKED_SERVICE_PACKAGE_EDIT: "CLICKED_SERVICE_PACKAGE_EDIT", CLICKED_SERVICE_LOCATION_EDIT: "CLICKED_SERVICE_LOCATION_EDIT", CLICKED_SCHEDULE_EDIT: "CLICKED_SCHEDULE_EDIT", + CLICKED_CUSTOMER_EDIT: "CLICKED_CUSTOMER_EDIT", }; export { navigationScenarios }; diff --git a/src/router/router-constants/routing-table.js b/src/router/router-constants/routing-table.js index f1f83b445..953eaffc3 100644 --- a/src/router/router-constants/routing-table.js +++ b/src/router/router-constants/routing-table.js @@ -488,6 +488,10 @@ const routingTable = function (store) { scenario: navigationScenarios.CLICKED_SCHEDULE_EDIT, destinationFmgPageValue: fmgPageValues.SCHEDULE, }, + { + scenario: navigationScenarios.CLICKED_CUSTOMER_EDIT, + destinationFmgPageValue: fmgPageValues.CUSTOMER_DETAILS, + }, ], }, ]; From 7ed74f5915f59a7417958941cb0e9e310f3d1a63 Mon Sep 17 00:00:00 2001 From: Chloe Herd Date: Thu, 17 Aug 2023 11:10:48 -0400 Subject: [PATCH 48/60] Remove custom hack from cms as no longer needed --- .../review-sections/customer-review/customer-review.vue | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/layouts/review/review-sections/customer-review/customer-review.vue b/src/layouts/review/review-sections/customer-review/customer-review.vue index d8777d9e4..678dcf0b6 100644 --- a/src/layouts/review/review-sections/customer-review/customer-review.vue +++ b/src/layouts/review/review-sections/customer-review/customer-review.vue @@ -36,10 +36,7 @@ export default { return this.customer?.phoneNumber; }, smsOptIn() { - const rawCmsText = this.getCmsContent(this.cmsWidgetName, "SubheaderText"); - const joinerText = this.customer?.isSmsOptIn ? "in to" : "out of"; - - return rawCmsText.replace("{custom:smsOptInJoiner}", joinerText); + return this.getCmsContent(this.cmsWidgetName, "SubheaderText"); }, }, components: { From 1f6a18dcaf21e9a8cbe7c8f45c5e91eeac50ea12 Mon Sep 17 00:00:00 2001 From: Sneha Date: Mon, 21 Aug 2023 12:36:42 +0530 Subject: [PATCH 49/60] CSR-1418 --- .../vehicle-banner/vehicle-banner.spec.js | 13 ++++- .../vehicle-banner/vehicle-banner.vue | 16 +++++- src/layouts/vehicle/vehicle.vue | 52 +++++++++++++------ src/store/index.js | 18 ++++--- src/store/store.spec.js | 18 ++++--- 5 files changed, 84 insertions(+), 33 deletions(-) diff --git a/src/fmg-components/vehicle-banner/vehicle-banner.spec.js b/src/fmg-components/vehicle-banner/vehicle-banner.spec.js index b4d723e18..1a9222299 100644 --- a/src/fmg-components/vehicle-banner/vehicle-banner.spec.js +++ b/src/fmg-components/vehicle-banner/vehicle-banner.spec.js @@ -18,6 +18,7 @@ describe("vehicleBanner", () => { const { wrapper } = setupMocks({ displayGenericVehicleImageProp: true, imageUrlValue: "NULL", + displayUnmatchedVehicleIconProp: true, }); // Assert @@ -87,7 +88,12 @@ describe("vehicleBanner", () => { ); }); -function setupMocks({ displayGenericVehicleImageProp, imageUrlValue, categoryValue = "CAR" }) { +function setupMocks({ + displayGenericVehicleImageProp, + displayUnmatchedVehicleIconProp, + imageUrlValue, + categoryValue = "CAR", +}) { const mockGetCmsContent = jest.fn(); mockGetCmsContent((cmsWidget, field) => { return field; @@ -108,7 +114,10 @@ function setupMocks({ displayGenericVehicleImageProp, imageUrlValue, categoryVal }); //Mock props - mountOptions.propsData = { displayGenericVehicleImage: displayGenericVehicleImageProp }; + mountOptions.propsData = { + displayGenericVehicleImage: displayGenericVehicleImageProp, + displayUnmatchedVehicleIconProp: displayUnmatchedVehicleIconProp, + }; mountOptions.mixins = [mockMixin]; const wrapper = shallowMount(vehicleBanner, mountOptions); diff --git a/src/fmg-components/vehicle-banner/vehicle-banner.vue b/src/fmg-components/vehicle-banner/vehicle-banner.vue index 3354db13c..8bff4e9e2 100644 --- a/src/fmg-components/vehicle-banner/vehicle-banner.vue +++ b/src/fmg-components/vehicle-banner/vehicle-banner.vue @@ -18,6 +18,16 @@ export default { required: false, default: null, }, + displayUnmatchedVehicleIcon: { + type: Boolean, + required: false, + default: false, + }, + vehicleCategory: { + type: String, + required: false, + default: null, + }, }, computed: { vehicleImageToDisplay() { @@ -29,7 +39,8 @@ export default { } if ( this.$store.getters.vehicle.imageUrl === null || - this.$store.getters.vehicle.imageUrl === "NULL" + this.$store.getters.vehicle.imageUrl === "NULL" || + this.displayUnmatchedVehicleIcon ) { return this.getUnmatchedVehicleIcon(); } @@ -57,7 +68,8 @@ export default { }, methods: { getUnmatchedVehicleIcon() { - switch (this.$store.getters.vehicle.category) { + const category = this.vehicleCategory ?? this.$store.getters.vehicle.category; + switch (category) { case this.vehicleCategories.CAR: return this.carUnmatchedVehicleIcon; case this.vehicleCategories.SUV: diff --git a/src/layouts/vehicle/vehicle.vue b/src/layouts/vehicle/vehicle.vue index 13001e2fd..37e813bed 100644 --- a/src/layouts/vehicle/vehicle.vue +++ b/src/layouts/vehicle/vehicle.vue @@ -58,7 +58,9 @@ @@ -110,17 +112,17 @@ export default { selectedMake: this.selectedMakefromStore(), selectedModel: this.selectedModelfromStore(), selectedStyle: this.selectedStylefromStore(), - vehicle: { - carId: null, - category: null, - imageUrl: null, - imageVifNumber: null, - imageVifColor: null, - }, + carId: null, + category: null, + imageUrl: null, + imageVifNumber: null, + imageVifColor: null, yearOptions: [], makeOptions: [], modelOptions: [], styleOptions: [], + displayGeneric: this.displayGenericFromStore(), + unmatchedVehicleIcon: false, }; }, @@ -279,7 +281,18 @@ export default { this.selectedModel, style ); - this.vehicle = result?.data; + this.carId = result?.data.carId; + this.category = result?.data.category; + this.imageUrl = result?.data.imageUrl; + this.imageVifNumber = result?.data.imageVifNumber; + this.imageVifColor = result?.data.imageVifColor; + if (this.imageUrl == null) { + this.displayGeneric = false; + this.unmatchedVehicleIcon = true; + } else this.unmatchedVehicleIcon = false; + } else { + this.imageUrl = null; + this.displayGeneric = true; } }, }, @@ -293,6 +306,15 @@ export default { style: style, }); }, + displayGenericFromStore() { + if (store.getters.vehicle.imageUrl !== null) return false; + else if ( + store.getters.vehicle.imageUrl === null && + store.getters.vehicle.carId !== null + ) + return false; + else return true; + }, arePagePrerequisitesValid() { return true; }, @@ -305,7 +327,11 @@ export default { make: this.selectedMake, model: this.selectedModel, style: this.selectedStyle, - vehicle: this.vehicle, + carId: this.carId, + category: this.category, + imageUrl: this.imageUrl, + imageVifNumber: this.imageVifNumber, + imageVifColor: this.imageVifColor, }, false ); @@ -353,12 +379,6 @@ export default { }, }, - computed: { - displayGeneric() { - return !this.selectedStyle; - }, - }, - components: { funnelHeader, funnelFooter, diff --git a/src/store/index.js b/src/store/index.js index 2116e1658..b8a20b25b 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -1637,8 +1637,12 @@ export const actions = { } }, - saveVehicle(context, { year, make, model, style, vehicle }) { - context.dispatch(storeActions.RESET_PARTS_STATE_AND_DEPENDENCIES); + saveVehicle( + context, + { year, make, model, style, carId, category, imageUrl, imageVifNumber, imageVifColor } + ) { + context.dispatch(storeActions.RESET_DAMAGE_STATE_AND_DEPENDENCIES); + context.dispatch(storeActions.RESET_REGISTRATION_STATE_AND_DEPENDENCIES); if (context.state.order.vehicle.year !== year) { context.commit(storeMutations.UPDATE_YEAR, year); @@ -1652,11 +1656,11 @@ export const actions = { if (context.state.order.vehicle.style !== style) { context.commit(storeMutations.UPDATE_STYLE, style); } - context.commit(storeMutations.UPDATE_CAR_ID, vehicle.carId); - context.commit(storeMutations.UPDATE_VEHICLE_CATEGORY, vehicle.category); - context.commit(storeMutations.UPDATE_VEHICLE_IMAGE_URL, vehicle.imageUrl); - context.commit(storeMutations.UPDATE_VEHICLE_IMAGE_VIF_NUMBER, vehicle.imageVifNumber); - context.commit(storeMutations.UPDATE_VEHICLE_IMAGE_COLOR, vehicle.imageVifColor); + context.commit(storeMutations.UPDATE_CAR_ID, carId); + context.commit(storeMutations.UPDATE_VEHICLE_CATEGORY, category); + context.commit(storeMutations.UPDATE_VEHICLE_IMAGE_URL, imageUrl); + context.commit(storeMutations.UPDATE_VEHICLE_IMAGE_VIF_NUMBER, imageVifNumber); + context.commit(storeMutations.UPDATE_VEHICLE_IMAGE_COLOR, imageVifColor); }, saveVehicleDamage( diff --git a/src/store/store.spec.js b/src/store/store.spec.js index f70bbd3d1..0bb1d72c9 100644 --- a/src/store/store.spec.js +++ b/src/store/store.spec.js @@ -1762,14 +1762,20 @@ describe("Actions", () => { make: "Honda", model: "Civic", style: "Sedan", - vehicle: { - carId: "C00000000", - category: "CAR", - }, + carId: "C00000000", + category: "CAR", }; actions.saveVehicle(context, payload); //Assert + expect(dispatch).toHaveBeenNthCalledWith( + 1, + storeActions.RESET_DAMAGE_STATE_AND_DEPENDENCIES + ); + expect(dispatch).toHaveBeenNthCalledWith( + 2, + storeActions.RESET_REGISTRATION_STATE_AND_DEPENDENCIES + ); if (context.state.order.vehicle.year !== payload.year) { expect(commit).toBeCalledWith(storeMutations.UPDATE_YEAR, payload.year); } @@ -1782,8 +1788,8 @@ describe("Actions", () => { if (context.state.order.vehicle.style !== payload.style) { expect(commit).toBeCalledWith(storeMutations.UPDATE_STYLE, payload.style); } - context.commit(storeMutations.UPDATE_CAR_ID, payload.vehicle.carId); - context.commit(storeMutations.UPDATE_VEHICLE_CATEGORY, payload.vehicle.category); + context.commit(storeMutations.UPDATE_CAR_ID, payload.carId); + context.commit(storeMutations.UPDATE_VEHICLE_CATEGORY, payload.category); }); it("saveVehicleDamage, should wipe out damage if different", () => { From 93b1d489d13446754a2fb9c6ba267dd87a5abb52 Mon Sep 17 00:00:00 2001 From: hiteshkumar87 Date: Mon, 21 Aug 2023 13:38:05 +0530 Subject: [PATCH 50/60] CSR-1416 Quote page - Default to Insurance Tab if user Service zip is from certain States --- src/constants/pay-with-insurance-states.js | 1 + src/layouts/quote/quote.spec.js | 45 ++++++++++++++++++++++ src/layouts/quote/quote.vue | 13 +++++-- 3 files changed, 56 insertions(+), 3 deletions(-) create mode 100644 src/constants/pay-with-insurance-states.js diff --git a/src/constants/pay-with-insurance-states.js b/src/constants/pay-with-insurance-states.js new file mode 100644 index 000000000..e65589557 --- /dev/null +++ b/src/constants/pay-with-insurance-states.js @@ -0,0 +1 @@ +export const payWithInsuranceStates = ["AZ", "CT", "FL", "KY", "MA", "MN", "NY", "SC"]; diff --git a/src/layouts/quote/quote.spec.js b/src/layouts/quote/quote.spec.js index 6895b5d0b..b4a3df9fb 100644 --- a/src/layouts/quote/quote.spec.js +++ b/src/layouts/quote/quote.spec.js @@ -263,6 +263,9 @@ describe("quote.vue", () => { payment: { isInsurance: null, }, + serviceLocation: { + state: null, + }, }, }; wrapper.vm.$route = { query: { isInsurance: "true" } }; @@ -290,6 +293,9 @@ describe("quote.vue", () => { payment: { isInsurance: null, }, + serviceLocation: { + state: null, + }, }, }; wrapper.vm.$route = { query: { isInsurance: "false" } }; @@ -317,6 +323,9 @@ describe("quote.vue", () => { payment: { isInsurance: true, }, + serviceLocation: { + state: null, + }, }, }; // Ensure that query param isn't overriding selection @@ -345,6 +354,9 @@ describe("quote.vue", () => { payment: { isInsurance: false, }, + serviceLocation: { + state: null, + }, }, }; // Ensure that query param isn't overriding selection @@ -374,6 +386,9 @@ describe("quote.vue", () => { payment: { isInsurance: null, // Ensure that previous selection isn't overriding selection }, + serviceLocation: { + state: null, + }, }, }; mockTierOnePrice = 200; @@ -404,6 +419,9 @@ describe("quote.vue", () => { payment: { isInsurance: null, // Ensure that previous selection isn't overriding selection }, + serviceLocation: { + state: null, + }, }, }; mockTierOnePrice = 505; @@ -421,6 +439,33 @@ describe("quote.vue", () => { //Assert expect(wrapper.vm.isInsuranceSelected).toBe(true); }); + test("Should default to insurence if user Service zip is from certain States", async () => { + //Arrange + const { wrapper } = setupMocks({}); + store.getters = { + order: { + lineItems: { + glassParts: ["item", "item2"], + }, + payment: { + isInsurance: null, + }, + serviceLocation: { + state: "AZ", + }, + }, + }; + wrapper.vm.$route = { query: null }; + //Act + await quote.beforeRouteEnter.call( + wrapper.vm, + { query: { fmgPage: "quote" } }, + undefined, + (c) => c(wrapper.vm) + ); + //Assert + expect(wrapper.vm.isInsuranceSelected).toBe(true); + }); }); function setupMocks({ customMountOptions }) { diff --git a/src/layouts/quote/quote.vue b/src/layouts/quote/quote.vue index b17b0f3ac..eb4fe3917 100644 --- a/src/layouts/quote/quote.vue +++ b/src/layouts/quote/quote.vue @@ -67,7 +67,7 @@ import { errorMessages } from "@/constants/error-messages"; import { Form, defineRule } from "vee-validate"; import { navigateToHeritageFunnel } from "@/helpers/heritage-integration/navigation-helper"; import { applicationConfig } from "@/constants/application-config"; - +import { payWithInsuranceStates } from "@/constants/pay-with-insurance-states"; defineRule("option-required", required(errorMessages.OPTION_REQUIRED)); export default { @@ -153,12 +153,19 @@ export default { store.getters.order.referralNumber?.length !== 6 ); }, - getDefaultIsInsuranceSelectedValue(availableLineItems) { + getDefaultIsInsuranceSelectedValue(availableLineItems) { + const serviceLocationState = store.getters.order.serviceLocation.state; // Override if coming back from QuoteDetails. Remove override after Quote release const isInsuranceOverrideValue = this.$route.query?.isInsurance; const defaultIsInsuranceSelectedValue = this.$store.getters.order.payment.isInsurance; - if (isInsuranceOverrideValue != null) { + //Default to Insurance Tab if user Service zip is from certain States + if ( + serviceLocationState != null && + payWithInsuranceStates.find((item) => item === serviceLocationState) + ) + return true; + else if (isInsuranceOverrideValue != null) { return isInsuranceOverrideValue == "true"; } else if (defaultIsInsuranceSelectedValue != null) { return defaultIsInsuranceSelectedValue; From 66a371b2c62d4cc77bdc57947debe1ffa7c8bbf9 Mon Sep 17 00:00:00 2001 From: hiteshkumar87 Date: Mon, 21 Aug 2023 14:28:39 +0530 Subject: [PATCH 51/60] Update quote.vue --- src/layouts/quote/quote.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/layouts/quote/quote.vue b/src/layouts/quote/quote.vue index eb4fe3917..72d519028 100644 --- a/src/layouts/quote/quote.vue +++ b/src/layouts/quote/quote.vue @@ -153,7 +153,7 @@ export default { store.getters.order.referralNumber?.length !== 6 ); }, - getDefaultIsInsuranceSelectedValue(availableLineItems) { + getDefaultIsInsuranceSelectedValue(availableLineItems) { const serviceLocationState = store.getters.order.serviceLocation.state; // Override if coming back from QuoteDetails. Remove override after Quote release const isInsuranceOverrideValue = this.$route.query?.isInsurance; From 435572ecc510d53550683d3730f14bbe38e91273 Mon Sep 17 00:00:00 2001 From: Sneha Date: Mon, 21 Aug 2023 18:09:25 +0530 Subject: [PATCH 52/60] Update index.js --- src/store/index.js | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/store/index.js b/src/store/index.js index 4345daf01..35b4c266e 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -1568,8 +1568,12 @@ export const actions = { // Business domain actions // Vehicle - saveVehicle(context, { year, make, model, style, vehicle }) { - context.dispatch(storeActions.RESET_PARTS_STATE_AND_DEPENDENCIES); + saveVehicle( + context, + { year, make, model, style, carId, category, imageUrl, imageVifNumber, imageVifColor } + ) { + context.dispatch(storeActions.RESET_DAMAGE_STATE_AND_DEPENDENCIES); + context.dispatch(storeActions.RESET_REGISTRATION_STATE_AND_DEPENDENCIES); if (context.state.order.vehicle.year !== year) { context.commit(storeMutations.UPDATE_YEAR, year); @@ -1583,11 +1587,11 @@ export const actions = { if (context.state.order.vehicle.style !== style) { context.commit(storeMutations.UPDATE_STYLE, style); } - context.commit(storeMutations.UPDATE_CAR_ID, vehicle.carId); - context.commit(storeMutations.UPDATE_VEHICLE_CATEGORY, vehicle.category); - context.commit(storeMutations.UPDATE_VEHICLE_IMAGE_URL, vehicle.imageUrl); - context.commit(storeMutations.UPDATE_VEHICLE_IMAGE_VIF_NUMBER, vehicle.imageVifNumber); - context.commit(storeMutations.UPDATE_VEHICLE_IMAGE_COLOR, vehicle.imageVifColor); + context.commit(storeMutations.UPDATE_CAR_ID, carId); + context.commit(storeMutations.UPDATE_VEHICLE_CATEGORY, category); + context.commit(storeMutations.UPDATE_VEHICLE_IMAGE_URL, imageUrl); + context.commit(storeMutations.UPDATE_VEHICLE_IMAGE_VIF_NUMBER, imageVifNumber); + context.commit(storeMutations.UPDATE_VEHICLE_IMAGE_COLOR, imageVifColor); }, saveVehicleDamage( From a921521f5c6d9c7616d04ea73e99739c95e45b6e Mon Sep 17 00:00:00 2001 From: CarlNation <32103961+CarlNation@users.noreply.github.com> Date: Tue, 22 Aug 2023 10:02:02 -0400 Subject: [PATCH 53/60] Create work order --- src/constants/store-actions.js | 1 + src/constants/store-mutations.js | 2 ++ src/layouts/customer-details/customer-details.vue | 1 + src/store/index.js | 10 ++++++++++ 4 files changed, 14 insertions(+) diff --git a/src/constants/store-actions.js b/src/constants/store-actions.js index c4efe9d45..f9e1dcb17 100644 --- a/src/constants/store-actions.js +++ b/src/constants/store-actions.js @@ -87,6 +87,7 @@ const storeActions = { SAVE_VAPS: "saveVaps", SAVE_CUSTOMER_DETAILS: "saveCustomerDetails", SAVE_SERVICE_LOCATION_TECH_NOTES: "saveServiceLocationTechNotes", + SAVE_WORK_ORDER_FLAG: "saveWorkOrderFlag", }; export { storeActions }; diff --git a/src/constants/store-mutations.js b/src/constants/store-mutations.js index fd568ead7..240a76762 100644 --- a/src/constants/store-mutations.js +++ b/src/constants/store-mutations.js @@ -1,4 +1,6 @@ const storeMutations = { + UPDATE_WORK_ORDER_FLAG: "updateWorkOrderFlag", + // VEHICLE MUTATIONS UPDATE_YEAR: "updateYear", UPDATE_MAKE: "updateMake", diff --git a/src/layouts/customer-details/customer-details.vue b/src/layouts/customer-details/customer-details.vue index 55e1b01b8..82e9f6f4b 100644 --- a/src/layouts/customer-details/customer-details.vue +++ b/src/layouts/customer-details/customer-details.vue @@ -163,6 +163,7 @@ export default { false ); + this.dispatchStoreAction(this.storeActions.SAVE_WORK_ORDER_FLAG, true, false); this.$router.navigateWithSaving(this.navigationScenarios.CLICKED_FORWARD, this.$route); }, }, diff --git a/src/store/index.js b/src/store/index.js index 2116e1658..ab3f53455 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -25,6 +25,7 @@ import { // Export State const getDefaultState = () => { return { + submitAfterSave: false, order: { vehicle: { year: null, @@ -123,6 +124,10 @@ export const state = getDefaultState(); // Export Mutations export const mutations = { + updateWorkOrderFlag(state, submitAfterSave) { + state.submitAfterSave = submitAfterSave; + }, + // VEHICLE MUTATIONS updateYear(state, year) { state.order.vehicle.year = year; @@ -1400,6 +1405,7 @@ export const actions = { method: endpoints.SaveSession.method, endpoint: endpoints.SaveSession.url, payload: { + submitAfterSave: context.state.submitAfterSave, applicationUser: { crmCustomerId: applicationUser.crmCustomerId, experiments: applicationUser.experiments, @@ -1552,6 +1558,10 @@ export const actions = { ); }, + saveWorkOrderFlag(context, submitAfterSave) { + context.commit(storeMutations.UPDATE_WORK_ORDER_FLAG, submitAfterSave); + }, + // Business domain actions // Vehicle From 398964ea597a7abe11dbd05958d4b20233f51094 Mon Sep 17 00:00:00 2001 From: sheena Date: Tue, 22 Aug 2023 20:07:44 +0530 Subject: [PATCH 54/60] CSR-1599 Updated the color --- .../shop-question/shop-list-button/shop-list-button.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/layouts/service-location/shop-question/shop-list-button/shop-list-button.vue b/src/layouts/service-location/shop-question/shop-list-button/shop-list-button.vue index 31c415a2d..9a0fb063e 100644 --- a/src/layouts/service-location/shop-question/shop-list-button/shop-list-button.vue +++ b/src/layouts/service-location/shop-question/shop-list-button/shop-list-button.vue @@ -88,7 +88,7 @@ export default { if (this.availabilityRating == null) { return "gray"; } else { - return this.availabilityRating == "high" ? "green" : "red"; + return this.availabilityRating == "high" ? "green" : "Orange"; } }, badgeText() { From 8cae60577a98080f9ba8df67fe916a6e96506c21 Mon Sep 17 00:00:00 2001 From: Chloe Herd Date: Tue, 22 Aug 2023 16:33:13 -0400 Subject: [PATCH 55/60] Update Tests --- .../customer-review/customer-review.spec.js | 61 ++++--------------- 1 file changed, 12 insertions(+), 49 deletions(-) diff --git a/src/layouts/review/review-sections/customer-review/customer-review.spec.js b/src/layouts/review/review-sections/customer-review/customer-review.spec.js index 1bcbbe83b..45627df2e 100644 --- a/src/layouts/review/review-sections/customer-review/customer-review.spec.js +++ b/src/layouts/review/review-sections/customer-review/customer-review.spec.js @@ -9,11 +9,7 @@ const testConstants = { text: "Header", }, sms: { - template: "Test {custom:smsOptInJoiner}", - expected: { - ifTrue: "Test in to", - ifFalse: "Test out of", - }, + text: "Sms", }, }, customer: { @@ -27,7 +23,7 @@ const testConstants = { fullName: "First Last", phoneNumber: "111-111-1111", emailAddress: "builddigitaltest@safelite.com", - smsOptIn: "Test out of", + smsOptIn: "Sms", }, }; @@ -38,7 +34,7 @@ describe("Customer Review Block", () => { cmsContent = { CustomerWidget: { HeaderText: testConstants.cms.header.text, - SubheaderText: testConstants.cms.sms.template, + SubheaderText: testConstants.cms.sms.text, }, }; }); @@ -58,52 +54,19 @@ describe("Customer Review Block", () => { expect(wrapper.vm.header).toEqual(testConstants.cms.header.text); }); - describe("SMS Opt In Text", () => { - test("Should render correctly when opt in is true:", async () => { - // Arrange - let props = generateDefaultProps(); - props.customer.isSmsOptIn = true; + test("Should display sms text from cms", async () => { + // Arrange + let props = generateDefaultProps(); - const { wrapper } = setupMocks({ - propsData: props, - }); - - // Act - await wrapper.vm.$nextTick(); - - // Assert - expect(wrapper.vm.smsOptIn).toEqual(testConstants.cms.sms.expected.ifTrue); + const { wrapper } = setupMocks({ + propsData: props, }); - test("Should render correctly when opt in is false:", async () => { - // Arrange - let props = generateDefaultProps(); - props.customer.isSmsOptIn = false; - const { wrapper } = setupMocks({ - propsData: props, - }); + // Act + await wrapper.vm.$nextTick(); - // Act - await wrapper.vm.$nextTick(); - - // Assert - expect(wrapper.vm.smsOptIn).toEqual(testConstants.cms.sms.expected.ifFalse); - }); - test("Should render correctly when opt in is null:", async () => { - // Arrange - let props = generateDefaultProps(); - props.customer.isSmsOptIn = null; - - const { wrapper } = setupMocks({ - propsData: props, - }); - - // Act - await wrapper.vm.$nextTick(); - - // Assert - expect(wrapper.vm.smsOptIn).toEqual(testConstants.cms.sms.expected.ifFalse); - }); + // Assert + expect(wrapper.vm.smsOptIn).toEqual(testConstants.cms.sms.text); }); test("Should render correct display content", async () => { From 54010aa81f4095f7f77f15a962dd955aec400800 Mon Sep 17 00:00:00 2001 From: Chloe Herd Date: Wed, 23 Aug 2023 10:12:41 -0400 Subject: [PATCH 56/60] Add prereq check --- src/layouts/review/review.vue | 63 ++++++++++++++++++++++++++++++++++- 1 file changed, 62 insertions(+), 1 deletion(-) diff --git a/src/layouts/review/review.vue b/src/layouts/review/review.vue index be0af585e..61538c8f3 100644 --- a/src/layouts/review/review.vue +++ b/src/layouts/review/review.vue @@ -111,8 +111,11 @@ import serviceLocationReview from "@/layouts/review/review-sections/service-loca import scheduleReview from "@/layouts/review/review-sections/schedule-review/schedule-review"; import customerReview from "@/layouts/review/review-sections/customer-review/customer-review"; +import { AppointmentTypeStrings } from "@/constants/schedule-constants"; + import { fetchCmsContentForPage } from "@/helpers/cms-content-helper"; import { settleAllPromises } from "@/helpers/layout-helper"; +import store from "@/store"; export default { name: "review", @@ -147,7 +150,65 @@ export default { }, methods: { arePagePrerequisitesValid() { - return true; + // Vehicle + const vehicle = store.getters.order.vehicle; + const vehicleReqs = vehicle.year && vehicle.make && vehicle.model && vehicle.style; + + // Damage + const damage = store.getters.order.damage; + const damageReqs = + (damage.isRepair && damage.numberOfChips) || damage.glassToReplace?.length; + + // Service Package + const lineItems = store.getters.order.lineItems; + // damageReqs handles checking for damage, even though it is also required for this section. + const packageReqs = (damage.isRepair || lineItems.glassParts) && lineItems.supportingItems && lineItems.vaps; + + // Service Location + const serviceLocation = store.getters.order.serviceLocation; + const mobileReqs = + serviceLocation.address && + serviceLocation.city && + serviceLocation.state && + serviceLocation.zipCode; + + const providerLocation = serviceLocation.provider.address; + const dropOffInshopReqs = + providerLocation.streetAddress && + providerLocation.city && + providerLocation.state && + providerLocation.zipCode; + + const isMobile = serviceLocation.appointmentType === AppointmentTypeStrings.MOBILE; + + const serviceLocationReqs = + (isMobile && mobileReqs) || (!isMobile && dropOffInshopReqs); + + // Schedule + const schedule = store.getters.order.schedule; + const scheduleReqs = + schedule.date && + schedule.startTime && + schedule.endTime && + schedule.jobMaxMinutes && + schedule.jobMinMinutes; + + // Customer + const customer = store.getters.order.customer; + const customerReqs = + customer.firstName && + customer.lastName && + customer.phoneNumber && + customer.emailAddress; + + return ( + vehicleReqs && + damageReqs && + packageReqs && + serviceLocationReqs && + scheduleReqs && + customerReqs + ); }, backButtonAction() { this.$router.navigateWithoutSaving(this.navigationScenarios.CLICKED_BACK, this.$route); From 076c48552e9c71bf0bc2f3aca1d713b92684d3ae Mon Sep 17 00:00:00 2001 From: Chloe Herd Date: Wed, 23 Aug 2023 14:14:52 -0400 Subject: [PATCH 57/60] Type Coerce --- src/layouts/review/review.vue | 34 ++++++++++++++++++++++------------ 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/src/layouts/review/review.vue b/src/layouts/review/review.vue index 61538c8f3..6b2d26cff 100644 --- a/src/layouts/review/review.vue +++ b/src/layouts/review/review.vue @@ -152,32 +152,40 @@ export default { arePagePrerequisitesValid() { // Vehicle const vehicle = store.getters.order.vehicle; - const vehicleReqs = vehicle.year && vehicle.make && vehicle.model && vehicle.style; + const vehicleReqs = !!(vehicle.year && vehicle.make && vehicle.model && vehicle.style); // Damage const damage = store.getters.order.damage; - const damageReqs = - (damage.isRepair && damage.numberOfChips) || damage.glassToReplace?.length; + const damageReqs = !!( + (damage.isRepair && damage.numberOfChips) || + damage.glassToReplace?.length + ); // Service Package const lineItems = store.getters.order.lineItems; // damageReqs handles checking for damage, even though it is also required for this section. - const packageReqs = (damage.isRepair || lineItems.glassParts) && lineItems.supportingItems && lineItems.vaps; + const packageReqs = !!( + (damage.isRepair || lineItems.glassParts) && + lineItems.supportingItems && + lineItems.vaps + ); // Service Location const serviceLocation = store.getters.order.serviceLocation; - const mobileReqs = + const mobileReqs = !!( serviceLocation.address && serviceLocation.city && serviceLocation.state && - serviceLocation.zipCode; + serviceLocation.zipCode + ); const providerLocation = serviceLocation.provider.address; - const dropOffInshopReqs = + const dropOffInshopReqs = !!( providerLocation.streetAddress && providerLocation.city && providerLocation.state && - providerLocation.zipCode; + providerLocation.zipCode + ); const isMobile = serviceLocation.appointmentType === AppointmentTypeStrings.MOBILE; @@ -186,20 +194,22 @@ export default { // Schedule const schedule = store.getters.order.schedule; - const scheduleReqs = + const scheduleReqs = !!( schedule.date && schedule.startTime && schedule.endTime && schedule.jobMaxMinutes && - schedule.jobMinMinutes; + schedule.jobMinMinutes + ); // Customer const customer = store.getters.order.customer; - const customerReqs = + const customerReqs = !!( customer.firstName && customer.lastName && customer.phoneNumber && - customer.emailAddress; + customer.emailAddress + ); return ( vehicleReqs && From 4d953cae649c68c3838393f8e35ca634a2032a79 Mon Sep 17 00:00:00 2001 From: Chloe Herd Date: Wed, 23 Aug 2023 14:35:01 -0400 Subject: [PATCH 58/60] Clarify damage requirements --- src/layouts/review/review.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/layouts/review/review.vue b/src/layouts/review/review.vue index 6b2d26cff..2fb033ea3 100644 --- a/src/layouts/review/review.vue +++ b/src/layouts/review/review.vue @@ -158,7 +158,7 @@ export default { const damage = store.getters.order.damage; const damageReqs = !!( (damage.isRepair && damage.numberOfChips) || - damage.glassToReplace?.length + (!damage.isRepair && damage.glassToReplace?.length) ); // Service Package From 06c095fcb1103369cbc6be3fc701bc06ca853ae7 Mon Sep 17 00:00:00 2001 From: Chloe Herd Date: Wed, 23 Aug 2023 14:54:28 -0400 Subject: [PATCH 59/60] Add tests --- src/layouts/review/review.spec.js | 361 +++++++++++++++++++++++++++++- 1 file changed, 360 insertions(+), 1 deletion(-) diff --git a/src/layouts/review/review.spec.js b/src/layouts/review/review.spec.js index 674dc71f7..bd1bfc5b6 100644 --- a/src/layouts/review/review.spec.js +++ b/src/layouts/review/review.spec.js @@ -1,3 +1,362 @@ +import { shallowMount } from "@vue/test-utils"; +import { getMountOptions } from "@/helpers/unit-test-helper.js"; +import store from "@/store"; + +import review from "@/layouts/review/review"; + +const testConstants = {}; + +jest.mock("@/store", () => ({ + commit: jest.fn(), + dispatch: jest.fn(), +})); + describe("Review Page", () => { - test.todo("Add more tests as specific functionality is added."); + beforeEach(() => { + store.getters = { + order: { + vehicle: { + year: "2020", + make: "Acura", + model: "MDX", + style: "4 door sedan", + }, + damage: { + isRepair: false, + numberOfChips: 2, + glassToReplace: ["dummy location value"], + }, + lineItems: { + glassParts: ["dummy part value"], + supportingItems: ["dummy supporting item"], + vaps: ["dummy vap"], + }, + serviceLocation: { + address: "address 1", + address2: "address 2", + city: "city", + state: "state", + zipCode: "zip code", + appointmentType: "Mobile", + provider: { + providerNumber: 1, + address: { + streetAddress: "provider address 1", + city: "provider city", + state: "provider state", + zipCode: "provider zip code", + }, + }, + }, + schedule: { + date: "date", + startTime: "start", + endTime: "end", + jobMinMinutes: "30", + jobMaxMinutes: "45", + }, + customer: { + firstName: "first name", + lastName: "last name", + emailAddress: "builddigitaltest@safelite.com", + phoneNumber: "555-555-5555", + isSmsOptIn: true, + }, + }, + }; + }); + describe("arePagePrerequisitesValid", () => { + test("Returns true for baseline valid state", () => { + // Arrange + const { wrapper } = setupMocks({}); + + // Act + const isValid = wrapper.vm.arePagePrerequisitesValid(); + + // Assert + expect(isValid).toBe(true); + }); + test("Returns false for empty state", () => { + // Arrange + store.getters.order = { + vehicle: { + year: null, + make: null, + model: null, + style: null, + carId: null, + category: null, + vin: null, + imageUrl: null, + imageVifNumber: null, + imageColor: null, + registration: { + licensePlate: null, + }, + }, + serviceLocation: { + address: null, + address2: null, + city: null, + state: null, + zipCode: null, + zipCodeCtu: null, + appointmentType: null, + isVehicleProtected: null, + provider: { + providerNumber: null, + address: { + streetAddress: null, + city: null, + state: null, + zipCode: null, + zipCodeCtu: null, + }, + }, + techNotes: null, + }, + customer: { + firstName: null, + lastName: null, + emailAddress: null, + phoneNumber: null, + isSmsOptIn: null, + }, + damage: { + isRepair: null, + numberOfChips: null, + glassToReplace: null, + partQuestionAnswers: null, + moldingQuestionAnswers: null, + capabilityQuestionAnswers: null, + }, + lineItems: { + glassParts: null, + supportingItems: null, + vaps: null, + serverData: null, + }, + payment: { + isInsurance: null, + insuranceCoverage: { + isVerified: null, + coverageStatus: null, + }, + parentAccountNumber: 0, + }, + schedule: { + date: null, + startTime: null, + endTime: null, + routeCode: null, + jobMaxMinutes: null, + jobMinMinutes: null, + }, + referralNumber: null, + referralSequenceNumber: null, + referralDate: null, + referralCorrelationId: null, + eon: null, + }; + + const { wrapper } = setupMocks({}); + + // Act + const isValid = wrapper.vm.arePagePrerequisitesValid(); + + // Assert + expect(isValid).toBe(false); + }); + describe("Damage requirements", () => { + test("Accepts null glassToReplace when is repair", () => { + // Arrange + store.getters.order.damage.isRepair = true; + store.getters.order.damage.glassToReplace = null; + store.getters.order.damage.numberOfChips = 1; + + const { wrapper } = setupMocks({}); + + // Act + const isValid = wrapper.vm.arePagePrerequisitesValid(); + + // Assert + expect(isValid).toBe(true); + }); + test("Rejects 0 chips when repair", () => { + // Arrange + store.getters.order.damage.isRepair = true; + store.getters.order.damage.numberOfChips = 0; + + const { wrapper } = setupMocks({}); + + // Act + const isValid = wrapper.vm.arePagePrerequisitesValid(); + + // Assert + expect(isValid).toBe(false); + }); + test("Rejects null chips when repair", () => { + // Arrange + store.getters.order.damage.isRepair = true; + store.getters.order.damage.numberOfChips = null; + + const { wrapper } = setupMocks({}); + + // Act + const isValid = wrapper.vm.arePagePrerequisitesValid(); + + // Assert + expect(isValid).toBe(false); + }); + test("Accepts null chips when not repair", () => { + // Arrange + store.getters.order.damage.isRepair = false; + store.getters.order.damage.numberOfChips = null; + + const { wrapper } = setupMocks({}); + + // Act + const isValid = wrapper.vm.arePagePrerequisitesValid(); + + // Assert + expect(isValid).toBe(true); + }); + test("Rejects empty glassToReplace when not repair", () => { + // Arrange + store.getters.order.damage.isRepair = false; + store.getters.order.damage.glassToReplace = null; + + const { wrapper } = setupMocks({}); + + // Act + const isValid = wrapper.vm.arePagePrerequisitesValid(); + + // Assert + expect(isValid).toBe(false); + }); + test("Rejects null glassToReplace when not repair", () => { + // Arrange + store.getters.order.damage.isRepair = false; + store.getters.order.damage.glassToReplace = []; + + const { wrapper } = setupMocks({}); + + // Act + const isValid = wrapper.vm.arePagePrerequisitesValid(); + + // Assert + expect(isValid).toBe(false); + }); + }); + describe("Package requirements", () => { + test("Accepts null glassParts when is repair", () => { + // Arrange + store.getters.order.damage.isRepair = true; + store.getters.order.lineItems.glassParts = null; + + const { wrapper } = setupMocks({}); + + // Act + const isValid = wrapper.vm.arePagePrerequisitesValid(); + + // Assert + expect(isValid).toBe(true); + }); + test("Rejects null glassParts when not repair", () => { + // Arrange + store.getters.order.damage.isRepair = false; + store.getters.order.lineItems.glassParts = null; + + const { wrapper } = setupMocks({}); + + // Act + const isValid = wrapper.vm.arePagePrerequisitesValid(); + + // Assert + expect(isValid).toBe(false); + }); + }); + describe("Service Location requirements", () => { + test("Accepts null provider address when mobile appointment", () => { + // Arrange + store.getters.order.serviceLocation.appointmentType = "Mobile"; + store.getters.order.serviceLocation.provider.address = {}; + + const { wrapper } = setupMocks({}); + + // Act + const isValid = wrapper.vm.arePagePrerequisitesValid(); + + // Assert + expect(isValid).toBe(true); + }); + test("Reject null provider address when non-mobile appointment", () => { + // Arrange + store.getters.order.serviceLocation.appointmentType = "Inshop"; + store.getters.order.serviceLocation.provider.address = {}; + + const { wrapper } = setupMocks({}); + + // Act + const isValid = wrapper.vm.arePagePrerequisitesValid(); + + // Assert + expect(isValid).toBe(false); + }); + test("Accepts null service location address when non-mobile appointment", () => { + // Arrange + store.getters.order.serviceLocation.appointmentType = "Inshop"; + store.getters.order.serviceLocation.address = null; + store.getters.order.serviceLocation.address2 = null; + store.getters.order.serviceLocation.zipCode = null; + store.getters.order.serviceLocation.city = null; + store.getters.order.serviceLocation.state = null; + + const { wrapper } = setupMocks({}); + + // Act + const isValid = wrapper.vm.arePagePrerequisitesValid(); + + // Assert + expect(isValid).toBe(true); + }); + test("Rejects null service location address when mobile appointment", () => { + // Arrange + store.getters.order.serviceLocation.appointmentType = "Mobile"; + store.getters.order.serviceLocation.address = null; + store.getters.order.serviceLocation.address2 = null; + store.getters.order.serviceLocation.zipCode = null; + store.getters.order.serviceLocation.city = null; + store.getters.order.serviceLocation.state = null; + + const { wrapper } = setupMocks({}); + + // Act + const isValid = wrapper.vm.arePagePrerequisitesValid(); + + // Assert + expect(isValid).toBe(false); + }); + }); + }); }); + +function setupMocks(customMountOptions) { + customMountOptions.store = store; + + const mountOptions = getMountOptions(customMountOptions); + + const mockMixin = { + methods: { + getCmsContent: jest.fn((widgetName, cmsFieldName) => { + return `${widgetName} ${cmsFieldName}`; + }), + }, + }; + + mountOptions.global.mixins = [mockMixin]; + + const wrapper = shallowMount(review, mountOptions); + wrapper.vm.setCmsContent = jest.fn(); + return { wrapper }; +} From 5d79f79c8834aa291dc094d699721367ad7b23d0 Mon Sep 17 00:00:00 2001 From: Chloe Herd Date: Wed, 23 Aug 2023 15:17:34 -0400 Subject: [PATCH 60/60] Formatting --- src/layouts/review/review.spec.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/layouts/review/review.spec.js b/src/layouts/review/review.spec.js index bd1bfc5b6..a4f82451d 100644 --- a/src/layouts/review/review.spec.js +++ b/src/layouts/review/review.spec.js @@ -235,17 +235,17 @@ describe("Review Page", () => { expect(isValid).toBe(false); }); test("Rejects null glassToReplace when not repair", () => { - // Arrange - store.getters.order.damage.isRepair = false; - store.getters.order.damage.glassToReplace = []; + // Arrange + store.getters.order.damage.isRepair = false; + store.getters.order.damage.glassToReplace = []; - const { wrapper } = setupMocks({}); + const { wrapper } = setupMocks({}); - // Act - const isValid = wrapper.vm.arePagePrerequisitesValid(); + // Act + const isValid = wrapper.vm.arePagePrerequisitesValid(); - // Assert - expect(isValid).toBe(false); + // Assert + expect(isValid).toBe(false); }); }); describe("Package requirements", () => {