diff --git a/src/digital-components/button-question/button-question.vue b/src/digital-components/button-question/button-question.vue
index 0ea02ce05..44a427275 100644
--- a/src/digital-components/button-question/button-question.vue
+++ b/src/digital-components/button-question/button-question.vue
@@ -5,7 +5,10 @@ https://safelite.atlassian.net/wiki/spaces/DC/pages/76644418/Button+Question+Com
:class="
isOverflowScrollable ? 'button-question button-question-overflow' : 'button-question'
">
-
+
{{ questionText }}
@@ -124,6 +127,7 @@ export default {
useTextForValue: Boolean,
valueToLogType: String,
additionalButtonStyling: String,
+ isSmallQuestionText: Boolean,
},
beforeMount() {
if (this.buttonTypeObject) {
@@ -137,13 +141,15 @@ export default {
},
computed: {
getFieldSetClasses() {
- if (this.isOverflowScrollable) {
- return "container-fluid overflow-scroll position-absolute px-5 pt-1 py-0";
- } else if (this.buttonTypeString == "listCard") {
- return "w-100";
- } else {
- return "";
- }
+ const baseClasses = this.isOverflowScrollable
+ ? "container-fluid overflow-scroll position-absolute px-5 pt-1 py-0"
+ : this.buttonTypeString == "listCard"
+ ? "w-100"
+ : "";
+ const withSmallQuestionClass = this.isSmallQuestionText
+ ? baseClasses + " small-question-text"
+ : baseClasses;
+ return withSmallQuestionClass;
},
getComponentLoopWrapperClasses() {
let classes;
@@ -210,7 +216,7 @@ export default {
},
methods: {
formatString(str) {
- return str?.replaceAll(" ", "-");
+ return String(str).replaceAll(" ", "-");
},
setLastValuePushedToGa(lastValuePushedToGa) {
this.lastValuePushedToGa = lastValuePushedToGa;
@@ -260,19 +266,18 @@ export default {
text-align: center;
}
}
-
-.vehicle-parts {
- .question-text {
+.small-question-text {
+ &.question-text {
span {
font-size: 0.875rem;
text-align: left;
- margin: 0 0 0.5rem 0;
+ margin: 1rem 0 0.5rem 0;
}
}
- .question-text {
+ &.question-text {
margin: 0;
}
- fieldset {
+ & fieldset {
.ui-radio {
margin: 0;
}
diff --git a/src/digital-components/modal/modal.spec.js b/src/digital-components/modal/modal.spec.js
index 5feaf0216..7ed8fff12 100644
--- a/src/digital-components/modal/modal.spec.js
+++ b/src/digital-components/modal/modal.spec.js
@@ -1,10 +1,13 @@
import { shallowMount } from "@vue/test-utils";
import Modal from "./modal";
+import crypto from "crypto";
const modalId = "modal-one";
const footerButtonText = "Sample footer text here.";
const headerText = "Sample header text here.";
+global.crypto = crypto;
+
describe("modal.vue", () => {
it("Should display footer button text when footerButtonText is defined", async () => {
const wrapper = shallowMount(Modal, {
diff --git a/src/fmg-components/content-group-modal/content-group-modal.spec.js b/src/fmg-components/content-group-modal/content-group-modal.spec.js
index a8058b2d5..cbdf6e182 100644
--- a/src/fmg-components/content-group-modal/content-group-modal.spec.js
+++ b/src/fmg-components/content-group-modal/content-group-modal.spec.js
@@ -1,5 +1,8 @@
import { mount } from "@vue/test-utils";
import contentGroupModal from "./content-group-modal";
+import crypto from "crypto";
+
+global.crypto = crypto;
describe("content-group-modal.vue", () => {
it("Should display header text when HeaderText is defined in the CMS", async () => {
diff --git a/src/helpers/heritage-integration/navigation-helper.js b/src/helpers/heritage-integration/navigation-helper.js
index 6fa248c63..0e756a8a4 100644
--- a/src/helpers/heritage-integration/navigation-helper.js
+++ b/src/helpers/heritage-integration/navigation-helper.js
@@ -28,7 +28,11 @@ export async function getPageToRouteExistingOrderTo(toRoute = {}, existingHerita
// If navigating to a specific page, and that page is not part of the vin pages.
// Return that page, so that it can navigate like normal.
- if (toRoute.query[queryStrings.FMG_PAGE] !== undefined && !isVinRelatedPage(toRoute)) {
+ if (
+ toRoute.query[queryStrings.FMG_PAGE] !== undefined &&
+ toRoute.query[queryStrings.FMG_PAGE] !== fmgPageValues.QUOTE &&
+ !isVinRelatedPage(toRoute)
+ ) {
return overrideYmmsDirectionIfNeeded(toRoute);
}
@@ -107,6 +111,7 @@ async function getLatestPageForRedirection() {
const capabilityQuestionsComponent = await getLazyLoadedComponent(
fmgPageValues.CAPABILITY_QUESTIONS
);
+ const quoteComponent = await getLazyLoadedComponent(fmgPageValues.QUOTE);
const skipVin = await skipVinLookup();
@@ -121,7 +126,9 @@ async function getLatestPageForRedirection() {
} else if (!estimateComponent.methods.arePagePrerequisitesValid()) {
return fmgPageValues.VEHICLE_DAMAGE;
} else {
- if (capabilityQuestionsComponent.methods.arePagePrerequisitesValid()) {
+ if (quoteComponent.methods.arePagePrerequisitesValid()) {
+ return fmgPageValues.QUOTE;
+ } else if (capabilityQuestionsComponent.methods.arePagePrerequisitesValid()) {
return fmgPageValues.CAPABILITY_QUESTIONS;
} else if (moldingQuestionsComponent.methods.arePagePrerequisitesValid()) {
return fmgPageValues.MOLDING_QUESTIONS;
diff --git a/src/helpers/heritage-integration/order-helper.js b/src/helpers/heritage-integration/order-helper.js
index 05b4c4dc4..7cf3cc12b 100644
--- a/src/helpers/heritage-integration/order-helper.js
+++ b/src/helpers/heritage-integration/order-helper.js
@@ -44,7 +44,7 @@ export async function loadSessionIfPresent(isConceptInsurance) {
funnelCookie.ReferralCorrelationId,
isConceptInsurance
)
- ).data;
+ )?.data;
}
/*
diff --git a/src/layouts/address-lookup/customer-questions/customer-questions.vue b/src/layouts/address-lookup/customer-questions/customer-questions.vue
index 5c8ee6b4e..cfc121731 100644
--- a/src/layouts/address-lookup/customer-questions/customer-questions.vue
+++ b/src/layouts/address-lookup/customer-questions/customer-questions.vue
@@ -56,7 +56,7 @@ defineRule("email-address-required", required(errorMessages.EMAIL_ADDRESS_REQUIR
defineRule(
"email-address-format",
regex(
- /^([a-zA-Z0-9_\-.+]+)@([a-zA-Z0-9_\-.]+)\.([a-zA-Z]{2,})$/,
+ /^([a-zA-Z0-9_\-.+]+)@([a-zA-Z0-9-]+)\.([a-zA-Z]{2,})$/,
errorMessages.EMAIL_ADDRESS_FORMAT
)
);
diff --git a/src/layouts/estimate/estimate.vue b/src/layouts/estimate/estimate.vue
index 0f8508921..36a52a2ff 100644
--- a/src/layouts/estimate/estimate.vue
+++ b/src/layouts/estimate/estimate.vue
@@ -120,7 +120,7 @@ defineRule("email-address-required", required(errorMessages.EMAIL_ADDRESS_REQUIR
defineRule(
"email-address-format",
regex(
- /^([a-zA-Z0-9_\-.+]+)@([a-zA-Z0-9_\-.]+)\.([a-zA-Z]{2,})$/,
+ /^([a-zA-Z0-9_\-.+]+)@([a-zA-Z0-9-]+)\.([a-zA-Z]{2,})$/,
errorMessages.EMAIL_ADDRESS_FORMAT
)
);
@@ -223,6 +223,25 @@ export default {
} else if (this.$store.getters.order.referralNumber?.length === 6) {
await this.navigateForwardWithSingleCarMatch();
} else if (this.isRepair) {
+ const supportingItemsPromise = await this.dispatchStoreAction(
+ storeActions.GET_SUPPORTING_ITEMS
+ );
+
+ const promiseResultMap = [
+ {
+ resultKey: "supportingItems",
+ promise: supportingItemsPromise,
+ },
+ ];
+
+ const resultMap = await settleAllPromises(promiseResultMap);
+
+ this.dispatchStoreAction(
+ this.storeActions.SAVE_SUPPORTING_ITEMS,
+ resultMap.supportingItems,
+ false
+ );
+
// call saveSession here - navigateWithSaving saves too late in the flow
await saveSession({});
return this.$router.navigateWithoutSaving(
diff --git a/src/layouts/license-plate-lookup/license-plate-lookup.vue b/src/layouts/license-plate-lookup/license-plate-lookup.vue
index 5b7c0b568..9f3b8c349 100644
--- a/src/layouts/license-plate-lookup/license-plate-lookup.vue
+++ b/src/layouts/license-plate-lookup/license-plate-lookup.vue
@@ -120,7 +120,7 @@ defineRule("email-address-required", required(errorMessages.EMAIL_ADDRESS_REQUIR
defineRule(
"email-address-format",
regex(
- /^([a-zA-Z0-9_\-.+]+)@([a-zA-Z0-9_\-.]+)\.([a-zA-Z]{2,})$/,
+ /^([a-zA-Z0-9_\-.+]+)@([a-zA-Z0-9-]+)\.([a-zA-Z]{2,})$/,
errorMessages.EMAIL_ADDRESS_FORMAT
)
);
diff --git a/src/layouts/quote/quote.spec.js b/src/layouts/quote/quote.spec.js
new file mode 100644
index 000000000..e5d4d54fb
--- /dev/null
+++ b/src/layouts/quote/quote.spec.js
@@ -0,0 +1,128 @@
+import { shallowMount, flushPromises } from "@vue/test-utils";
+import { getMountOptions } from "@/helpers/unit-test-helper.js";
+import { applicationConfig } from "@/constants/application-config";
+import quote from "@/layouts/quote/quote.vue";
+import store from "@/store";
+import * as navigateToHeritage from "@/helpers/heritage-integration/navigation-helper";
+
+jest.mock("@/store", () => ({
+ commit: jest.fn(),
+ dispatch: jest.fn(),
+}));
+
+// 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(),
+}));
+
+jest.mock("@/helpers/heritage-integration/navigation-helper", () => ({
+ navigateToHeritageFunnel: jest.fn(),
+}));
+
+jest.mock(
+ "@/store",
+ () => {
+ return {};
+ },
+ { virtual: true }
+);
+
+store.getters = {
+ order: {
+ accountNumber: applicationConfig.CASH_ACCOUNT_NUMBER,
+ },
+ payment: {
+ insuranceCoverage: {},
+ isInsurance: false,
+ },
+};
+
+afterEach(() => {
+ // reset store after each test
+ store.getters = {
+ order: {
+ accountNumber: applicationConfig.CASH_ACCOUNT_NUMBER,
+ },
+ payment: {
+ insuranceCoverage: {},
+ isInsurance: false,
+ },
+ };
+});
+
+describe("quote.vue", () => {
+ test("IsInsurance false should navigateWithSaving", async () => {
+ //Arrange
+ const { wrapper } = setupMocks({
+ customMountOptions: {
+ router: {
+ navigateWithSaving: jest.fn(),
+ },
+ route: { quote },
+ },
+ });
+
+ store.getters.payment = {
+ insuranceCoverage: {},
+ isInsurance: false,
+ };
+
+ wrapper.vm.dispatchStoreAction = jest.fn(() => {
+ return {
+ data: [],
+ };
+ });
+
+ //Act
+ await wrapper.vm.forwardButtonAction();
+
+ //Assert
+ expect(wrapper.vm.$router.navigateWithSaving).toHaveBeenCalled();
+ });
+
+ test("IsInsurance true should navigateToHeritageFunnel", async () => {
+ //Arrange
+ const { wrapper } = setupMocks({
+ customMountOptions: {
+ router: {
+ navigateWithSaving: jest.fn(),
+ },
+ route: { quote },
+ },
+ });
+
+ store.getters.payment = {
+ insuranceCoverage: {},
+ isInsurance: true,
+ };
+
+ wrapper.vm.dispatchStoreAction = jest.fn(() => {
+ return {
+ data: [],
+ };
+ });
+
+ //Act
+ await wrapper.vm.forwardButtonAction();
+
+ //Assert
+ expect(navigateToHeritage.navigateToHeritageFunnel).toHaveBeenCalled();
+ });
+});
+
+function setupMocks({ customMountOptions }) {
+ const mountOptions = getMountOptions({
+ ...customMountOptions,
+ });
+
+ mountOptions.global.mocks["$store"] = store;
+ mountOptions["attachTo"] = document.body;
+
+ const wrapper = shallowMount(quote, mountOptions);
+ return { wrapper };
+}
diff --git a/src/layouts/quote/quote.vue b/src/layouts/quote/quote.vue
index 517de9acb..85b773779 100644
--- a/src/layouts/quote/quote.vue
+++ b/src/layouts/quote/quote.vue
@@ -183,6 +183,7 @@ export default {
false
);
}
+
if (this.$store.getters.order.accountNumber != applicationConfig.CASH_ACCOUNT_NUMBER) {
this.supportingItems = this.filterOutFees(this.supportingItems);
}
@@ -193,7 +194,15 @@ export default {
);
this.dispatchStoreAction(this.storeActions.SAVE_VAPS, this.selectedVaps, false);
- navigateToHeritageFunnel({ loadingModal: this.$refs.loadingModal });
+ const payment = this.$store.getters.payment;
+ if (payment.isInsurance) {
+ navigateToHeritageFunnel({ loadingModal: this.$refs.loadingModal });
+ } else {
+ this.$router.navigateWithSaving(
+ this.navigationScenarios.CLICKED_FORWARD_WITH_CASH,
+ this.$route
+ );
+ }
},
},
components: {
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 e1b8ce716..790608c2e 100644
--- a/src/layouts/quote/service-package-question/service-package-question.vue
+++ b/src/layouts/quote/service-package-question/service-package-question.vue
@@ -43,7 +43,7 @@ export default {
},
watch: {
availableLineItems() {
- if (this.$store.getters.lineItems.supportingItems) {
+ if (this.$store.getters.lineItems.vaps) {
this.selectDefaultPackage();
}
},
@@ -213,18 +213,20 @@ export default {
selectDefaultPackage() {
const vapsFromStore = this.$store.getters.lineItems.vaps;
let lowestTierForPackage = packageNames.TIER_ONE;
- vapsFromStore.every((vapsItem) => {
- let lowestTierForThisItem = this.getLowestTierForThisItem(vapsItem);
- if (lowestTierForThisItem === packageNames.TIER_THREE) {
- lowestTierForPackage = packageNames.TIER_THREE;
- return false;
- } else if (lowestTierForThisItem === packageNames.TIER_TWO) {
- lowestTierForPackage = packageNames.TIER_TWO;
- return true;
- } else {
- return true;
- }
- });
+ if (vapsFromStore.length > 0) {
+ vapsFromStore.every((vapsItem) => {
+ let lowestTierForThisItem = this.getLowestTierForThisItem(vapsItem);
+ if (lowestTierForThisItem === packageNames.TIER_THREE) {
+ lowestTierForPackage = packageNames.TIER_THREE;
+ return false;
+ } else if (lowestTierForThisItem === packageNames.TIER_TWO) {
+ lowestTierForPackage = packageNames.TIER_TWO;
+ return true;
+ } else {
+ return true;
+ }
+ });
+ }
this.selectedPackageName = lowestTierForPackage;
},
getLowestTierForThisItem(vapsItem) {
diff --git a/src/layouts/reveal/reveal.vue b/src/layouts/reveal/reveal.vue
deleted file mode 100644
index b416b5318..000000000
--- a/src/layouts/reveal/reveal.vue
+++ /dev/null
@@ -1,66 +0,0 @@
-
-
-
-
Reveal Confetti Page Placeholder
-
-
-
-
-
diff --git a/src/layouts/service-location/service-location.vue b/src/layouts/service-location/service-location.vue
index 3d430c720..209a2f0fd 100644
--- a/src/layouts/service-location/service-location.vue
+++ b/src/layouts/service-location/service-location.vue
@@ -1,6 +1,7 @@