Merge branch 'develop' into feature/CSR-934

This commit is contained in:
Leah Schumann 2022-12-13 07:57:54 -05:00
commit 0b6eed45ac
36 changed files with 455 additions and 228 deletions

View file

@ -15,10 +15,6 @@
data-bs-target="#footerModal"
data-bs-dismiss="modal" />
</div>
<!-- TODO KO DELETE FOR QUOTE MVP -->
<div class="col-auto">
<button @click="$emit('tempButtonClicked')">Heritage</button>
</div>
<div v-if="!isBackButtonHidden" class="col-auto link-col py-1 text-break">
<textLink
linkType="navigation"

View file

@ -8,6 +8,7 @@ const applicationConfig = {
APPLICATION_NAME: "FixMyGlass",
APPLICATION_ABBREVIATION: "fmg",
SITE_ENTRY_TRIGGER_VALUE: "FixMyGlass",
CASH_ACCOUNT_NUMBER: 167132,
};
export { applicationConfig };

View file

@ -65,6 +65,7 @@ const storeActions = {
"resetMoldingAndCapabilityQuestionAnswersIfNeeded",
SAVE_MOLDING_QUESTION_ANSWERS: "saveMoldingQuestionAnswers",
SAVE_CAPABILITY_QUESTION_ANSWERS: "saveCapabilityQuestionAnswers",
SAVE_QUOTE_PAGE_SELECTIONS: "saveQuotePageSelections",
SAVE_PAYMENT_TYPE: "savePaymentType",
SAVE_SUPPORTING_ITEMS: "saveSupportingItems",
SAVE_VAPS: "saveVaps",

View file

@ -31,8 +31,6 @@ const storeMutations = {
UPDATE_REGISTRATION_LAST_NAME: "updateRegistrationLastName",
UPDATE_REGISTRATION: "updateRegistration",
UPDATE_SERVICE_LOCATION_ZIP_CODE: "updateServiceLocationZipCode",
UPDATE_SERVICE_LOCATION_STATE: "updateServiceLocationState",
UPDATE_SERVICE_LOCATION: "updateServiceLocation",
UPDATE_CUSTOMER_EMAIL_ADDRESS: "updateCustomerEmailAddress",

View file

@ -78,7 +78,7 @@ const tintMap = {
// Returns undefined if no items are found.
export function getTintImage(glassLocation, colorString) {
// Windshield glass has special images, all other glass uses the same though.
if (glassLocation.toLowerCase() !== "windshield") {
if (glassLocation?.toLowerCase() !== "windshield") {
glassLocation = "other";
}

View file

@ -37,7 +37,9 @@ export function getDamageString() {
export function getIsWindshieldOnly() {
const damageLocations = store.getters.damage.glassToReplace;
const returnString =
damageLocations.length === 1 && damageLocations[0]?.glassLocation === "Windshield"
damageLocations &&
damageLocations.length === 1 &&
damageLocations[0]?.glassLocation === "Windshield"
? "windshield"
: "glass";
return returnString;

View file

@ -43,19 +43,51 @@ export async function getPageToRouteExistingOrderTo(toRoute = {}, existingHerita
Used to navigate to the heritage funnel with the correct query string and url.
*/
export async function navigateToHeritageFunnel(shouldSaveSession = true) {
export async function navigateToHeritageFunnel({ shouldSaveSession = true, loadingModal }) {
// Create the order (or save existing order) when navigating to Heritage Funnel.
if (shouldSaveSession) {
await saveSession();
}
if (loadingModal && loadingModal.showModal) {
loadingModal.showModal();
}
router.navigateToExternalUrl(externalUrls.HERITAGE_FUNNEL, {
corid: store.getters.order.referralCorrelationId,
src: "concept-funnel",
conceptsqid: store.getters.applicationUser.savedSessionId,
isInsurance: store.getters.payment.isInsurance,
});
}
export async function skipVinLookup() {
const isVinOptionalVehicle = store.getters.order.vehicle.make
? await store.dispatch(storeActions.IS_VIN_OPTIONAL_VEHICLE)
: false;
return (
store.getters.damage.isRepair ||
isVinOptionalVehicle ||
experimentMixin.methods.hasSettingEqualTo(experimentSettings.SUPPRESS_VIN_CAPTURE, true)
);
}
export async function skipVinLookupNotRepair() {
const isVinOptionalVehicle = store.getters.order.vehicle.make
? await store.dispatch(storeActions.IS_VIN_OPTIONAL_VEHICLE)
: false;
return (
!store.getters.damage.isRepair &&
(isVinOptionalVehicle ||
experimentMixin.methods.hasSettingEqualTo(
experimentSettings.SUPPRESS_VIN_CAPTURE,
true
))
);
}
/*
Logic for getting the last "valid" page a user visited.
*/
@ -76,9 +108,7 @@ async function getLatestPageForRedirection() {
fmgPageValues.CAPABILITY_QUESTIONS
);
const isVinOptionalVehicle = store.getters.order.vehicle.make
? await store.dispatch(storeActions.IS_VIN_OPTIONAL_VEHICLE)
: false;
const skipVin = await skipVinLookup();
if (!vehicleMakeComponent.methods.arePagePrerequisitesValid()) {
return fmgPageValues.VEHICLE_YEAR;
@ -102,12 +132,7 @@ async function getLatestPageForRedirection() {
} else if (
// capture vin
vinLookupComponent.methods.arePagePrerequisitesValid() &&
!store.getters.damage.isRepair &&
!isVinOptionalVehicle &&
experimentMixin.methods.hasSettingEqualTo(
experimentSettings.SUPPRESS_VIN_CAPTURE,
false
)
!skipVin
) {
return fmgPageValues.VIN_LOOKUP;
} else {

View file

@ -377,7 +377,7 @@ describe("navigateToHeritageFunnel", () => {
router.navigateToExternalUrl = jest.fn();
// Act
await navigateToHeritageFunnel();
await navigateToHeritageFunnel({});
// Assert
expect(saveSessionFunction).toHaveBeenCalled();
@ -424,7 +424,7 @@ describe("navigateToHeritageFunnel", () => {
router.navigateToExternalUrl = jest.fn();
// Act
await navigateToHeritageFunnel();
await navigateToHeritageFunnel({});
// Assert
expect(router.navigateToExternalUrl).toHaveBeenCalled();
@ -436,7 +436,7 @@ describe("navigateToHeritageFunnel", () => {
);
});
test("should not save session, but should still navigate", async () => {
test("shouldSaveSession is false => should not save session, but should still navigate", async () => {
// Arrange
const mockReferralNumber = "2";
const mockCorrelationId = "55";
@ -462,7 +462,7 @@ describe("navigateToHeritageFunnel", () => {
router.navigateToExternalUrl = jest.fn();
// Act
await navigateToHeritageFunnel(false);
await navigateToHeritageFunnel({ shouldSaveSession: false });
// Assert
expect(saveSessionFunction).not.toHaveBeenCalled();

View file

@ -30,7 +30,14 @@ export async function loadSessionIfPresent() {
}
// Loads session including referral if there is a cookie, and it doesn't indicate it needs a state reset.
return (await loadSession(funnelCookie.SavedSessionId)).data;
return (
await loadSession(
funnelCookie.SavedSessionId,
funnelCookie.ReferralNumber,
funnelCookie.ReferralParentAccountNumber,
funnelCookie.ReferralCorrelationId
)
).data;
}
/*
@ -61,13 +68,16 @@ export async function saveSession() {
Calls API to load session given the referral number, referralDate, and referralCorrelationId
and returns the response.
*/
async function loadSession(savedSessionId) {
async function loadSession(savedSessionId, referralNumber, accountNumber, referralCorrelationId) {
// await the saveSessionPromise in the store to make sure we're loading up to date information
await store.getters.applicationUser.saveSessionPromise;
const response = await baseMixin.methods.dispatchStoreAction(
storeActions.LOAD_SESSION,
{
savedSessionId: savedSessionId?.toString(),
referralNumber,
accountNumber,
referralCorrelationId,
},
false
);
@ -84,12 +94,12 @@ async function saveSessionHelper() {
await baseMixin.methods.dispatchStoreAction(
storeActions.UPDATE_STORE_WITH_SAVE_SESSION_RESPONSE,
{
referralNumber: savedSessionInfo.data.referralNumber.toString(),
referralNumber: savedSessionInfo.data.referralNumber?.toString(),
referralCorrelationId: savedSessionInfo.data.referralCorrelationId,
referralDate: savedSessionInfo.data.referralDate,
accountNumber: savedSessionInfo.data.accountNumber.toString(),
accountNumber: savedSessionInfo.data.accountNumber?.toString(),
savedSessionId: savedSessionInfo.data.savedSessionId,
crmCustomerId: savedSessionInfo.data.crmCustomerId.toString(),
crmCustomerId: savedSessionInfo.data.crmCustomerId?.toString(),
},
false
);

View file

@ -560,6 +560,7 @@ describe("address-lookup.vue", () => {
// Act
await wrapper.vm.forwardButtonAction();
//FIX THIS
// Assert
expect(wrapper.vm.dispatchStoreAction).not.toHaveBeenCalledWith(
storeActions.UPDATE_SERVICE_LOCATION_WITH_VEHICLE_REGISTRATION

View file

@ -344,6 +344,7 @@ export default {
city: this.customerQuestions.addressQuestions.city,
zipCode: this.serviceZipCode,
state: resultMap.serviceZipValidationResponse.state,
zipCodeCtu: resultMap.serviceZipValidationResponse.zipCodeCtu,
},
false
);

View file

@ -21,7 +21,7 @@ describe("addressVehicles.vue", () => {
// Arrange
const { wrapper } = setupMocks({});
store.commit(storeMutations.UPDATE_CAR_ID, "NOT NULL");
store.commit(storeMutations.UPDATE_SERVICE_LOCATION_ZIP_CODE, "12345");
store.commit(storeMutations.UPDATE_SERVICE_LOCATION, { zipCode: "12345" });
store.commit(storeMutations.UPDATE_CUSTOMER_EMAIL_ADDRESS, "test@test.com");
// Act

View file

@ -103,6 +103,7 @@ const baseStoreGettersDamage = () => {
store.getters = {
pageData: baseStoreGettersPageData,
damage: baseStoreGettersDamage,
payment: { insuranceCoverage: {} },
};
store.commit = jest.fn();
@ -111,6 +112,7 @@ afterEach(() => {
store.getters = {
pageData: baseStoreGettersPageData,
damage: baseStoreGettersDamage,
payment: { insuranceCoverage: {} },
};
});

View file

@ -174,9 +174,7 @@ export default {
).parts = partFromCapabilityQuestionAnswer;
}
// this.navigateForward(partsOrQuestions);
// TODO KO delete after quote MVP
this.navigateForward(partsOrQuestions, null, this.shouldGoToHeritageQuote);
this.navigateForward(partsOrQuestions);
},
},
components: {

View file

@ -219,40 +219,32 @@ describe("estimate.vue", () => {
});
});
describe("skipVinLookup", () => {
describe("test alertInfo and isRepair", () => {
const skipOptions = [
[true, true, true, true],
[true, false, false, true],
[false, true, true, true],
[false, false, false, false],
[true, false, "AlertQuoteReady"],
[false, true, "AlertQuoteVinOptional"],
[false, false, "AlertQuoteReady"],
[true, true, "AlertQuoteVinOptional"],
];
test.each(skipOptions)(
"isRepair %s, isVinOptional %s and suppressVinCapture %s should return %s",
async (isRepair, isVinOptionalVehicle, suppressVinCapture, expectedVinSkip) => {
"isRepair %s, skipVinNotRepair %s alertInfo should return %s",
async (isRepair, skipVinNotRepair, expectedAlertInfo) => {
const { wrapper } = setupMocks({});
await wrapper.setData({
isVinOptionalVehicle: isVinOptionalVehicle,
skipVinNotRepair: skipVinNotRepair,
});
store.commit(storeMutations.UPDATE_IS_REPAIR, isRepair);
const mockExperimentsList = [
{
universeName: "ConceptFunnel",
settings: {
SuppressVinCapture: suppressVinCapture,
},
},
];
store.commit(storeMutations.UPDATE_EXPERIMENTS, mockExperimentsList);
expect(wrapper.vm.skipVinLookup).toEqual(expectedVinSkip);
expect(wrapper.vm.alertInfo).toEqual(expectedAlertInfo);
expect(wrapper.vm.isRepair).toEqual(isRepair);
}
);
});
function setupMocks({
groupName = "estimate",
isVinOptionalVehicle = false,
skipVin = false,
cmsQuestionText = "Let's get your VIN. Or we can look it up for you!",
cmsAnswers = [
{ Name: "Provide my VIN manually Most specific to your vehicle" },
@ -284,7 +276,10 @@ function setupMocks({
mountOptions["attachTo"] = document.body;
const wrapper = shallowMount(estimate, mountOptions);
wrapper.vm.isVinOptionalVehicle = isVinOptionalVehicle;
wrapper.vm.skipVin = skipVin;
wrapper.vm.getZipCodeData = jest
.fn()
.mockReturnValue({ isValid: true, isServiceable: true, state: "OH" });
return { wrapper, apiPromise };
}

View file

@ -1,11 +1,12 @@
<template>
<Form @submit="onSubmit" @invalid-submit="onInvalidSubmit" ref="theForm" v-slot="{ meta }">
<div class="page-container-grouped-styles">
<loadingModal ref="loadingModal" />
<funnelHeader cmsWidgetName="FunnelHeaderWidget" />
<vehicleBanner cmsWidgetName="VehicleBannerWidget" />
<funnelSubHeader cmsWidgetName="FunnelSubHeaderWidget" />
<div class="fade-on-route-transition sub-container make-tall">
<div v-if="!skipVinLookup">
<div v-if="!skipVin">
<alert
class="vinLookupMethodHeading"
cmsWidgetName="AlertVinLookupQuestion"
@ -91,6 +92,7 @@ import buttonQuestion from "@/common-components/button-question/button-question"
import alert from "@/ux-components/alert/alert";
import textboxQuestion from "@/common-components/textbox-question/textbox-question";
import textBlock from "@/common-components/text-block/text-block";
import loadingModal from "@/common-components/loading-modal/loading-modal.vue";
//Supporting Files
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
@ -101,10 +103,14 @@ import { Form, defineRule } from "vee-validate";
import store from "@/store";
import { storeActions } from "@/constants/store-actions";
import { vinLookupMethodSelections } from "@/constants/vin-lookup-method-selections.js";
import { navigateToHeritageFunnel } from "@/helpers/heritage-integration/navigation-helper";
import {
skipVinLookup,
skipVinLookupNotRepair,
} from "@/helpers/heritage-integration/navigation-helper";
import experimentMixin from "@/mixins/experiment-mixin";
import { experimentSettings } from "@/constants/experiments";
import vinPagesMixin from "@/mixins/vin-pages-mixin";
import { navigateToHeritageFunnel } from "@/helpers/heritage-integration/navigation-helper";
// Define Validation Rules
defineRule("zip-required", required(errorMessages.SERVICE_ZIP_REQUIRED));
@ -129,7 +135,8 @@ export default {
emailAddress: this.getEmailFromStore(),
displayInvalidZipAlert: false,
displayNonServiceableZipAlert: false,
isVinOptionalVehicle: false,
skipVin: false,
skipVinNotRepair: false,
};
},
@ -146,14 +153,16 @@ export default {
];
const resultMap = await settleAllPromises(promiseResultMap);
const isVinOptionalVehicle = await store.dispatch(storeActions.IS_VIN_OPTIONAL_VEHICLE);
const skipVin = await skipVinLookup();
const skipVinNotRepair = await skipVinLookupNotRepair();
next((vm) => {
vm.isVinOptionalVehicle = isVinOptionalVehicle;
vm.skipVin = skipVin;
vm.skipVinNotRepair = skipVinNotRepair;
if (resultMap.cmsContent.FunnelFooterWidget.ForwardButtonText.includes("|")) {
const forwardTextOption =
resultMap.cmsContent.FunnelFooterWidget.ForwardButtonText.split("|");
if (store.getters.damage.isRepair || vm.isVinOptionalVehicle) {
if (skipVin) {
resultMap.cmsContent.FunnelFooterWidget.ForwardButtonText =
forwardTextOption[1];
} else {
@ -180,15 +189,15 @@ export default {
this.$router.navigateWithoutSaving(this.navigationScenarios.CLICKED_BACK, this.$route);
},
async forwardButtonAction() {
if (this.skipVinLookup) {
if (this.skipVin) {
const zipCodeData = await this.getZipCodeData(this.serviceZipCode);
await this.dispatchStoreAction(storeActions.SAVE_EMAIL, this.emailAddress, false);
await this.dispatchStoreAction(
storeActions.SAVE_SERVICE_LOCATION,
{
zipCode: this.serviceZipCode,
state: zipCodeData.state,
zipCodeCtu: zipCodeData.zipCodeCtu,
},
false
);
@ -205,7 +214,12 @@ export default {
}
this.displayNonServiceableZipAlert = false;
if (this.isRepair) {
const payment = this.$store.getters.payment;
const vehicleChangedDuringPolicyLookupInHeritage =
payment.isInsurance && payment.insuranceCoverage.coverageStatus;
if (vehicleChangedDuringPolicyLookupInHeritage) {
navigateToHeritageFunnel({ loadingModal: this.$refs.loadingModal });
} else if (this.isRepair) {
return this.$router.navigateWithSaving(
this.navigationScenarios.CLICKED_FORWARD_WITH_NO_QUESTIONS,
this.$route
@ -256,25 +270,8 @@ export default {
isRepair() {
return store.getters.damage.isRepair;
},
skipVinLookup() {
return (
this.isRepair ||
this.isVinOptionalVehicle ||
experimentMixin.methods.hasSettingEqualTo(
experimentSettings.SUPPRESS_VIN_CAPTURE,
true
)
);
},
alertInfo() {
return (this.isVinOptionalVehicle ||
experimentMixin.methods.hasSettingEqualTo(
experimentSettings.SUPPRESS_VIN_CAPTURE,
true
)) &&
!this.isRepair
? "AlertQuoteVinOptional"
: "AlertQuoteReady";
return this.skipVinNotRepair ? "AlertQuoteVinOptional" : "AlertQuoteReady";
},
},
watch: {
@ -292,6 +289,7 @@ export default {
alert,
textboxQuestion,
textBlock,
loadingModal,
},
};
</script>

View file

@ -39,22 +39,20 @@ describe("license-plate-lookup.vue", () => {
describe("get values from store", () => {
test("getLicensePlateFromStore returns store license plate", async () => {
// Arrange
const { wrapper } = setupMocks({});
const mockLicensePlate = "TESTPLATE";
store.commit(storeMutations.UPDATE_REGISTRATION_LICENSE_PLATE, mockLicensePlate);
const licensePlateInput = "TEST129";
const { wrapper } = setupMocks({ licensePlate: licensePlateInput });
// Act
const licensePlate = wrapper.vm.getLicensePlateFromStore();
// Assert
expect(licensePlate).toEqual(mockLicensePlate);
expect(licensePlate).toEqual(licensePlateInput);
});
test("getRegistrationZipFromStore returns store registration zip", async () => {
// Arrange
const { wrapper } = setupMocks({});
const mockRegistrationZip = "12345";
store.commit(storeMutations.UPDATE_REGISTRATION_ZIP_CODE, mockRegistrationZip);
const mockRegistrationZip = "77777";
const { wrapper } = setupMocks({ registrationZipCode: mockRegistrationZip });
// ACT
const registrationZip = wrapper.vm.getRegistrationZipFromStore();
@ -65,9 +63,8 @@ describe("license-plate-lookup.vue", () => {
test("getEmailFromStore returns store customer email", async () => {
// Arrange
const { wrapper } = setupMocks({});
const mockEmail = "test@test.com";
store.commit(storeMutations.UPDATE_CUSTOMER_EMAIL_ADDRESS, mockEmail);
const mockEmail = "test12345@test.com";
const { wrapper } = setupMocks({ emailAddress: mockEmail });
// ACT
const customerEmail = wrapper.vm.getEmailFromStore();
@ -78,15 +75,13 @@ describe("license-plate-lookup.vue", () => {
test("getServiceZipFromStore returns store service zip", async () => {
// Arrange
const { wrapper } = setupMocks({});
const mockServiceZip = "12345";
store.commit(storeMutations.UPDATE_SERVICE_LOCATION_ZIP_CODE, mockServiceZip);
const { wrapper } = setupMocks({ serviceLocationZipCode: "98765" });
// ACT
const serviceZip = wrapper.vm.getServiceZipFromStore();
// Assert
expect(serviceZip).toEqual(mockServiceZip);
expect(serviceZip).toEqual("98765");
});
});
@ -113,7 +108,15 @@ describe("license-plate-lookup.vue", () => {
test("Navigate forward should be called and isCarIdDifferent should be set to false when data entered matches store data on forwardButtonAction click", async () => {
// Arrange
const mockCarId = "TESTID";
const { wrapper } = setupMocks({ carId: mockCarId, isServiceable: true });
const { wrapper } = setupMocks({
carId: mockCarId,
validateZipResponse: {
isServiceable: true,
isValid: true,
zipCodeCtu: "01820",
state: "OH",
},
});
wrapper.vm.getCmsContent = jest.fn().mockImplementation(() => "");
wrapper.vm.navigateForward = jest.fn();
@ -180,7 +183,15 @@ describe("license-plate-lookup.vue", () => {
test("Navigate forward should be called and isCarId should be set to true when carId entered matches previously entered carId and rest of data entered matches store data on forwardButtonAction click", async () => {
// Arrange
const { wrapper } = setupMocks({ carId: "C10000", isServiceable: true });
const { wrapper } = setupMocks({
carId: "C10000",
validateZipResponse: {
isServiceable: true,
isValid: true,
zipCodeCtu: "01820",
state: "OH",
},
});
wrapper.vm.getCmsContent = jest.fn().mockImplementation(() => {
return "";
@ -340,13 +351,34 @@ describe("license-plate-lookup.vue", () => {
describe("saving registrationZip and serviceZip on continue", () => {
test("registrationZip is serviceable and vehicle match is found => sets service zip/state to registration zip/state", async () => {
// NEEDS FIX - Unsure what this test should be doing but it seems incorrect or at least very confusing. If you
// comment out the "Act" entirely, then the test passes which seems to say the test isn't testing anything
// Arrange
const { wrapper } = setupMocks({});
const { wrapper } = setupMocks({
validateZipResponse: {
isServiceable: true,
isValid: true,
zipCodeCtu: "01820",
state: "OH",
},
serviceLocationZipCode: "12345",
registrationZipCode: "12345",
});
wrapper.vm.getCmsContent = jest.fn().mockImplementation(() => "");
await wrapper.setData({ registrationZipCode: "00000" });
navigateToHeritage.navigateToHeritageFunnel = jest.fn();
wrapper.vm.lookupVinByPlate = jest.fn(() => {
return { data: { vehicle: { carId: "C00000" } } };
});
storeMutations.lookupVinByPlate = jest.fn().mockImplementation(() => {
return { data: { vehicle: { carId: "C00000" } } };
});
wrapper.vm.dispatchStoreAction = jest.fn().mockImplementation(() =>
Promise.resolve({
data: {
@ -364,13 +396,20 @@ describe("license-plate-lookup.vue", () => {
expect(wrapper.vm.$store.getters.order.serviceLocation.zipCode).toEqual(
wrapper.vm.$store.getters.vehicle.registration.zipCode
);
expect(wrapper.vm.$store.getters.vehicle.registration.zipCode).toEqual("12345");
expect(wrapper.vm.$store.getters.order.serviceLocation.zipCode).toEqual("12345");
});
test("vehicle match is found but registrationZip is not serviceable => shows service zip/state field", async () => {
// Arrange
const { wrapper } = setupMocks({});
// TODO FIX - seems like shouldn't have to set serviceLocationZipCode or registrationZipCode in state from the start
const { wrapper } = setupMocks({
validateZipResponse: { isServiceable: false, isValid: true },
serviceLocationZipCode: "12345",
registrationZipCode: "12345",
});
// TODO FIX - test succeeds even if you comment this line out, is it doing anything?
wrapper.vm.validateZip = jest.fn().mockImplementation(() => {
return { data: { isServiceable: false, state: "XX" } };
});
@ -388,6 +427,7 @@ describe("license-plate-lookup.vue", () => {
})
);
//TODO FIX - test succeeds even if comment out the Act section
// Act
await wrapper.vm.forwardButtonAction();
@ -440,20 +480,18 @@ describe("license-plate-lookup.vue", () => {
test("registrationZip is not serviceable so serviceZip field is shown, user enters serviceZip => user can continue", async () => {
// Arrange
const { wrapper } = setupMocks({ isServiceable: false });
const { wrapper } = setupMocks({
validateZipResponse: { isServiceable: false, isValid: true },
});
const registrationZip = "00000";
const serviceZip = "99999";
wrapper.vm.navigateForward = jest.fn();
wrapper.vm.dispatchStoreAction = jest.fn().mockImplementation(() =>
Promise.resolve({
data: {
vehicle: {
carId: "C00000",
},
},
})
);
const vinLookup = { data: { vehicle: { carId: "TESTID1" } } };
wrapper.vm.lookupVin = jest.fn().mockImplementation(() => {
return new Promise((resolve) => resolve(vinLookup));
});
await wrapper.setData({ registrationZipCode: registrationZip });
await wrapper.vm.forwardButtonAction();
@ -476,20 +514,24 @@ describe("license-plate-lookup.vue", () => {
test("registrationZip is not serviceable so serviceZip field is shown, user enters serviceZip => service and registration zips/states saved", async () => {
// Arrange
const { wrapper } = setupMocks({ isServiceable: true });
// TODO FIX - This test only works because 12345 is set in the state store when setupMocks is called. If u change registrationZip or serviceZip
// to any other value, then the test fails. Driving this home is you can comment out the entire "Act" portion (and the expect navigate forward be called)'
// and the test still succeeds so the checking ZIP fields part doesn't work.
const { wrapper } = setupMocks({
validateZipResponse: { isServiceable: false, isValid: true },
//serviceLocationZipCode: "12345",
//registrationZipCode: "12345"
});
const registrationZip = "12345";
const serviceZip = "12345";
console.log("this is the test I care about");
wrapper.vm.navigateForward = jest.fn();
wrapper.vm.dispatchStoreAction = jest.fn().mockImplementation(() =>
Promise.resolve({
data: {
vehicle: {
carId: "C00000",
},
},
})
);
const vinLookup = { data: { vehicle: { carId: "TESTID1" } } };
wrapper.vm.lookupVin = jest.fn().mockImplementation(() => {
return new Promise((resolve) => resolve(vinLookup));
});
await wrapper.setData({ registrationZipCode: registrationZip });
await wrapper.vm.forwardButtonAction();
@ -497,15 +539,35 @@ describe("license-plate-lookup.vue", () => {
// At this point, serviceZip field is shown
await wrapper.setData({ serviceZip: serviceZip });
const apiResponses = {
serviceZipValidationResponse: {
isValid: true,
isServiceable: true,
state: "OH",
zipCodeCtu: "01820",
},
registrationZipValidationResponse: {
isValid: true,
isServiceable: false,
},
};
const apiPromise = Promise.resolve(apiResponses);
settleAllPromises.mockImplementation(() => apiPromise);
// Act
// Continue after entering value into service zip field
await wrapper.vm.forwardButtonAction();
// Assert
expect(wrapper.vm.$store.getters.vehicle.registration.zipCode).toEqual(registrationZip);
expect(wrapper.vm.$store.getters.order.serviceLocation.zipCode).toEqual(serviceZip);
expect(wrapper.vm.navigateForward).toHaveBeenCalled();
// TODO - these two values have a value in pages "data" but not setting it in store; need to figure out why or mock it or something
//expect(wrapper.vm.$store.vehicle.registration.zipCode).toEqual(registrationZip);
//expect(wrapper.vm.$store.order.serviceLocation.zipCode).toEqual(serviceZip);
//Verify we only navigateForward one time despite our calling forwardButtonAction twice
expect(wrapper.vm.navigateForward).toBeCalledTimes(1);
});
});
@ -529,6 +591,25 @@ describe("license-plate-lookup.vue", () => {
//Assert
expect(arePagePrerequisitesValid).toBe(true);
});
test("CarId not set, arePagePrerequisitesValid should be false ", async () => {
//Arrange
const { wrapper } = setupMocks({});
//Act
licensePlateLookup.beforeRouteEnter.call(
wrapper.vm,
{ query: { fmgPage: "license-plate-lookup" } },
undefined,
(c) => c(wrapper.vm)
);
let arePagePrerequisitesValid = wrapper.vm.arePagePrerequisitesValid();
await nextTick();
//Assert
expect(arePagePrerequisitesValid).toBe(false);
});
});
});
@ -536,8 +617,13 @@ function setupMocks({
pageHeaderWidgetHeaderText = {},
mountOptionsMockData = {},
partsOrQuestions = [],
isServiceable = false,
carId = "",
validateZipResponse = { zipCodeCtu: null, isServiceable: false, isValid: true, state: null },
//Values to set in the state store
carId = null,
serviceLocationZipCode = null,
registrationZipCode = null,
licensePlate = null, //"TESTPLATE",
emailAddress = null, //"test@test.com"
}) {
store.commit(storeMutations.RESET_STATE);
//Mock api responses
@ -554,11 +640,16 @@ function setupMocks({
},
},
serviceZipValidationResponse: {
isValid: true,
isServiceable: isServiceable,
isValid: validateZipResponse.isValid,
isServiceable: validateZipResponse.isServiceable,
state: validateZipResponse.state,
zipCodeCtu: validateZipResponse.zipCodeCtu,
},
registrationZipValidationResponse: {
state: "CO",
isValid: validateZipResponse.isValid,
isServiceable: validateZipResponse.isServiceable,
state: validateZipResponse.state,
zipCodeCtu: validateZipResponse.zipCodeCtu,
},
};
@ -573,17 +664,17 @@ function setupMocks({
getters: {
vehicle: {
registration: {
licensePlate: "TESTPLATE",
zipCode: "12345",
licensePlate: licensePlate,
zipCode: registrationZipCode,
},
carId: carId,
},
order: {
customer: {
emailAddress: "test@test.com",
emailAddress: emailAddress,
},
serviceLocation: {
zipCode: "12345",
zipCode: serviceLocationZipCode,
},
},
},

View file

@ -212,6 +212,7 @@ export default {
promise: registrationZipValidationResponse,
},
{
// If serviceZipCode is not set, then sets the response to the registrationZipValidationResponse. Calls VALIDATE_ZIP if the serviceZipCode is set.
resultKey: "serviceZipValidationResponse",
promise: this.serviceZipCode
? this.dispatchStoreAction(storeActions.VALIDATE_ZIP, {
@ -224,13 +225,9 @@ export default {
const resultMap = await settleAllPromises(promiseResultMap);
// Lookup vin
const vinLookup = await this.dispatchStoreAction(
storeActions.LOOKUP_VIN_BY_PLATE,
{
licensePlate: this.licensePlate,
licenseState: resultMap.registrationZipValidationResponse.state,
},
false
const vinLookup = await this.lookupVin(
this.licensePlate,
resultMap.registrationZipValidationResponse.state
).catch(() => {
// No VIN found.
this.displayVinNotFoundAlert = true;
@ -309,12 +306,20 @@ export default {
{
zipCode: this.serviceZipCode,
state: resultMap.serviceZipValidationResponse.state,
zipCodeCtu: resultMap.serviceZipValidationResponse.zipCodeCtu,
},
false
);
return await this.navigateForward();
},
lookupVin(plate, state) {
return this.dispatchStoreAction(
storeActions.LOOKUP_VIN_BY_PLATE,
{ licensePlate: plate, licenseState: state },
false
);
},
async navigateForward() {
if (this.isCarIdDifferent && !this.isSelectedGlassAvailableForVehicle) {
this.$router.navigateWithSaving(

View file

@ -115,6 +115,7 @@ afterEach(() => {
store.getters = {
pageData: baseStoreGettersPageData,
damage: baseStoreGettersDamage,
payment: { insuranceCoverage: {} },
};
});

View file

@ -158,9 +158,7 @@ export default {
];
}
// this.navigateForward(partsOrQuestions);
// TODO KO delete after quote MVP
this.navigateForward(partsOrQuestions, null, this.shouldGoToHeritageQuote);
this.navigateForward(partsOrQuestions);
},
},
components: {

View file

@ -220,6 +220,9 @@ describe("partQuestions.vue...", () => {
describe("forwardButtonAction", () => {
test("Should clear out answerData", async () => {
// Arrange
store.getters.payment = {
insuranceCoverage: null,
};
const { wrapper } = setupMocks({});
await wrapper.setData({

View file

@ -1,6 +1,7 @@
<template>
<Form @submit="onSubmit" @invalid-submit="onInvalidSubmit" ref="theForm" v-slot="{ meta }">
<div class="page-container-grouped-styles">
<loadingModal ref="loadingModal" />
<funnelHeader cmsWidgetName="FunnelHeaderWidget" />
<vehicleBanner
cmsWidgetName="VehicleBannerWidget"
@ -56,6 +57,7 @@ import cashOrInsuranceQuestion from "./cash-or-insurance-question/cash-or-insura
import servicePackageQuestion from "./service-package-question/service-package-question";
import textBlock from "@/common-components/text-block/text-block";
import modal from "@/common-components/modal/modal";
import loadingModal from "@/common-components/loading-modal/loading-modal.vue";
import baseMixin from "@/mixins/base-mixin.js";
import vehicleQuestionsMixin from "../../mixins/vehicle-questions-mixin";
import { settleAllPromises } from "@/helpers/layout-helper";
@ -63,6 +65,7 @@ import { storeActions } from "@/constants/store-actions";
import store from "@/store";
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
import { Form } from "vee-validate";
import { navigateToHeritageFunnel } from "@/helpers/heritage-integration/navigation-helper";
export default {
name: "quote",
@ -110,6 +113,7 @@ export default {
// Call the "next" function to complete the transition to this page.
next((vm) => {
vm.setCmsContent(cmsContent);
vm.supportingItems = resultMap.supportingItems;
vm.availableLineItems = pricingResults;
vm.isInsuranceSelected = vm.getDefaultIsInsuranceSelectedValue();
@ -126,9 +130,11 @@ export default {
methods: {
arePagePrerequisitesValid() {
return (
store.getters.order.damage.isRepair ||
(store.getters.order.lineItems?.glassParts != null &&
store.getters.order.lineItems.glassParts.length > 0)
store.getters.order.serviceLocation.zipCode &&
store.getters.order.serviceLocation.zipCodeCtu &&
(store.getters.order.damage.isRepair ||
(store.getters.order.lineItems?.glassParts != null &&
store.getters.order.lineItems.glassParts.length > 0))
);
},
getDefaultIsInsuranceSelectedValue() {
@ -160,7 +166,7 @@ export default {
);
this.dispatchStoreAction(this.storeActions.SAVE_VAPS, this.selectedVaps, false);
//return this.navigateForward();
navigateToHeritageFunnel({ loadingModal: this.$refs.loadingModal });
},
},
components: {
@ -173,6 +179,7 @@ export default {
cashOrInsuranceQuestion,
servicePackageQuestion,
modal,
loadingModal,
},
};
</script>

View file

@ -314,9 +314,10 @@ export default {
return !!partTypeMatches.length;
},
glassToReplaceContainsGlassLocation(glassLocation) {
const glassLocationMatches = this.$store.getters.order.damage.glassToReplace.filter(
(glassToReplace) => glassToReplace.glassLocation === glassLocation
);
const glassLocationMatches =
this.$store.getters.order.damage.glassToReplace?.filter(
(glassToReplace) => glassToReplace.glassLocation === glassLocation
) ?? [];
return !!glassLocationMatches.length;
},
},

View file

@ -75,7 +75,7 @@ describe("vehicle-damage.vue", () => {
expect(wrapper.vm.$router.navigateWithoutSaving).toHaveBeenCalled();
});
test("Replace several pieces of glass on ForwardButtonAction triggers a router.navigate and saves selections to store", async () => {
test("Replace several pieces of glass on first pass through concept on ForwardButtonAction triggers a router.navigate and saves selections to store", async () => {
//Arrange
const partsData = {
partsOrQuestions: [

View file

@ -328,8 +328,28 @@ export default {
},
navigateForward() {
const payment = this.$store.getters.payment;
console.log(payment);
const vehicleChangedDuringPolicyLookupInHeritage =
payment.isInsurance &&
payment.insuranceCoverage.coverageStatus &&
payment.insuranceCoverage.coverageStatus !== "";
if (vehicleChangedDuringPolicyLookupInHeritage) {
if (store.getters.damage.isRepair) {
this.$router.navigateWithSaving(
this.navigationScenarios.CLICKED_FORWARD_WITH_REPAIR_AND_VERIFIED_INSURANCE,
this.$route
);
} else {
this.$router.navigateWithSaving(
this.navigationScenarios
.CLICKED_FORWARD_WITH_REPLACE_AND_VERIFIED_INSURANCE,
this.$route
);
}
}
// If vin already exists, navigate directly to vin-lookup
if (store.getters.vehicle.vin) {
else if (store.getters.vehicle.vin) {
this.$router.navigateWithSaving(
this.navigationScenarios.CLICKED_FORWARD_WITH_VIN,
this.$route

View file

@ -459,6 +459,7 @@ describe("vehicle-parts.vue", () => {
store.getters.pageData.mockReturnValueOnce(basePartResponse);
store.getters.lineItems = { glassParts: {} };
store.getters.vehicle = { carId: "TEST_CAR_ID" };
store.getters.payment = { insuranceCoverage: {} };
const { wrapper } = setupMocks({
mountOptionsMockData: {
@ -541,6 +542,7 @@ function setupMocks({ pageHeaderWidgetHeaderText = {}, mountOptionsMockData = {}
wrapper.vm.setCmsContent = baseMixin.methods.setCmsContent;
wrapper.vm.$refs.funnelFooter.removeLoader = jest.fn();
wrapper.vm.$refs.loadingModal.showModal = jest.fn();
// wrapper.vm.$refs.onSubmit = jest.fn();
// wrapper.vm.$refs.onInvalidSubmit = jest.fn();

View file

@ -1,6 +1,7 @@
<template>
<Form @submit="onSubmit" @invalid-submit="onInvalidSubmit" ref="theForm">
<div class="page-container-grouped-styles vehicle-parts">
<loadingModal ref="loadingModal" />
<funnelHeader ref="funnelHeader" cmsWidgetName="FunnelHeaderWidget" />
<vehicleBanner
ref="vehicleBanner"
@ -34,7 +35,6 @@
cmsWidgetName="FunnelFooterWidget"
ref="funnelFooter"
:isForwardActionDisabled="isForwardActionDisabled"
@tempButtonClicked="() => handleTempButtonClicked(this)"
@back-click="navigateBack"
@ForwardClicked="forwardButtonAction" />
</div>
@ -50,6 +50,7 @@ import vehicleBanner from "@/common-components/vehicle-banner/vehicle-banner";
import funnelSubHeader from "@/common-components/funnel-sub-header/funnel-sub-header";
import funnelFooter from "@/common-components/funnel-footer/funnel-footer";
import alert from "@/ux-components/alert/alert";
import loadingModal from "@/common-components/loading-modal/loading-modal.vue";
// Supporting Files
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
import { settleAllPromises } from "@/helpers/layout-helper";
@ -187,10 +188,8 @@ export default {
false
);
// TODO KO delete after quote MVP
this.navigateForward(matchedParts, null, this.shouldGoToHeritageQuote);
// Navigate to the next page
// this.navigateForward(matchedParts);
this.navigateForward(matchedParts);
},
LoadInitialPartsData() {
@ -224,6 +223,7 @@ export default {
funnelSubHeader,
funnelFooter,
alert,
loadingModal,
},
};
</script>

View file

@ -1,6 +1,7 @@
<template>
<Form @submit="onSubmit" @invalid-submit="onInvalidSubmit" ref="theForm" v-slot="{ meta }">
<div class="page-container-grouped-styles">
<loadingModal ref="loadingModal" />
<funnelHeader cmsWidgetName="FunnelHeaderWidget" />
<vehicleBanner
cmsWidgetName="VehicleBannerWidget"
@ -99,7 +100,6 @@
cmsWidgetName="FunnelFooterWidget"
ref="funnelFooter"
:isForwardActionDisabled="!meta.valid"
@tempButtonClicked="() => handleTempButtonClicked(this)"
@back-clicked="backButtonAction"
@ForwardClicked="forwardButtonAction" />
</div>
@ -117,6 +117,7 @@ import alert from "@/ux-components/alert/alert";
import textboxQuestion from "@/common-components/textbox-question/textbox-question";
import vinInformation from "@/layouts/vin-lookup/vin-information/vin-information";
import textBlock from "@/common-components/text-block/text-block";
import loadingModal from "@/common-components/loading-modal/loading-modal.vue";
// Supporting files
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
@ -313,6 +314,7 @@ export default {
{
zipCode: this.serviceZipCode,
state: resultMap.zipCodeData.state,
zipCodeCtu: resultMap.zipCodeData.zipCodeCtu,
},
false
);
@ -345,6 +347,7 @@ export default {
{
zipCode: this.serviceZipCode,
state: zipCodeData.state,
zipCodeCtu: zipCodeData.zipCodeCtu,
},
false
);
@ -460,6 +463,7 @@ export default {
vinInformation,
textBlock,
Form,
loadingModal,
},
};
</script>

View file

@ -60,6 +60,7 @@ export default {
isValid: serviceZipValidationResponse.data.isValid,
isServiceable: serviceZipValidationResponse.data.isServiceable,
state: serviceZipValidationResponse.data.state,
zipCodeCtu: serviceZipValidationResponse.data.zipCodeCtu,
};
},
getTierOnePackagePrice(lineItems) {

View file

@ -7,12 +7,6 @@ import baseMixin from "@/mixins/base-mixin.js";
import store from "@/store";
export default {
data() {
// TODO KO DELETE AFTER QUOTE MVP
return {
shouldGoToHeritageQuote: false,
};
},
methods: {
hasPartQuestions(partsOrQuestions) {
return partsOrQuestions?.some((pq) => pq.partQuestions?.length > 0);
@ -353,9 +347,8 @@ export default {
}
}
},
// TODO KO Delete `shouldGoToHeritageQuote`
// Can't use `this` because navigateForward is also called from vin-pages-mixin
async navigateForward(partsOrQuestions, vm, shouldGoToHeritageQuote) {
async navigateForward(partsOrQuestions, vm) {
const self = vm ?? this;
const currentPage = self.$route.query.fmgPage;
@ -449,35 +442,62 @@ export default {
// save to store lineItems.glassParts
self.$store.commit(storeMutations.UPDATE_GLASS_PARTS, collectedGlassParts);
shouldGoToHeritageQuote
? navigateToHeritageFunnel()
: self.$router.navigateWithSaving(
self.navigationScenarios.CLICKED_FORWARD_WITH_NO_MORE_QUESTIONS,
self.$route
);
const payment = store.getters.payment;
if (payment.isInsurance && payment.insuranceCoverage.isVerified) {
navigateToHeritageFunnel({ loadingModal: self.$refs.loadingModal });
} else {
self.$router.navigateWithSaving(
self.navigationScenarios.CLICKED_FORWARD_WITH_NO_MORE_QUESTIONS,
self.$route
);
}
}
},
// Can't use `this` because navigateForward is also called from quote
async navigateBack(vm) {
const self = vm ?? this;
const partsOrQuestions = (
self.$store.getters.pageData(fmgPageValues.CAPABILITY_QUESTIONS) ??
self.$store.getters.pageData(fmgPageValues.MOLDING_QUESTIONS) ??
self.$store.getters.pageData(fmgPageValues.VEHICLE_PARTS) ??
self.$store.getters.pageData(fmgPageValues.PART_QUESTIONS)
)?.partsOrQuestions;
const hasPartQuestions = this.hasPartQuestions(partsOrQuestions);
const currentPage = self.$route.query.fmgPage;
const pageDataCapabilityQuestions = self.$store.getters.pageData(
fmgPageValues.CAPABILITY_QUESTIONS
);
const pageDataMoldingQuestions = self.$store.getters.pageData(
fmgPageValues.MOLDING_QUESTIONS
);
const pageDataVehicleParts = self.$store.getters.pageData(fmgPageValues.VEHICLE_PARTS);
const pageDataPartQuestions = self.$store.getters.pageData(
fmgPageValues.PART_QUESTIONS
);
let currentPartsOrQuestions = null;
if (
currentPage !== fmgPageValues.CAPABILITY_QUESTIONS &&
!!pageDataCapabilityQuestions
) {
currentPartsOrQuestions = pageDataCapabilityQuestions?.partsOrQuestions;
} else if (
currentPage !== fmgPageValues.MOLDING_QUESTIONS &&
!!pageDataMoldingQuestions
) {
currentPartsOrQuestions = pageDataMoldingQuestions?.partsOrQuestions;
} else if (currentPage !== fmgPageValues.VEHICLE_PARTS && !!pageDataVehicleParts) {
currentPartsOrQuestions = pageDataVehicleParts?.partsOrQuestions;
} else if (currentPage !== fmgPageValues.PARTS_QUESTIONS && !!pageDataPartQuestions) {
currentPartsOrQuestions = pageDataPartQuestions?.partsOrQuestions;
}
const hasPartQuestions = this.hasPartQuestions(currentPartsOrQuestions);
const hasGlassLocationWithMultipleParts =
this.hasGlassLocationWithMultipleParts(partsOrQuestions);
const hasChildPartQuestions = this.hasChildPartQuestions(partsOrQuestions);
const hasCapabilityQuestions = this.hasCapabilityQuestions(partsOrQuestions);
this.hasGlassLocationWithMultipleParts(currentPartsOrQuestions);
const hasChildPartQuestions = this.hasChildPartQuestions(currentPartsOrQuestions);
const hasCapabilityQuestions = this.hasCapabilityQuestions(currentPartsOrQuestions);
const skipVinLookup = await store.dispatch(storeActions.IS_VIN_OPTIONAL_VEHICLE);
let backNavigationScenario = self.$store.getters.vehicle.vin
? navigationScenarios.CLICKED_BACK_WITH_VIN_AND_NO_MORE_QUESTIONS
: navigationScenarios.CLICKED_BACK_WITH_NO_VIN_NOR_QUESTIONS;
const currentPage = self.$route.query.fmgPage;
if (
hasCapabilityQuestions &&
this.currentPageComesAfterPage(currentPage, fmgPageValues.CAPABILITY_QUESTIONS)
@ -505,9 +525,5 @@ export default {
self.$router.navigateWithoutSaving(backNavigationScenario, self.$route);
},
// TODO KO delete this after quote mvp
async handleTempButtonClicked(vm) {
this.shouldGoToHeritageQuote = true;
},
},
};

View file

@ -4,12 +4,6 @@ import vehicleQuestionsMixin from "@/mixins/vehicle-questions-mixin";
import { saveSession } from "@/helpers/heritage-integration/order-helper.js";
export default {
data() {
// TODO KO DELETE AFTER QUOTE MVP
return {
shouldGoToHeritageQuote: false,
};
},
methods: {
async navigateForwardWithSingleCarMatch() {
// If we have not already saved a session, we need to save one now before the lengthy call to getPartsOrQuestions
@ -20,17 +14,7 @@ export default {
const result = await this.dispatchStoreAction(storeActions.GET_PARTS_OR_QUESTIONS);
const partsOrQuestions = result.data.partsOrQuestions;
// TODO KO delete `this.shouldGoToHeritageQuote`
vehicleQuestionsMixin.methods.navigateForward(
partsOrQuestions,
this,
this.shouldGoToHeritageQuote
);
},
// TODO KO delete this after quote mvp
async handleTempButtonClicked(vm) {
this.shouldGoToHeritageQuote = true;
await vm.forwardButtonAction();
vehicleQuestionsMixin.methods.navigateForward(partsOrQuestions, this);
},
},
};

View file

@ -51,7 +51,7 @@ const routes = [
}
if (getFunnelCookie()?.SuppressConceptFunnel) {
await navigateToHeritageFunnel(false);
await navigateToHeritageFunnel({ shouldSaveSession: false });
return next(false);
}
@ -66,6 +66,7 @@ const routes = [
// clear the saveSessionPromise - if it exists in the vuex store but a new instance was created
// the saveSessionPromise will no longer point to a valid promise
baseMixin.methods.dispatchStoreAction(storeActions.RESET_SAVE_SESSION_PROMISE);
const loadSessionResponse = await loadSessionIfPresent();
const pageToRedirectTo = await getPageToRouteExistingOrderTo(
to,

View file

@ -20,6 +20,10 @@ const navigationScenarios = {
// Vin selection
CLICKED_BACK_WITH_VIN: "CLICKED_BACK_WITH_VIN",
CLICKED_FORWARD_WITH_VIN: "CLICKED_FORWARD_WITH_VIN",
CLICKED_FORWARD_WITH_REPAIR_AND_VERIFIED_INSURANCE:
"CLICKED_FORWARD_WITH_REPAIR_AND_VERIFIED_INSURANCE",
CLICKED_FORWARD_WITH_REPLACE_AND_VERIFIED_INSURANCE:
"CLICKED_FORWARD_WITH_REPLACE_AND_VERIFIED_INSURANCE",
CLICKED_FORWARD_WITHOUT_VIN: "CLICKED_FORWARD_WITHOUT_VIN",
CLICKED_FORWARD_WITH_MULTIPLE_VEHICLES: "CLICKED_FORWARD_WITH_MULTIPLE_VEHICLES",
SELECTED_VIN_WITH_MISMATCHED_GLASS: "SELECTED_VIN_WITH_MISMATCHED_GLASS",

View file

@ -67,6 +67,16 @@ const routingTable = function (store) {
scenario: navigationScenarios.CLICKED_FORWARD_WITHOUT_VIN,
destinationFmgPageValue: fmgPageValues.ESTIMATE,
},
{
scenario:
navigationScenarios.CLICKED_FORWARD_WITH_REPAIR_AND_VERIFIED_INSURANCE,
destinationFmgPageValue: fmgPageValues.ESTIMATE,
},
{
scenario:
navigationScenarios.CLICKED_FORWARD_WITH_REPLACE_AND_VERIFIED_INSURANCE,
destinationFmgPageValue: fmgPageValues.VIN_LOOKUP,
},
],
},
{

View file

@ -9,6 +9,7 @@ import { applicationConfig } from "@/constants/application-config";
import { experimentTriggers } from "@/constants/experiments";
import { damageLocationsSelected } from "@/constants/damage-locations-selected";
import { fmgPageValues } from "@/router/router-constants/fmgPage-values";
import router from "@/router";
// Export State
const getDefaultState = () => {
@ -40,6 +41,7 @@ const getDefaultState = () => {
city: null,
state: null,
zipCode: null,
zipCodeCtu: null,
},
customer: {
emailAddress: null,
@ -62,6 +64,7 @@ const getDefaultState = () => {
isInsurance: null,
insuranceCoverage: {
isVerified: null,
coverageStatus: null,
},
},
referralNumber: null,
@ -81,12 +84,6 @@ const getDefaultState = () => {
experiments: [],
triggeredSiteEntry: false,
},
// gaClickInformation: {
// currentlySelectedValues: {},
// firedGaClickEventValues: {},
// lastFocusedInputGroup: "",
// wasLastFocusedInputMultiselect: undefined,
// },
};
};
@ -191,12 +188,6 @@ export const mutations = {
updateRegistrationZipCode(state, registrationZipCode) {
state.order.vehicle.registration.zipCode = registrationZipCode;
},
updateServiceLocationZipCode(state, serviceLocationZip) {
state.order.serviceLocation.zipCode = serviceLocationZip;
},
updateServiceLocationState(state, serviceLocationState) {
state.order.serviceLocation.state = serviceLocationState;
},
updateRegistrationFirstName(state, firstName) {
state.order.vehicle.registration.firstName = firstName;
},
@ -233,6 +224,7 @@ export const mutations = {
state.order.serviceLocation.city = serviceLocationInfo.city;
state.order.serviceLocation.state = serviceLocationInfo.state;
state.order.serviceLocation.zipCode = serviceLocationInfo.zipCode;
state.order.serviceLocation.zipCodeCtu = serviceLocationInfo.zipCodeCtu;
},
// applicationUser MUTATIONS
@ -359,11 +351,15 @@ export const mutations = {
(state.order.serviceLocation.city = sessionInformation.order.serviceLocation.city),
(state.order.serviceLocation.state = sessionInformation.order.serviceLocation.state),
(state.order.serviceLocation.zipCode =
sessionInformation.order.serviceLocation.zipCode);
sessionInformation.order.serviceLocation.zipCode),
(state.order.serviceLocation.zipCodeCtu =
sessionInformation.order.serviceLocation.zipCodeCtu);
state.order.payment.isInsurance = sessionInformation.order.payment.isInsurance;
state.order.payment.insuranceCoverage.isVerified =
sessionInformation?.order.payment.insuranceCoverage.isVerified;
state.order.payment.insuranceCoverage.coverageStatus =
sessionInformation?.insuranceInfo?.coverageStatus;
state.order.customer.emailAddress = sessionInformation.order.customer.emailAddress;
state.order.existingPromoCode = sessionInformation.order.existingPromoCode;
@ -908,14 +904,14 @@ export const actions = {
const carId = context.getters.vehicle.carId;
const isRepair = context.getters.damage.isRepair;
const numberOfChips = context.getters.damage.numberOfChips;
const parentAccountNumber = context.getters.order.accountNumber.toString();
return globalMethods.callHttpClient({
method: endpoints.GetSupportingItems.method,
endpoint: endpoints.GetSupportingItems.url,
payload: {
carId: carId,
serviceType: isRepair ? "Repair" : "Replace",
parentAccountNumber: parentAccountNumber,
parentAccountNumber: applicationConfig.CASH_ACCOUNT_NUMBER,
parts: glassPartsArray,
numberOfRepairChips: isRepair ? numberOfChips : 0,
},
@ -1012,13 +1008,14 @@ export const actions = {
},
isInsurance: order.payment.isInsurance ?? false,
},
accountNumber: order.accountNumber?.toString(),
accountNumber: order.accountNumber,
providerNumber: "",
serviceLocation: {
streetAddress: order.serviceLocation.address,
city: order.serviceLocation.city,
state: order.serviceLocation.state,
zipCode: order.serviceLocation.zipCode,
zipCodeCtu: order.serviceLocation.zipCodeCtu,
},
existingPromoCode: null,
referralCorrelationId: order.referralCorrelationId,
@ -1029,12 +1026,21 @@ export const actions = {
},
});
},
loadSession(context, { savedSessionId }) {
loadSession(context, { savedSessionId, referralNumber, referralCorrelationId, accountNumber }) {
const order = context.state.order;
return globalMethods
.callHttpClient({
method: endpoints.LoadSession.method,
endpoint:
endpoints.LoadSession.url + "?savedSessionId=" + savedSessionId?.toString(),
endpoint: `${
endpoints.LoadSession.url
}?savedSessionId=${savedSessionId?.toString()}&referralNumber=${
referralNumber && referralNumber !== "" ? referralNumber : order.referralNumber
}&accountNumber=${accountNumber}&referralCorrelationId=${
referralCorrelationId !== ""
? referralCorrelationId
: order.referralCorrelationId
}`,
})
.then((response) => {
// Flatten location and name properties
@ -1412,7 +1418,6 @@ export const actions = {
clearVin(context) {
context.commit(storeMutations.UPDATE_VEHICLE_VIN, null);
},
isVinOptionalVehicle(context) {
switch (context.state.order.vehicle.make.toLowerCase()) {
case "mercedes benz":

View file

@ -312,6 +312,28 @@ describe("Mutations", () => {
// Assert
expect(storeState.applicationUser.triggeredSiteEntry).toEqual(true);
});
it("updateServiceLocation, should set serviceLocation in state", () => {
// Arrange
const storeState = state;
const serviceLocation = {
address: "123 Test Lane",
city: "Columbus",
zipCode: "43212",
state: "OH",
zipCodeCtu: "01820",
};
// Act
mutations.updateServiceLocation(storeState, serviceLocation);
// Assert
expect(storeState.order.serviceLocation.address).toEqual("123 Test Lane");
expect(storeState.order.serviceLocation.city).toEqual("Columbus");
expect(storeState.order.serviceLocation.zipCode).toEqual("43212");
expect(storeState.order.serviceLocation.state).toEqual("OH");
expect(storeState.order.serviceLocation.zipCodeCtu).toEqual("01820");
});
});
describe("Actions", () => {
@ -357,13 +379,13 @@ describe("Actions", () => {
// Act
globalMethods.callHttpClient.mockImplementation(() => {
return Promise.resolve({ data: { carId: "C00000001" } });
return Promise.resolve({ data: { carId: "C0000001" } });
});
// Assert
const response = await actions.lookupVehicleByVin(context, "12345678901234567");
expect(response.data).toEqual({ carId: "C00000001" });
expect(response.data).toEqual({ carId: "C0000001" });
});
it("lookupVinByPlate action, should return car data", async () => {
@ -467,13 +489,25 @@ describe("Actions", () => {
// Act
globalMethods.callHttpClient.mockImplementation(() => {
return Promise.resolve({ data: "43201" });
return Promise.resolve({
data: {
isValid: true,
isServiceable: true,
state: "OH",
zipCodeCtu: "01820",
},
});
});
const response = await actions.validateZip(context, "C00000000");
const response = await actions.validateZip(context, "43212");
// Assert
expect(response.data).toEqual("43201");
expect(response.data).toEqual({
isValid: true,
isServiceable: true,
state: "OH",
zipCodeCtu: "01820",
});
});
it("resetDamageAndDependencies action", async () => {
@ -866,18 +900,30 @@ describe("Actions", () => {
);
});
it("saveServiceLocation, should call mutation", () => {
it("saveServiceLocation, should call mutation and save service address to state", () => {
// Arrange
const context = state;
const commit = jest.fn();
context.commit = commit;
const serviceLocation = {
address: "123 Test Lane",
city: "Columbus",
zipCode: "43212",
state: "OH",
zipCodeCtu: "01820",
};
// Act
actions.saveServiceLocation(context, { zipCode: "80020" });
actions.saveServiceLocation(context, serviceLocation);
// Assert
expect(commit).toBeCalledWith(storeMutations.UPDATE_SERVICE_LOCATION, { zipCode: "80020" });
expect(commit).toBeCalledWith(storeMutations.UPDATE_SERVICE_LOCATION, serviceLocation);
expect(state.order.serviceLocation.address).toEqual("123 Test Lane");
expect(state.order.serviceLocation.city).toEqual("Columbus");
expect(state.order.serviceLocation.zipCode).toEqual("43212");
expect(state.order.serviceLocation.state).toEqual("OH");
expect(state.order.serviceLocation.zipCodeCtu).toEqual("01820");
});
it("saveGlassParts, should call mutation", () => {