Merge branch 'release/2024.02.08' into rlsmerge/2024.02.08-to-develop
This commit is contained in:
commit
05090b4345
15 changed files with 2244 additions and 32 deletions
|
|
@ -30,7 +30,7 @@ module.exports = {
|
||||||
testMatch: ["**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)"],
|
testMatch: ["**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)"],
|
||||||
coverageThreshold: {
|
coverageThreshold: {
|
||||||
global: {
|
global: {
|
||||||
statements: 73,
|
statements: 78,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
// Uncomment this to avoid the massive amount of warnings we are getting for onSubmit and onInvalidSubmit
|
// Uncomment this to avoid the massive amount of warnings we are getting for onSubmit and onInvalidSubmit
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@ const applicationConfig = {
|
||||||
"//" +
|
"//" +
|
||||||
location.host +
|
location.host +
|
||||||
"/fmg/?fmgPage=payment-method&src=concept-funnel",
|
"/fmg/?fmgPage=payment-method&src=concept-funnel",
|
||||||
|
CONFIRMATION_URL: location.protocol + "//" + location.host + "/fmg/?fmgPage=confirmation",
|
||||||
GOOGLE_CALENDAR: "https://www.google.com/calendar/render?action=TEMPLATE",
|
GOOGLE_CALENDAR: "https://www.google.com/calendar/render?action=TEMPLATE",
|
||||||
YAHOO_CALENDAR: "https://calendar.yahoo.com/?v=60",
|
YAHOO_CALENDAR: "https://calendar.yahoo.com/?v=60",
|
||||||
OUTLOOK_CALENDAR:
|
OUTLOOK_CALENDAR:
|
||||||
|
|
|
||||||
|
|
@ -53,6 +53,7 @@ const storeMutations = {
|
||||||
UPDATE_IS_PIA: "updateIsPia",
|
UPDATE_IS_PIA: "updateIsPia",
|
||||||
UPDATE_PIA_TYPE: "updatePiaType",
|
UPDATE_PIA_TYPE: "updatePiaType",
|
||||||
WORK_ORDER_NUMBER: "updateWorkOrderNumber",
|
WORK_ORDER_NUMBER: "updateWorkOrderNumber",
|
||||||
|
WORK_ORDER_ID: "updateWorkOrderId",
|
||||||
Customer_Portal_Login_Token: "updateCustomerPortalLoginToken",
|
Customer_Portal_Login_Token: "updateCustomerPortalLoginToken",
|
||||||
LOCK_TOKEN: "updateLockToken",
|
LOCK_TOKEN: "updateLockToken",
|
||||||
UPDATE_SETTLED_TENDER_AMOUNT: "updateSettledTenderAmount",
|
UPDATE_SETTLED_TENDER_AMOUNT: "updateSettledTenderAmount",
|
||||||
|
|
|
||||||
|
|
@ -118,8 +118,7 @@ export default {
|
||||||
left: 0;
|
left: 0;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
background-color: $black;
|
background-color: $white;
|
||||||
opacity: 0.4;
|
|
||||||
z-index: 1056;
|
z-index: 1056;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -129,7 +128,7 @@ export default {
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
outline: 0;
|
outline: 0;
|
||||||
background: $gray-100;
|
background: $white;
|
||||||
|
|
||||||
&.full-screen {
|
&.full-screen {
|
||||||
top: 0;
|
top: 0;
|
||||||
|
|
|
||||||
|
|
@ -162,6 +162,7 @@ async function saveSessionHelper(
|
||||||
crmCustomerId: savedSessionInfo.data.crmCustomerId?.toString(),
|
crmCustomerId: savedSessionInfo.data.crmCustomerId?.toString(),
|
||||||
eon: savedSessionInfo.data.eon,
|
eon: savedSessionInfo.data.eon,
|
||||||
workOrderNumber: savedSessionInfo.data.workOrderNumber,
|
workOrderNumber: savedSessionInfo.data.workOrderNumber,
|
||||||
|
workOrderId: savedSessionInfo.data.workOrderId,
|
||||||
customerPortalLoginToken: savedSessionInfo.data.customerPortalLoginToken,
|
customerPortalLoginToken: savedSessionInfo.data.customerPortalLoginToken,
|
||||||
lockToken: savedSessionInfo.data.lockToken,
|
lockToken: savedSessionInfo.data.lockToken,
|
||||||
settledTenderAmount: savedSessionInfo.data.settledTenderAmount,
|
settledTenderAmount: savedSessionInfo.data.settledTenderAmount,
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@ const stackingPromoErrorCodes = [
|
||||||
promoErrorCodes.SIMILAR_PROMO_ALREADY_ON_ORDER,
|
promoErrorCodes.SIMILAR_PROMO_ALREADY_ON_ORDER,
|
||||||
];
|
];
|
||||||
|
|
||||||
const excludeFromInactivePromoErrorCodes = [
|
export const excludeFromInactivePromoErrorCodes = [
|
||||||
promoErrorCodes.UNKNOWN,
|
promoErrorCodes.UNKNOWN,
|
||||||
promoErrorCodes.PROMO_NOT_YET_IN_USE,
|
promoErrorCodes.PROMO_NOT_YET_IN_USE,
|
||||||
promoErrorCodes.PROMO_USAGE_COUNT_EXCEEDED,
|
promoErrorCodes.PROMO_USAGE_COUNT_EXCEEDED,
|
||||||
|
|
@ -45,7 +45,7 @@ const excludeFromInactivePromoErrorCodes = [
|
||||||
export const pagesToStripPromoQueryStringFrom = ["quote", "payment-method"];
|
export const pagesToStripPromoQueryStringFrom = ["quote", "payment-method"];
|
||||||
|
|
||||||
export function getPromosWithAddableVaps(promoList) {
|
export function getPromosWithAddableVaps(promoList) {
|
||||||
if (!promoList.length) {
|
if (promoList == null || !promoList.length) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -53,8 +53,14 @@ export function getPromosWithAddableVaps(promoList) {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getLineItemsThatMatchPromos(promos, availableLineItems) {
|
export function getLineItemsThatMatchPromos(promos, availableLineItems) {
|
||||||
|
if (promos == null || availableLineItems == null) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
const matchingLineItems = [];
|
const matchingLineItems = [];
|
||||||
promos.forEach((promo) => {
|
promos.forEach((promo) => {
|
||||||
|
if (promo.discountedLineItemIds == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
promo.discountedLineItemIds.forEach((discountedLineItemId) => {
|
promo.discountedLineItemIds.forEach((discountedLineItemId) => {
|
||||||
matchingLineItems.push(
|
matchingLineItems.push(
|
||||||
...availableLineItems.filter((lineItem) => lineItem.id === discountedLineItemId)
|
...availableLineItems.filter((lineItem) => lineItem.id === discountedLineItemId)
|
||||||
|
|
@ -180,6 +186,9 @@ export function buildToastMessagesFromRevalidateOrValidatePromoResponse(
|
||||||
oldActivePromos = [],
|
oldActivePromos = [],
|
||||||
oldInactivePromos = []
|
oldInactivePromos = []
|
||||||
) {
|
) {
|
||||||
|
if (promoResponse == null) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
const alerts = [];
|
const alerts = [];
|
||||||
// Revalidate always has an "errors" array
|
// Revalidate always has an "errors" array
|
||||||
if (promoResponse.errors) {
|
if (promoResponse.errors) {
|
||||||
|
|
@ -213,19 +222,24 @@ export function buildToastMessagesFromRevalidateOrValidatePromoResponse(
|
||||||
);
|
);
|
||||||
alerts.push(createPromoSuccessAlert(promoCodeToDisplay));
|
alerts.push(createPromoSuccessAlert(promoCodeToDisplay));
|
||||||
} else {
|
} else {
|
||||||
alerts.push(
|
if (promoResponse.promoCode) {
|
||||||
createPromoErrorAlert(
|
alerts.push(
|
||||||
promoResponse.promoCode,
|
createPromoErrorAlert(
|
||||||
promoResponse.errorCode,
|
promoResponse.promoCode,
|
||||||
promoResponse.additionalInfo
|
promoResponse.errorCode,
|
||||||
)
|
promoResponse.additionalInfo
|
||||||
);
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return alerts;
|
return alerts;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getPromosThatMatchLineItemsOnOrder(promos, lineItemsOnOrder) {
|
export function getPromosThatMatchLineItemsOnOrder(promos, lineItemsOnOrder) {
|
||||||
|
if (promos == null || lineItemsOnOrder == null) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
const matchingPromoCodes = [];
|
const matchingPromoCodes = [];
|
||||||
const matchingPromos = [];
|
const matchingPromos = [];
|
||||||
const consolidatedPromosWithIds = {};
|
const consolidatedPromosWithIds = {};
|
||||||
|
|
@ -266,7 +280,7 @@ export function getVapsThatNeedToBeAddedToSatisfyPromos(
|
||||||
availableLineItems,
|
availableLineItems,
|
||||||
lineItemsOnOrder
|
lineItemsOnOrder
|
||||||
) {
|
) {
|
||||||
const clonedVaps = deepClone(lineItemsOnOrder.vaps ?? []);
|
const clonedVaps = deepClone(lineItemsOnOrder?.vaps ?? []);
|
||||||
const promosWithAddableVaps = getPromosWithAddableVaps(promos);
|
const promosWithAddableVaps = getPromosWithAddableVaps(promos);
|
||||||
if (promosWithAddableVaps.length) {
|
if (promosWithAddableVaps.length) {
|
||||||
const matchingLineItems = getLineItemsThatMatchPromos(
|
const matchingLineItems = getLineItemsThatMatchPromos(
|
||||||
|
|
@ -311,7 +325,7 @@ export function getNewlyInactivatedPromos(oldInactivePromos, newInactivePromos)
|
||||||
const inactivePromoCodesFromResponse =
|
const inactivePromoCodesFromResponse =
|
||||||
getPromoCodesFromPromoObjectsWithoutDuplicates(newInactivePromos);
|
getPromoCodesFromPromoObjectsWithoutDuplicates(newInactivePromos);
|
||||||
return inactivePromoCodesFromResponse.filter(
|
return inactivePromoCodesFromResponse.filter(
|
||||||
(errorPromoCode) => !oldInactivePromos.includes(errorPromoCode)
|
(errorPromoCode) => !oldInactivePromos?.includes(errorPromoCode)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -365,8 +379,9 @@ export function getPromoCodesFromPromoObjectsWithoutDuplicates(promos) {
|
||||||
|
|
||||||
// private methods
|
// private methods
|
||||||
function findLineItemsWithPartType(typeToFind, itemsToSearch) {
|
function findLineItemsWithPartType(typeToFind, itemsToSearch) {
|
||||||
const partTypeMatches = itemsToSearch?.filter(
|
const partTypeMatches =
|
||||||
(lineItem) => lineItem.partType.toUpperCase() === typeToFind.toUpperCase()
|
itemsToSearch?.filter(
|
||||||
);
|
(lineItem) => lineItem.partType.toUpperCase() === typeToFind.toUpperCase()
|
||||||
|
) ?? [];
|
||||||
return partTypeMatches;
|
return partTypeMatches;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
1215
src/helpers/promotions-helper.spec.js
Normal file
1215
src/helpers/promotions-helper.spec.js
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -75,6 +75,7 @@ import cart from "@/fmg-components/cart/cart";
|
||||||
|
|
||||||
//Supporting files
|
//Supporting files
|
||||||
import baseMixin from "@/mixins/base-mixin.js";
|
import baseMixin from "@/mixins/base-mixin.js";
|
||||||
|
import analyticsMixin from "@/mixins/analytics-mixin";
|
||||||
import store from "@/store";
|
import store from "@/store";
|
||||||
import { storeActions } from "@/constants/store-actions";
|
import { storeActions } from "@/constants/store-actions";
|
||||||
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
|
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
|
||||||
|
|
@ -134,6 +135,7 @@ export default {
|
||||||
vm.setCmsContent(resultMap.cmsContent);
|
vm.setCmsContent(resultMap.cmsContent);
|
||||||
vm.lineItems = lineItemsFromSubmittedOrder;
|
vm.lineItems = lineItemsFromSubmittedOrder;
|
||||||
vm.vaps = availableVaps;
|
vm.vaps = availableVaps;
|
||||||
|
analyticsMixin.methods.pushSubmittedOrderToDataLayer();
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
|
|
@ -387,7 +389,9 @@ export default {
|
||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
}
|
}
|
||||||
.header-container {
|
.header-container {
|
||||||
text-align: center;
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
padding: 1rem 0 1.5rem 0;
|
padding: 1rem 0 1.5rem 0;
|
||||||
|
|
||||||
p {
|
p {
|
||||||
|
|
@ -395,6 +399,11 @@ export default {
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
font-size: 1.25rem;
|
font-size: 1.25rem;
|
||||||
color: $black;
|
color: $black;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
img {
|
||||||
|
margin-right: 0.5rem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@
|
||||||
v-if="shouldDisplayPiaCCAlert"
|
v-if="shouldDisplayPiaCCAlert"
|
||||||
cmsWidgetName="PIACCErrorAlertWidget"
|
cmsWidgetName="PIACCErrorAlertWidget"
|
||||||
alertClass="alert-danger"
|
alertClass="alert-danger"
|
||||||
|
@textLinkClicked="paymentFailedPayLater"
|
||||||
v-bind:isDismissible="false" />
|
v-bind:isDismissible="false" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -27,6 +28,7 @@
|
||||||
v-if="shouldDisplayPiaAPAlert"
|
v-if="shouldDisplayPiaAPAlert"
|
||||||
cmsWidgetName="PIAAPErrorAlertWidget"
|
cmsWidgetName="PIAAPErrorAlertWidget"
|
||||||
alertClass="alert-danger"
|
alertClass="alert-danger"
|
||||||
|
@textLinkClicked="paymentFailedPayLater"
|
||||||
v-bind:isDismissible="false" />
|
v-bind:isDismissible="false" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -216,6 +218,7 @@ import {
|
||||||
import { queryStrings } from "@/constants/query-strings";
|
import { queryStrings } from "@/constants/query-strings";
|
||||||
import { getQuerystringParameter } from "@/helpers/querystring-helper";
|
import { getQuerystringParameter } from "@/helpers/querystring-helper";
|
||||||
import { deepClone } from "@/helpers/object-helper";
|
import { deepClone } from "@/helpers/object-helper";
|
||||||
|
import { submitWorkOrder } from "@/helpers/heritage-integration/order-helper.js";
|
||||||
|
|
||||||
import iframeResize from "../../../node_modules/iframe-resizer/js/iframeResizer.js";
|
import iframeResize from "../../../node_modules/iframe-resizer/js/iframeResizer.js";
|
||||||
import { routerParams } from "@/router/router-constants/router-params";
|
import { routerParams } from "@/router/router-constants/router-params";
|
||||||
|
|
@ -573,6 +576,36 @@ export default {
|
||||||
getDisplayAmountDue() {
|
getDisplayAmountDue() {
|
||||||
return baseMixin.methods.getDisplayAmountDue(store.getters.order.lineItems);
|
return baseMixin.methods.getDisplayAmountDue(store.getters.order.lineItems);
|
||||||
},
|
},
|
||||||
|
async paymentFailedPayLater() {
|
||||||
|
this.$refs.loadingModal.isModalVisible = true;
|
||||||
|
|
||||||
|
await this.dispatchStoreAction(
|
||||||
|
storeActions.SAVE_PAYMENT_METHOD_CHOICE,
|
||||||
|
paymentMethods.LATER,
|
||||||
|
false
|
||||||
|
);
|
||||||
|
|
||||||
|
await this.dispatchStoreAction(storeActions.RESET_SAVE_SESSION_PROMISE);
|
||||||
|
try {
|
||||||
|
await submitWorkOrder({
|
||||||
|
pageNameToLog: "payment",
|
||||||
|
submitAfterSave: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
await baseMixin.methods.dispatchStoreAction(storeActions.CREATE_SUBMITTED_ORDER);
|
||||||
|
window.location = applicationConfig.CONFIRMATION_URL;
|
||||||
|
} catch (error) {
|
||||||
|
console.log("error: response from submit work order(payment pg):" + error.message);
|
||||||
|
this.$router.navigateWithoutSaving(
|
||||||
|
this.navigationScenarios.PIA_ERROR,
|
||||||
|
this.$route,
|
||||||
|
{},
|
||||||
|
{ [routerParams.DISPLAY_PIA_ALERT]: true }
|
||||||
|
);
|
||||||
|
this.$refs.loadingModal.isModalVisible = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
},
|
||||||
backButtonAction() {
|
backButtonAction() {
|
||||||
// The only way I could figure out how to get navigation to work on a page with the iframe.
|
// The only way I could figure out how to get navigation to work on a page with the iframe.
|
||||||
// This is also how a cancel from Paypal would work. Just a redirect to the payment-method page.
|
// This is also how a cancel from Paypal would work. Just a redirect to the payment-method page.
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ import {
|
||||||
GaEvents,
|
GaEvents,
|
||||||
ValueToLogTypes,
|
ValueToLogTypes,
|
||||||
} from "@/constants/analytics";
|
} from "@/constants/analytics";
|
||||||
|
import { AppointmentTypeStrings } from "@/constants/schedule-constants";
|
||||||
import store from "@/store";
|
import store from "@/store";
|
||||||
|
|
||||||
import baseMixin from "@/mixins/base-mixin";
|
import baseMixin from "@/mixins/base-mixin";
|
||||||
|
|
@ -119,6 +120,82 @@ export default {
|
||||||
await this.logPageView(analyticsPageEvents.ENTRY);
|
await this.logPageView(analyticsPageEvents.ENTRY);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
pushSubmittedOrderToDataLayer() {
|
||||||
|
// check if submitted order exists; exit if not.
|
||||||
|
const hasSubmittedOrder = store.getters.hasSubmittedOrder;
|
||||||
|
|
||||||
|
if (!hasSubmittedOrder) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const order = store.getters.submittedOrder;
|
||||||
|
|
||||||
|
// assemble data for payload
|
||||||
|
// // reduce promocode array
|
||||||
|
const promos = order.lineItems.promos ?? [];
|
||||||
|
const promoCodes = promos.map((promo) => promo.promoCode);
|
||||||
|
const promoString =
|
||||||
|
promoCodes.length === 0 ? "" : promoCodes.reduce((prev, next) => `${prev},${next}`);
|
||||||
|
|
||||||
|
// // reduce glass array
|
||||||
|
const glassToReplace = order.damage.glassToReplace ?? [];
|
||||||
|
const glassToReplaceNames = glassToReplace.map(
|
||||||
|
(glassPiece) => `${glassPiece.glassLocation}/${glassPiece.glassName}`
|
||||||
|
);
|
||||||
|
const glassString =
|
||||||
|
glassToReplaceNames.length === 0
|
||||||
|
? ""
|
||||||
|
: glassToReplaceNames.reduce((prev, next) => `${prev},${next}`);
|
||||||
|
|
||||||
|
// // calculate subtotal
|
||||||
|
const lineItems = order.lineItems;
|
||||||
|
const combinedLineItems = [
|
||||||
|
...(lineItems.glassParts ?? []),
|
||||||
|
...(lineItems.supportingItems ?? []),
|
||||||
|
...(lineItems.vaps ?? []),
|
||||||
|
...(lineItems.promos ?? []),
|
||||||
|
];
|
||||||
|
const subtotal = baseMixin.methods.getTotalPriceOfAllLineItemsAndChildParts(
|
||||||
|
combinedLineItems,
|
||||||
|
false
|
||||||
|
);
|
||||||
|
|
||||||
|
// // get correct zip code
|
||||||
|
const providerZip = order.serviceLocation.provider.address.zipCode;
|
||||||
|
const serviceZip =
|
||||||
|
order.serviceLocation.appointmentType === AppointmentTypeStrings.MOBILE
|
||||||
|
? order.serviceLocation.zipCode
|
||||||
|
: providerZip;
|
||||||
|
|
||||||
|
// // calculate total
|
||||||
|
const total = baseMixin.methods.getTotalPriceOfAllLineItemsAndChildParts(
|
||||||
|
combinedLineItems,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
|
||||||
|
const payload = {
|
||||||
|
serviceZipCode: serviceZip,
|
||||||
|
damageType: order.damage.isRepair ? "repair" : "replace",
|
||||||
|
accountType: order.payment.isInsurance ? "insurance" : "cash",
|
||||||
|
promoCodes: promoString,
|
||||||
|
vehicleYear: order.vehicle.year,
|
||||||
|
vehicleMake: order.vehicle.make,
|
||||||
|
vehicleModel: order.vehicle.model,
|
||||||
|
vehicleStyle: order.vehicle.style,
|
||||||
|
glassToReplace: glassString,
|
||||||
|
workOrderId: order.workOrderId,
|
||||||
|
providerCtu: order.serviceLocation.zipCodeCtu,
|
||||||
|
orderNumber: order.workOrderNumber,
|
||||||
|
priceTotal: total,
|
||||||
|
priceSubTotal: subtotal,
|
||||||
|
isRecalibrationOnOrder: store.getters.isRecalibrationOnSubmittedOrder,
|
||||||
|
appointmentType: order.serviceLocation.appointmentType,
|
||||||
|
};
|
||||||
|
|
||||||
|
// push to data layer.
|
||||||
|
pushToDataLayerIfDefined(payload);
|
||||||
|
},
|
||||||
|
|
||||||
pushExperimentsToDataLayer() {
|
pushExperimentsToDataLayer() {
|
||||||
const experiments = store.getters.applicationUser.experiments;
|
const experiments = store.getters.applicationUser.experiments;
|
||||||
experiments?.forEach((exp) => {
|
experiments?.forEach((exp) => {
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,46 @@ import {
|
||||||
getUserIdValue,
|
getUserIdValue,
|
||||||
} from "@/helpers/heritage-integration/cookie-helper";
|
} from "@/helpers/heritage-integration/cookie-helper";
|
||||||
|
|
||||||
|
const parts = {
|
||||||
|
windshield: {
|
||||||
|
name: "windshield",
|
||||||
|
canSafeliteRecalibrate: true,
|
||||||
|
childParts: [],
|
||||||
|
color: "Green Tint",
|
||||||
|
description:
|
||||||
|
"solar, soundproofing, lane keep assist, lane departure warning system, w/adaptive cruise control",
|
||||||
|
id: "db22fd44-10dd-456f-979b-ff88cf68cca6",
|
||||||
|
partNumber: "FW04896GTYN",
|
||||||
|
partType: "WINDSHIELD",
|
||||||
|
recalibrationType: "STATIC",
|
||||||
|
requiresCapabilityQuestions: false,
|
||||||
|
requiresRecalibration: true,
|
||||||
|
salesTax: 63.86,
|
||||||
|
sellingPrice: 791.46,
|
||||||
|
},
|
||||||
|
frontWipers: {
|
||||||
|
name: "front wipers",
|
||||||
|
partNumber: "SBB16",
|
||||||
|
description: "SAFELITE BEAM BLADE 16",
|
||||||
|
partType: "FRONT WIPER",
|
||||||
|
price: 32.64,
|
||||||
|
},
|
||||||
|
rearWipers: {
|
||||||
|
name: "rear wipers",
|
||||||
|
partNumber: "SBBR12A",
|
||||||
|
description: "SAFELITE REAR BLADE 12A",
|
||||||
|
partType: "REAR WIPER",
|
||||||
|
price: 24.48,
|
||||||
|
},
|
||||||
|
rainDefense: {
|
||||||
|
name: "rain defense",
|
||||||
|
partNumber: "RAIN DEFENSE",
|
||||||
|
description: null,
|
||||||
|
partType: "RAIN DEFENSE",
|
||||||
|
price: 35.5,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
describe("analyticsMixin.js", () => {
|
describe("analyticsMixin.js", () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
removeAllTestCookies();
|
removeAllTestCookies();
|
||||||
|
|
@ -284,6 +324,130 @@ describe("analyticsMixin.js", () => {
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("pushSubmittedOrderToDataLayer", () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
store.getters.hasSubmittedOrder = true;
|
||||||
|
store.getters.submittedOrder = {
|
||||||
|
vehicle: {
|
||||||
|
year: "2020",
|
||||||
|
make: "acura",
|
||||||
|
model: "mdx",
|
||||||
|
style: "4-door sedan",
|
||||||
|
carId: "dummyCarId",
|
||||||
|
category: "dummyCategory",
|
||||||
|
vin: "dummyVin",
|
||||||
|
},
|
||||||
|
serviceLocation: {
|
||||||
|
address: "add1",
|
||||||
|
address2: "add2",
|
||||||
|
city: "city",
|
||||||
|
state: "state",
|
||||||
|
zipCode: "zip",
|
||||||
|
zipCodeCtu: "zipCtu",
|
||||||
|
appointmentType: "IN_SHOP",
|
||||||
|
isVehicleProtected: true,
|
||||||
|
provider: {
|
||||||
|
providerNumber: 2,
|
||||||
|
address: {
|
||||||
|
streetAddress: "add3",
|
||||||
|
city: "city2",
|
||||||
|
state: "state2",
|
||||||
|
zipCode: "zip2",
|
||||||
|
zipCodeCtu: "zipCtu2",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
techNotes: "",
|
||||||
|
},
|
||||||
|
customer: {
|
||||||
|
firstName: "first",
|
||||||
|
lastName: "last",
|
||||||
|
emailAddress: "builddigitaltest@safelite.com",
|
||||||
|
phoneNumber: "555-555-5555",
|
||||||
|
isSmsOptIn: false,
|
||||||
|
},
|
||||||
|
damage: {
|
||||||
|
isRepair: false,
|
||||||
|
numberOfChips: null,
|
||||||
|
glassToReplace: [{ glassName: "single", location: "windshield" }],
|
||||||
|
},
|
||||||
|
lineItems: {
|
||||||
|
glassParts: [parts.windshield],
|
||||||
|
supportingItems: [],
|
||||||
|
vaps: [parts.frontWipers],
|
||||||
|
promos: [{ promoCode: "promoTEST" }, { promoCode: "promoTEST2" }],
|
||||||
|
},
|
||||||
|
payment: {
|
||||||
|
isInsurance: false,
|
||||||
|
insuranceCoverage: {
|
||||||
|
isVerified: null,
|
||||||
|
coverageStatus: null,
|
||||||
|
coverageVerificationType: null,
|
||||||
|
},
|
||||||
|
isPia: true,
|
||||||
|
piaType: "Afterpay",
|
||||||
|
inactivePromos: [],
|
||||||
|
},
|
||||||
|
schedule: {
|
||||||
|
date: "date",
|
||||||
|
startTime: "start",
|
||||||
|
endTime: "end",
|
||||||
|
jobMinMinutes: "30",
|
||||||
|
jobMaxMinutes: "45",
|
||||||
|
},
|
||||||
|
workOrderNumber: "01820-111111",
|
||||||
|
workOrderId: "222222222222",
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
test("Pushes to data layer if nominal", () => {
|
||||||
|
// Arrange
|
||||||
|
const mockDataLayerFn = jest.fn();
|
||||||
|
|
||||||
|
window.dataLayer = {
|
||||||
|
push: mockDataLayerFn,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
analyticsMixin.methods.pushSubmittedOrderToDataLayer();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(mockDataLayerFn).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("Does not push to data layer if no submitted order available.", () => {
|
||||||
|
// Arrange
|
||||||
|
store.getters.hasSubmittedOrder = false;
|
||||||
|
store.getters.submittedOrder = undefined;
|
||||||
|
|
||||||
|
const mockDataLayerFn = jest.fn();
|
||||||
|
|
||||||
|
window.dataLayer = {
|
||||||
|
push: mockDataLayerFn,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
analyticsMixin.methods.pushSubmittedOrderToDataLayer();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(mockDataLayerFn).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("Glass and Promo strings correctly formatted", () => {
|
||||||
|
// Arrange
|
||||||
|
window.dataLayer = [];
|
||||||
|
|
||||||
|
// Act
|
||||||
|
analyticsMixin.methods.pushSubmittedOrderToDataLayer();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
const glassString = window.dataLayer[0].glassToReplace;
|
||||||
|
const promoString = window.dataLayer[0].promoCodes;
|
||||||
|
|
||||||
|
expect(glassString).toMatch(/(\w+\/\w+)?(,\w+\/\w+)*/);
|
||||||
|
expect(promoString).toMatch(/(\w+)?(,\w+)*/);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
test("Obj is not null after action prepended", () => {
|
test("Obj is not null after action prepended", () => {
|
||||||
//Arrange
|
//Arrange
|
||||||
const obj = { baseMethodName: "testMethodName", data: "testData" };
|
const obj = { baseMethodName: "testMethodName", data: "testData" };
|
||||||
|
|
|
||||||
|
|
@ -9,16 +9,9 @@ export default {
|
||||||
return Object.hasOwn(store.getters.experimentSettings, settingName);
|
return Object.hasOwn(store.getters.experimentSettings, settingName);
|
||||||
},
|
},
|
||||||
getSettingValue(settingName) {
|
getSettingValue(settingName) {
|
||||||
if (this.hasSetting(settingName)) {
|
return this.hasSetting(settingName)
|
||||||
return store.getters.experimentSettings[settingName];
|
? store.getters.experimentSettings[settingName]
|
||||||
} else if (store.getters.hasSubmittedOrder) {
|
: null;
|
||||||
const experimentSettings = store.getters.submittedOrder.experiments
|
|
||||||
.filter((x) => x.isActive)
|
|
||||||
.reduce((r, c) => ({ ...r, ...c.settings }), {});
|
|
||||||
return experimentSettings[settingName] ?? null;
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -132,6 +132,7 @@ const getDefaultState = () => {
|
||||||
referralCorrelationId: null,
|
referralCorrelationId: null,
|
||||||
eon: null,
|
eon: null,
|
||||||
workOrderNumber: null,
|
workOrderNumber: null,
|
||||||
|
workOrderId: null,
|
||||||
customerPortalLoginToken: null,
|
customerPortalLoginToken: null,
|
||||||
lockToken: null,
|
lockToken: null,
|
||||||
settledTenderAmount: 0,
|
settledTenderAmount: 0,
|
||||||
|
|
@ -254,6 +255,9 @@ export const mutations = {
|
||||||
updateWorkOrderNumber(state, workOrderNumber) {
|
updateWorkOrderNumber(state, workOrderNumber) {
|
||||||
state.order.workOrderNumber = workOrderNumber;
|
state.order.workOrderNumber = workOrderNumber;
|
||||||
},
|
},
|
||||||
|
updateWorkOrderId(state, workOrderId) {
|
||||||
|
state.order.workOrderId = workOrderId;
|
||||||
|
},
|
||||||
updateCustomerPortalLoginToken(state, customerPortalLoginToken) {
|
updateCustomerPortalLoginToken(state, customerPortalLoginToken) {
|
||||||
state.order.customerPortalLoginToken = customerPortalLoginToken;
|
state.order.customerPortalLoginToken = customerPortalLoginToken;
|
||||||
},
|
},
|
||||||
|
|
@ -1027,6 +1031,7 @@ export const actions = {
|
||||||
savedSessionId,
|
savedSessionId,
|
||||||
crmCustomerId,
|
crmCustomerId,
|
||||||
workOrderNumber,
|
workOrderNumber,
|
||||||
|
workOrderId,
|
||||||
customerPortalLoginToken,
|
customerPortalLoginToken,
|
||||||
lockToken,
|
lockToken,
|
||||||
settledTenderAmount,
|
settledTenderAmount,
|
||||||
|
|
@ -1041,6 +1046,7 @@ export const actions = {
|
||||||
context.commit(storeMutations.UPDATE_SAVED_SESSION_ID, savedSessionId);
|
context.commit(storeMutations.UPDATE_SAVED_SESSION_ID, savedSessionId);
|
||||||
context.commit(storeMutations.UPDATE_CRM_CUSTOMER_ID, crmCustomerId);
|
context.commit(storeMutations.UPDATE_CRM_CUSTOMER_ID, crmCustomerId);
|
||||||
context.commit(storeMutations.WORK_ORDER_NUMBER, workOrderNumber);
|
context.commit(storeMutations.WORK_ORDER_NUMBER, workOrderNumber);
|
||||||
|
context.commit(storeMutations.WORK_ORDER_ID, workOrderId);
|
||||||
context.commit(storeMutations.LOCK_TOKEN, lockToken);
|
context.commit(storeMutations.LOCK_TOKEN, lockToken);
|
||||||
context.commit(storeMutations.Customer_Portal_Login_Token, customerPortalLoginToken);
|
context.commit(storeMutations.Customer_Portal_Login_Token, customerPortalLoginToken);
|
||||||
context.commit(storeMutations.UPDATE_SETTLED_TENDER_AMOUNT, settledTenderAmount);
|
context.commit(storeMutations.UPDATE_SETTLED_TENDER_AMOUNT, settledTenderAmount);
|
||||||
|
|
@ -2514,14 +2520,16 @@ export const actions = {
|
||||||
// create a submitted order object from vuex.
|
// create a submitted order object from vuex.
|
||||||
const submittedOrder = context.state.order;
|
const submittedOrder = context.state.order;
|
||||||
|
|
||||||
//add experiments to submittedOrder
|
const experiments = context.state.applicationUser.experiments;
|
||||||
submittedOrder.experiments = context.state.applicationUser.experiments;
|
|
||||||
|
|
||||||
// set to local storage
|
// set to local storage
|
||||||
window.sessionStorage.setItem("submittedOrder", JSON.stringify(submittedOrder));
|
window.sessionStorage.setItem("submittedOrder", JSON.stringify(submittedOrder));
|
||||||
|
|
||||||
// clear vuex
|
// clear vuex
|
||||||
context.commit(storeMutations.RESET_STATE);
|
context.commit(storeMutations.RESET_STATE);
|
||||||
|
|
||||||
|
//restore user's experiments
|
||||||
|
context.commit(storeMutations.UPDATE_EXPERIMENTS, experiments);
|
||||||
},
|
},
|
||||||
|
|
||||||
resetSubmittedOrder(context) {
|
resetSubmittedOrder(context) {
|
||||||
|
|
|
||||||
|
|
@ -2766,6 +2766,702 @@ describe("Actions", () => {
|
||||||
testCapabilityQuestionAnswerDependenciesHaveBeenReset(context, true);
|
testCapabilityQuestionAnswerDependenciesHaveBeenReset(context, true);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
describe("saveActiveAndOrInactivePromos", () => {
|
||||||
|
it("should save empty arrays to promos and inactivePromos when provided with empty or null parameters", () => {
|
||||||
|
// Arrange
|
||||||
|
const context = state;
|
||||||
|
context.commit = jest.fn();
|
||||||
|
|
||||||
|
const emptyActivePromos = [];
|
||||||
|
const emptyInactivePromos = [];
|
||||||
|
const nullActivePromos = [];
|
||||||
|
const nullInactivePromos = [];
|
||||||
|
|
||||||
|
// Act
|
||||||
|
actions.saveActiveAndOrInactivePromos(context, {
|
||||||
|
activePromos: emptyActivePromos,
|
||||||
|
inactivePromos: emptyInactivePromos,
|
||||||
|
});
|
||||||
|
actions.saveActiveAndOrInactivePromos(context, {
|
||||||
|
activePromos: nullActivePromos,
|
||||||
|
inactivePromos: nullInactivePromos,
|
||||||
|
});
|
||||||
|
// Assert
|
||||||
|
expect(context.commit).toHaveBeenNthCalledWith(1, storeMutations.UPDATE_PROMOS, []);
|
||||||
|
expect(context.commit).toHaveBeenNthCalledWith(
|
||||||
|
2,
|
||||||
|
storeMutations.UPDATE_INACTIVE_PROMOS,
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
expect(context.commit).toHaveBeenNthCalledWith(3, storeMutations.UPDATE_PROMOS, []);
|
||||||
|
expect(context.commit).toHaveBeenNthCalledWith(
|
||||||
|
4,
|
||||||
|
storeMutations.UPDATE_INACTIVE_PROMOS,
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
});
|
||||||
|
it("should save both active and inactivePromos when method is supplied with both active and inactive", () => {
|
||||||
|
// Arrange
|
||||||
|
const context = state;
|
||||||
|
context.commit = jest.fn();
|
||||||
|
|
||||||
|
const activePromos = [{ promoCode: "activePromo" }];
|
||||||
|
const inactivePromos = ["inactivePromo"];
|
||||||
|
|
||||||
|
// Act
|
||||||
|
actions.saveActiveAndOrInactivePromos(context, {
|
||||||
|
activePromos: activePromos,
|
||||||
|
inactivePromos: inactivePromos,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(context.commit).toBeCalledWith(storeMutations.UPDATE_PROMOS, activePromos);
|
||||||
|
expect(context.commit).toBeCalledWith(
|
||||||
|
storeMutations.UPDATE_INACTIVE_PROMOS,
|
||||||
|
inactivePromos
|
||||||
|
);
|
||||||
|
});
|
||||||
|
it("should remove any inactivePromos that are already active when supplied with both active and inactive", () => {
|
||||||
|
// Arrange
|
||||||
|
const context = state;
|
||||||
|
context.commit = jest.fn();
|
||||||
|
|
||||||
|
const activePromos = [{ promoCode: "duplicatePromo" }];
|
||||||
|
const inactivePromos = ["duplicatePromo", "uniquePromo"];
|
||||||
|
|
||||||
|
const expectedInactivePromos = ["uniquePromo"];
|
||||||
|
|
||||||
|
// Act
|
||||||
|
actions.saveActiveAndOrInactivePromos(context, {
|
||||||
|
activePromos: activePromos,
|
||||||
|
inactivePromos: inactivePromos,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(context.commit).toBeCalledWith(
|
||||||
|
storeMutations.UPDATE_INACTIVE_PROMOS,
|
||||||
|
expectedInactivePromos
|
||||||
|
);
|
||||||
|
});
|
||||||
|
it("should save active promos from store and inactive promos from method call when only inactivePromos is provided", () => {
|
||||||
|
// Arrange
|
||||||
|
const context = state;
|
||||||
|
context.commit = jest.fn();
|
||||||
|
|
||||||
|
const activePromos = [{ promoCode: "storedPromo" }];
|
||||||
|
const inactivePromos = ["inactivePromo"];
|
||||||
|
context["getters"] = { lineItems: { promos: activePromos } };
|
||||||
|
|
||||||
|
// Act
|
||||||
|
actions.saveActiveAndOrInactivePromos(context, { inactivePromos: inactivePromos });
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(context.commit).toBeCalledWith(storeMutations.UPDATE_PROMOS, activePromos);
|
||||||
|
expect(context.commit).toBeCalledWith(
|
||||||
|
storeMutations.UPDATE_INACTIVE_PROMOS,
|
||||||
|
inactivePromos
|
||||||
|
);
|
||||||
|
});
|
||||||
|
it("should save active promos but remove duplicates from store and inactive promos from method call when only inactivePromos is provided", () => {
|
||||||
|
// If only inactivePromos is supplied, it will remove duplicates from active promos in the store
|
||||||
|
// Arrange
|
||||||
|
const context = state;
|
||||||
|
context.commit = jest.fn();
|
||||||
|
|
||||||
|
const activePromos = [{ promoCode: "storedPromo" }, { promoCode: "duplicatePromo" }];
|
||||||
|
const inactivePromos = ["duplicatePromo"];
|
||||||
|
context["getters"] = { lineItems: { promos: activePromos } };
|
||||||
|
|
||||||
|
const expectedSavedActivePromos = [{ promoCode: "storedPromo" }];
|
||||||
|
|
||||||
|
// Act
|
||||||
|
actions.saveActiveAndOrInactivePromos(context, { inactivePromos: inactivePromos });
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(context.commit).toBeCalledWith(
|
||||||
|
storeMutations.UPDATE_PROMOS,
|
||||||
|
expectedSavedActivePromos
|
||||||
|
);
|
||||||
|
expect(context.commit).toBeCalledWith(
|
||||||
|
storeMutations.UPDATE_INACTIVE_PROMOS,
|
||||||
|
inactivePromos
|
||||||
|
);
|
||||||
|
});
|
||||||
|
it("should save inactivePromos from the store and provided activePromos when only activePromos is provided", () => {
|
||||||
|
// Arrange
|
||||||
|
const context = state;
|
||||||
|
context.commit = jest.fn();
|
||||||
|
|
||||||
|
const activePromos = [{ promoCode: "activePromo" }];
|
||||||
|
const inactivePromos = ["inactivePromo"];
|
||||||
|
context["getters"] = { payment: { inactivePromos: inactivePromos } };
|
||||||
|
|
||||||
|
// Act
|
||||||
|
actions.saveActiveAndOrInactivePromos(context, { activePromos: activePromos });
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(context.commit).toBeCalledWith(storeMutations.UPDATE_PROMOS, activePromos);
|
||||||
|
expect(context.commit).toBeCalledWith(
|
||||||
|
storeMutations.UPDATE_INACTIVE_PROMOS,
|
||||||
|
inactivePromos
|
||||||
|
);
|
||||||
|
});
|
||||||
|
it("should save inactivePromos without duplicates from activePromos from the store and provided activePromos when only activePromos is provided", () => {
|
||||||
|
// Arrange
|
||||||
|
const context = state;
|
||||||
|
context.commit = jest.fn();
|
||||||
|
|
||||||
|
const activePromos = [{ promoCode: "activePromo" }, { promoCode: "duplicatePromo" }];
|
||||||
|
const inactivePromos = ["inactivePromo", "duplicatePromo"];
|
||||||
|
context["getters"] = { payment: { inactivePromos: inactivePromos } };
|
||||||
|
|
||||||
|
const expectedInactivePromos = ["inactivePromo"];
|
||||||
|
|
||||||
|
// Act
|
||||||
|
actions.saveActiveAndOrInactivePromos(context, { activePromos: activePromos });
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(context.commit).toBeCalledWith(storeMutations.UPDATE_PROMOS, activePromos);
|
||||||
|
expect(context.commit).toBeCalledWith(
|
||||||
|
storeMutations.UPDATE_INACTIVE_PROMOS,
|
||||||
|
expectedInactivePromos
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
describe("validateOrderPromoAndSaveServerData", () => {
|
||||||
|
it("should add GUIDs if not there to provided addableVaps before sending the http call", async () => {
|
||||||
|
// Arrange
|
||||||
|
const context = state;
|
||||||
|
const promoCode = "testPromo";
|
||||||
|
const lineItemsToUse = { vaps: [1], promos: [2] };
|
||||||
|
const addableVaps = [{ partNumber: "addableVap" }];
|
||||||
|
|
||||||
|
context["getters"] = {
|
||||||
|
order: {
|
||||||
|
serviceLocation: {
|
||||||
|
appointmentType: "test",
|
||||||
|
state: "test",
|
||||||
|
zipCodeCtu: "test",
|
||||||
|
},
|
||||||
|
vehicle: {
|
||||||
|
carId: "test",
|
||||||
|
year: "test",
|
||||||
|
},
|
||||||
|
referralCorrelationId: "test",
|
||||||
|
eon: "test",
|
||||||
|
damage: {
|
||||||
|
isRepair: true,
|
||||||
|
glassToReplace: null,
|
||||||
|
},
|
||||||
|
payment: {
|
||||||
|
parentAccountNumber: "test",
|
||||||
|
},
|
||||||
|
referralSequenceNumber: "test",
|
||||||
|
lineItems: {
|
||||||
|
serverData: "test",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
globalMethods.callHttpClient = jest.fn().mockResolvedValue({
|
||||||
|
data: {},
|
||||||
|
});
|
||||||
|
|
||||||
|
crypto.randomUUID = jest.fn(() => "GUID");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
actions.validateOrderPromoAndSaveServerData(context, {
|
||||||
|
payload: {
|
||||||
|
promoCode: promoCode,
|
||||||
|
lineItemsToUse: lineItemsToUse,
|
||||||
|
addableVaps: addableVaps,
|
||||||
|
},
|
||||||
|
pageNameToLog: "test",
|
||||||
|
});
|
||||||
|
|
||||||
|
const firstCallArgs = globalMethods.callHttpClient.mock.calls[0];
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(firstCallArgs[0].payload.addableVaps[0].id).toEqual("GUID");
|
||||||
|
});
|
||||||
|
it("should use lineItems from the store if not provided in the call", async () => {
|
||||||
|
// Arrange
|
||||||
|
const context = state;
|
||||||
|
const promoCode = "testPromo";
|
||||||
|
const lineItemsToUse = null;
|
||||||
|
const addableVaps = [{ partNumber: "addableVap" }];
|
||||||
|
|
||||||
|
context["getters"] = {
|
||||||
|
order: {
|
||||||
|
serviceLocation: {
|
||||||
|
appointmentType: "test",
|
||||||
|
state: "test",
|
||||||
|
zipCodeCtu: "test",
|
||||||
|
},
|
||||||
|
vehicle: {
|
||||||
|
carId: "test",
|
||||||
|
year: "test",
|
||||||
|
},
|
||||||
|
referralCorrelationId: "test",
|
||||||
|
eon: "test",
|
||||||
|
damage: {
|
||||||
|
isRepair: true,
|
||||||
|
glassToReplace: null,
|
||||||
|
},
|
||||||
|
payment: {
|
||||||
|
parentAccountNumber: "test",
|
||||||
|
},
|
||||||
|
referralSequenceNumber: "test",
|
||||||
|
lineItems: {
|
||||||
|
vaps: [1],
|
||||||
|
promos: [2],
|
||||||
|
serverData: "test",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
globalMethods.callHttpClient = jest.fn().mockResolvedValue({
|
||||||
|
data: {},
|
||||||
|
});
|
||||||
|
|
||||||
|
crypto.randomUUID = jest.fn(() => "GUID");
|
||||||
|
|
||||||
|
const expectedLineItemsOnOrder = [1, 2];
|
||||||
|
|
||||||
|
// Act
|
||||||
|
actions.validateOrderPromoAndSaveServerData(context, {
|
||||||
|
payload: {
|
||||||
|
promoCode: promoCode,
|
||||||
|
lineItemsToUse: lineItemsToUse,
|
||||||
|
addableVaps: addableVaps,
|
||||||
|
},
|
||||||
|
pageNameToLog: "test",
|
||||||
|
});
|
||||||
|
const firstCallArgs = globalMethods.callHttpClient.mock.calls[0];
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(firstCallArgs[0].payload.order.lineItemsOnOrder).toEqual(
|
||||||
|
expectedLineItemsOnOrder
|
||||||
|
);
|
||||||
|
});
|
||||||
|
it("should not blow up if an error comes back from the http call", async () => {
|
||||||
|
// Arrange
|
||||||
|
const context = state;
|
||||||
|
const promoCode = "testPromo";
|
||||||
|
const lineItemsToUse = null;
|
||||||
|
const addableVaps = [{ partNumber: "addableVap" }];
|
||||||
|
|
||||||
|
context["getters"] = {
|
||||||
|
order: {
|
||||||
|
serviceLocation: {
|
||||||
|
appointmentType: "test",
|
||||||
|
state: "test",
|
||||||
|
zipCodeCtu: "test",
|
||||||
|
},
|
||||||
|
vehicle: {
|
||||||
|
carId: "test",
|
||||||
|
year: "test",
|
||||||
|
},
|
||||||
|
referralCorrelationId: "test",
|
||||||
|
eon: "test",
|
||||||
|
damage: {
|
||||||
|
isRepair: true,
|
||||||
|
glassToReplace: null,
|
||||||
|
},
|
||||||
|
payment: {
|
||||||
|
parentAccountNumber: "test",
|
||||||
|
},
|
||||||
|
referralSequenceNumber: "test",
|
||||||
|
lineItems: {
|
||||||
|
vaps: [1],
|
||||||
|
promos: [2],
|
||||||
|
serverData: "test",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
globalMethods.callHttpClient = jest.fn(() =>
|
||||||
|
Promise.reject(new Error("Error message"))
|
||||||
|
);
|
||||||
|
|
||||||
|
crypto.randomUUID = jest.fn(() => "GUID");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
try {
|
||||||
|
await actions.validateOrderPromoAndSaveServerData(context, {
|
||||||
|
payload: {
|
||||||
|
promoCode: promoCode,
|
||||||
|
lineItemsToUse: lineItemsToUse,
|
||||||
|
addableVaps: addableVaps,
|
||||||
|
},
|
||||||
|
pageNameToLog: "test",
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
// Assert
|
||||||
|
fail("Unhandled error occurred");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
it("should always save serverData if any is received from the http call", async () => {
|
||||||
|
// Arrange
|
||||||
|
const context = state;
|
||||||
|
const promoCode = "testPromo";
|
||||||
|
const lineItemsToUse = null;
|
||||||
|
const addableVaps = [{ partNumber: "addableVap" }];
|
||||||
|
context.commit = jest.fn(() => {});
|
||||||
|
|
||||||
|
context["getters"] = {
|
||||||
|
order: {
|
||||||
|
serviceLocation: {
|
||||||
|
appointmentType: "test",
|
||||||
|
state: "test",
|
||||||
|
zipCodeCtu: "test",
|
||||||
|
},
|
||||||
|
vehicle: {
|
||||||
|
carId: "test",
|
||||||
|
year: "test",
|
||||||
|
},
|
||||||
|
referralCorrelationId: "test",
|
||||||
|
eon: "test",
|
||||||
|
damage: {
|
||||||
|
isRepair: true,
|
||||||
|
glassToReplace: null,
|
||||||
|
},
|
||||||
|
payment: {
|
||||||
|
parentAccountNumber: "test",
|
||||||
|
},
|
||||||
|
referralSequenceNumber: "test",
|
||||||
|
lineItems: {
|
||||||
|
vaps: [1],
|
||||||
|
promos: [2],
|
||||||
|
serverData: "test",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
globalMethods.callHttpClient = jest.fn().mockResolvedValue({
|
||||||
|
data: { serverData: "serverData" },
|
||||||
|
});
|
||||||
|
|
||||||
|
crypto.randomUUID = jest.fn(() => "GUID");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await actions.validateOrderPromoAndSaveServerData(context, {
|
||||||
|
payload: {
|
||||||
|
promoCode: promoCode,
|
||||||
|
lineItemsToUse: lineItemsToUse,
|
||||||
|
addableVaps: addableVaps,
|
||||||
|
},
|
||||||
|
pageNameToLog: "test",
|
||||||
|
});
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(context.commit).toBeCalledWith(
|
||||||
|
storeMutations.UPDATE_LINE_ITEMS_SERVER_DATA,
|
||||||
|
expect.anything()
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
describe("revalidateOrderPromosAndSaveServerData", () => {
|
||||||
|
it("should add GUIDs if not there to provided vaps before sending the http call", async () => {
|
||||||
|
// Arrange
|
||||||
|
const context = state;
|
||||||
|
context.commit = jest.fn(() => {});
|
||||||
|
|
||||||
|
context["getters"] = {
|
||||||
|
order: {
|
||||||
|
serviceLocation: {
|
||||||
|
appointmentType: "test",
|
||||||
|
state: "test",
|
||||||
|
zipCodeCtu: "test",
|
||||||
|
},
|
||||||
|
vehicle: {
|
||||||
|
carId: "test",
|
||||||
|
year: "test",
|
||||||
|
},
|
||||||
|
referralCorrelationId: "test",
|
||||||
|
eon: "test",
|
||||||
|
damage: {
|
||||||
|
isRepair: true,
|
||||||
|
glassToReplace: null,
|
||||||
|
},
|
||||||
|
payment: {
|
||||||
|
parentAccountNumber: "test",
|
||||||
|
inactivePromos: ["inactiveTest"],
|
||||||
|
},
|
||||||
|
referralSequenceNumber: "test",
|
||||||
|
lineItems: {
|
||||||
|
serverData: "test",
|
||||||
|
promos: [{ promoCode: "test" }],
|
||||||
|
vaps: [{ partNumber: "testVap" }],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
globalMethods.callHttpClient = jest.fn().mockResolvedValue({
|
||||||
|
data: { lineItemsServerData: "testData" },
|
||||||
|
});
|
||||||
|
|
||||||
|
crypto.randomUUID = jest.fn(() => "GUID");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
actions.revalidateOrderPromosAndSaveServerData(context, {
|
||||||
|
payload: {},
|
||||||
|
pageNameToLog: "test",
|
||||||
|
});
|
||||||
|
|
||||||
|
const firstCallArgs = globalMethods.callHttpClient.mock.calls[0];
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
const vapsLineItem = firstCallArgs[0].payload.order.lineItemsOnOrder.filter(
|
||||||
|
(lineItem) => {
|
||||||
|
return lineItem.partNumber == "testVap";
|
||||||
|
}
|
||||||
|
);
|
||||||
|
expect(vapsLineItem[0].id).toEqual("GUID");
|
||||||
|
});
|
||||||
|
it("uses provided parameters in favor of store values", async () => {
|
||||||
|
// Arrange
|
||||||
|
const context = state;
|
||||||
|
context.commit = jest.fn(() => {});
|
||||||
|
|
||||||
|
const activePromosToUse = [{ promoCode: "providedPromo" }];
|
||||||
|
const inactivePromosToUse = ["providedInactivePromo"];
|
||||||
|
const vapsProvided = [{ id: 123 }];
|
||||||
|
const lineItemsToUse = { vaps: vapsProvided };
|
||||||
|
|
||||||
|
context["getters"] = {
|
||||||
|
order: {
|
||||||
|
serviceLocation: {
|
||||||
|
appointmentType: "test",
|
||||||
|
state: "test",
|
||||||
|
zipCodeCtu: "test",
|
||||||
|
},
|
||||||
|
vehicle: {
|
||||||
|
carId: "test",
|
||||||
|
year: "test",
|
||||||
|
},
|
||||||
|
referralCorrelationId: "test",
|
||||||
|
eon: "test",
|
||||||
|
damage: {
|
||||||
|
isRepair: true,
|
||||||
|
glassToReplace: null,
|
||||||
|
},
|
||||||
|
payment: {
|
||||||
|
parentAccountNumber: "test",
|
||||||
|
inactivePromos: ["inactiveTest"],
|
||||||
|
},
|
||||||
|
referralSequenceNumber: "test",
|
||||||
|
lineItems: {
|
||||||
|
serverData: "test",
|
||||||
|
promos: [{ promoCode: "test" }],
|
||||||
|
vaps: [{ partNumber: "testVap" }],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
globalMethods.callHttpClient = jest.fn().mockResolvedValue({
|
||||||
|
data: { lineItemsServerData: "testData" },
|
||||||
|
});
|
||||||
|
|
||||||
|
crypto.randomUUID = jest.fn(() => "GUID");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
actions.revalidateOrderPromosAndSaveServerData(context, {
|
||||||
|
payload: {
|
||||||
|
activePromosToUse: activePromosToUse,
|
||||||
|
inactivePromosToUse: inactivePromosToUse,
|
||||||
|
lineItemsToUse: lineItemsToUse,
|
||||||
|
},
|
||||||
|
pageNameToLog: "test",
|
||||||
|
});
|
||||||
|
|
||||||
|
const firstCallArgs = globalMethods.callHttpClient.mock.calls[0];
|
||||||
|
const expectedInactivePromos = ["providedInactivePromo"];
|
||||||
|
const expectedLineItemsOnOrder = [...vapsProvided, ...activePromosToUse];
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(firstCallArgs[0].payload.inactivePromos).toEqual(expectedInactivePromos);
|
||||||
|
expect(firstCallArgs[0].payload.order.lineItemsOnOrder).toEqual(
|
||||||
|
expectedLineItemsOnOrder
|
||||||
|
);
|
||||||
|
});
|
||||||
|
it("can build a valid payload with store data only", async () => {
|
||||||
|
// Arrange
|
||||||
|
const context = state;
|
||||||
|
context.commit = jest.fn(() => {});
|
||||||
|
|
||||||
|
context["getters"] = {
|
||||||
|
order: {
|
||||||
|
serviceLocation: {
|
||||||
|
appointmentType: "test",
|
||||||
|
state: "test",
|
||||||
|
zipCodeCtu: "test",
|
||||||
|
},
|
||||||
|
vehicle: {
|
||||||
|
carId: "test",
|
||||||
|
year: "test",
|
||||||
|
},
|
||||||
|
referralCorrelationId: "test",
|
||||||
|
eon: "test",
|
||||||
|
damage: {
|
||||||
|
isRepair: true,
|
||||||
|
glassToReplace: null,
|
||||||
|
},
|
||||||
|
payment: {
|
||||||
|
parentAccountNumber: "test",
|
||||||
|
inactivePromos: ["inactiveTest"],
|
||||||
|
},
|
||||||
|
referralSequenceNumber: "test",
|
||||||
|
lineItems: {
|
||||||
|
serverData: "test",
|
||||||
|
promos: [{ promoCode: "test" }],
|
||||||
|
vaps: [{ partNumber: "testVap", id: "providedId" }],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
globalMethods.callHttpClient = jest.fn().mockResolvedValue({
|
||||||
|
data: { lineItemsServerData: "testData" },
|
||||||
|
});
|
||||||
|
|
||||||
|
crypto.randomUUID = jest.fn(() => "GUID");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
actions.revalidateOrderPromosAndSaveServerData(context, {
|
||||||
|
payload: {},
|
||||||
|
pageNameToLog: "test",
|
||||||
|
});
|
||||||
|
|
||||||
|
const expectedLineItemsOnOrder = [
|
||||||
|
...context.getters.order.lineItems.vaps,
|
||||||
|
...context.getters.order.lineItems.promos,
|
||||||
|
];
|
||||||
|
const firstCallArgs = globalMethods.callHttpClient.mock.calls[0];
|
||||||
|
// Assert
|
||||||
|
expect(firstCallArgs[0].payload.inactivePromos).toEqual(
|
||||||
|
context.getters.order.payment.inactivePromos
|
||||||
|
);
|
||||||
|
expect(firstCallArgs[0].payload.order.lineItemsOnOrder).toEqual(
|
||||||
|
expectedLineItemsOnOrder
|
||||||
|
);
|
||||||
|
});
|
||||||
|
it("removes any promos from inactivePromos that are already active before sending the request", async () => {
|
||||||
|
// Arrange
|
||||||
|
const context = state;
|
||||||
|
context.commit = jest.fn(() => {});
|
||||||
|
|
||||||
|
const activePromosToUse = [{ promoCode: "providedPromoDuplicate" }];
|
||||||
|
const inactivePromosToUse = ["providedPromoDuplicate"];
|
||||||
|
const vapsProvided = [{ id: 123 }];
|
||||||
|
const lineItemsToUse = { vaps: vapsProvided };
|
||||||
|
|
||||||
|
context["getters"] = {
|
||||||
|
order: {
|
||||||
|
serviceLocation: {
|
||||||
|
appointmentType: "test",
|
||||||
|
state: "test",
|
||||||
|
zipCodeCtu: "test",
|
||||||
|
},
|
||||||
|
vehicle: {
|
||||||
|
carId: "test",
|
||||||
|
year: "test",
|
||||||
|
},
|
||||||
|
referralCorrelationId: "test",
|
||||||
|
eon: "test",
|
||||||
|
damage: {
|
||||||
|
isRepair: true,
|
||||||
|
glassToReplace: null,
|
||||||
|
},
|
||||||
|
payment: {
|
||||||
|
parentAccountNumber: "test",
|
||||||
|
},
|
||||||
|
referralSequenceNumber: "test",
|
||||||
|
lineItems: {
|
||||||
|
serverData: "test",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
globalMethods.callHttpClient = jest.fn().mockResolvedValue({
|
||||||
|
data: { lineItemsServerData: "testData" },
|
||||||
|
});
|
||||||
|
|
||||||
|
crypto.randomUUID = jest.fn(() => "GUID");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
actions.revalidateOrderPromosAndSaveServerData(context, {
|
||||||
|
payload: {
|
||||||
|
activePromosToUse: activePromosToUse,
|
||||||
|
inactivePromosToUse: inactivePromosToUse,
|
||||||
|
lineItemsToUse: lineItemsToUse,
|
||||||
|
},
|
||||||
|
pageNameToLog: "test",
|
||||||
|
});
|
||||||
|
|
||||||
|
const firstCallArgs = globalMethods.callHttpClient.mock.calls[0];
|
||||||
|
// Assert
|
||||||
|
expect(firstCallArgs[0].payload.inactivePromos).toEqual([]);
|
||||||
|
});
|
||||||
|
it("saves serverData to the store", async () => {
|
||||||
|
// Arrange
|
||||||
|
const context = state;
|
||||||
|
context.commit = jest.fn(() => {});
|
||||||
|
|
||||||
|
const activePromosToUse = [{ promoCode: "providedPromoDuplicate" }];
|
||||||
|
const inactivePromosToUse = ["providedPromoDuplicate"];
|
||||||
|
const vapsProvided = [{ id: 123 }];
|
||||||
|
const lineItemsToUse = { vaps: vapsProvided };
|
||||||
|
|
||||||
|
context["getters"] = {
|
||||||
|
order: {
|
||||||
|
serviceLocation: {
|
||||||
|
appointmentType: "test",
|
||||||
|
state: "test",
|
||||||
|
zipCodeCtu: "test",
|
||||||
|
},
|
||||||
|
vehicle: {
|
||||||
|
carId: "test",
|
||||||
|
year: "test",
|
||||||
|
},
|
||||||
|
referralCorrelationId: "test",
|
||||||
|
eon: "test",
|
||||||
|
damage: {
|
||||||
|
isRepair: true,
|
||||||
|
glassToReplace: null,
|
||||||
|
},
|
||||||
|
payment: {
|
||||||
|
parentAccountNumber: "test",
|
||||||
|
},
|
||||||
|
referralSequenceNumber: "test",
|
||||||
|
lineItems: {
|
||||||
|
serverData: "test",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
globalMethods.callHttpClient = jest.fn().mockResolvedValue({
|
||||||
|
data: { lineItemsServerData: "testData" },
|
||||||
|
});
|
||||||
|
|
||||||
|
crypto.randomUUID = jest.fn(() => "GUID");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await actions.revalidateOrderPromosAndSaveServerData(context, {
|
||||||
|
payload: {
|
||||||
|
activePromosToUse: activePromosToUse,
|
||||||
|
inactivePromosToUse: inactivePromosToUse,
|
||||||
|
lineItemsToUse: lineItemsToUse,
|
||||||
|
},
|
||||||
|
pageNameToLog: "test",
|
||||||
|
});
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(context.commit).toBeCalledWith(
|
||||||
|
storeMutations.UPDATE_LINE_ITEMS_SERVER_DATA,
|
||||||
|
expect.anything()
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("Getters", () => {
|
describe("Getters", () => {
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@
|
||||||
<textLink
|
<textLink
|
||||||
linkType="text"
|
linkType="text"
|
||||||
:text="getRouterLinkDisplayTextFromCopy(copy)"
|
:text="getRouterLinkDisplayTextFromCopy(copy)"
|
||||||
href="#!"
|
href="javascript:void(0)"
|
||||||
@click-event="
|
@click-event="
|
||||||
$emit('textLinkClicked', getRouterLinkRouteFromCopy(copy))
|
$emit('textLinkClicked', getRouterLinkRouteFromCopy(copy))
|
||||||
"
|
"
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue