Merge branch 'develop' into feature/jnou/more-fixes-playwright
This commit is contained in:
commit
f4b4e6e863
7 changed files with 164 additions and 43 deletions
|
|
@ -165,8 +165,9 @@ export function getCartTotal(order) {
|
|||
export function getRecalibrationTotal(order) {
|
||||
const itemsWithRecalibration = getServiceLineItems(order)
|
||||
.filter((item) => item.requiresRecalibration);
|
||||
const recalibrationLineItems = itemsWithRecalibration.map((item) => {
|
||||
return item.childParts?.find((child) => child.partType === partTypeStrings.RECALIBRATION || child.partType === partTypeStrings.ADAS_RECALIBRATION) ?? {};
|
||||
|
||||
const recalibrationLineItems = itemsWithRecalibration.flatMap((item) => {
|
||||
return item.childParts?.filter((child) => child.partType === partTypeStrings.RECALIBRATION || child.partType === partTypeStrings.ADAS_RECALIBRATION) ?? [];
|
||||
});
|
||||
|
||||
return getPriceOfLineItems(recalibrationLineItems);
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import {
|
|||
getDeductible,
|
||||
getLineItems,
|
||||
getMobileFeeLineItem, getNonServiceLineItems,
|
||||
getRecalibrationTotal,
|
||||
getRecycleFeeLineItem, getSalesTax,
|
||||
getServiceLineItems, getSubtotal, isOrderITAC, isOrderNoComp,
|
||||
isOrderUnverified
|
||||
|
|
@ -25,7 +26,7 @@ describe('cart-helper', () => {
|
|||
};
|
||||
}
|
||||
|
||||
function createDummyFeeItem(partNumber, partType, price, salesTax) {
|
||||
function createDummyItemWithPartType(partNumber, partType, price, salesTax) {
|
||||
return {
|
||||
partNumber,
|
||||
partType,
|
||||
|
|
@ -56,8 +57,8 @@ describe('cart-helper', () => {
|
|||
const glassLineItem = createDummyItem('glass', 40, 2);
|
||||
const otherLineItem = createDummyItem('other', 50, 3);
|
||||
const vapsLineItem = createDummyItem('vaps', 60, 4);
|
||||
const mobileFeeLineItem = createDummyFeeItem(null, partTypeStrings.MOBILE_FEE, 70, 5);
|
||||
const recycleFeeLineItem = createDummyFeeItem(partNumberStrings.RECYCLE_FEE, null, 80, 6);
|
||||
const mobileFeeLineItem = createDummyItemWithPartType(null, partTypeStrings.MOBILE_FEE, 70, 5);
|
||||
const recycleFeeLineItem = createDummyItemWithPartType(partNumberStrings.RECYCLE_FEE, null, 80, 6);
|
||||
|
||||
const defaultLineItems = {
|
||||
supportingItems: [supportingLineItem],
|
||||
|
|
@ -592,4 +593,99 @@ describe('cart-helper', () => {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('getRecalibrationTotal', () => {
|
||||
test('Returns total price of recalibration items when there is only 1', () => {
|
||||
// Arrange
|
||||
const recalibrationItem = createDummyItemWithPartType('recal', partTypeStrings.RECALIBRATION, 25, 2);
|
||||
const lineItemWithRecal = {
|
||||
...glassLineItem,
|
||||
requiresRecalibration: true,
|
||||
childParts: [recalibrationItem]
|
||||
};
|
||||
const order = {
|
||||
lineItems: {
|
||||
...defaultLineItems,
|
||||
glassParts: [lineItemWithRecal]
|
||||
}
|
||||
};
|
||||
|
||||
// Act
|
||||
const result = getRecalibrationTotal(order);
|
||||
|
||||
// Assert
|
||||
expect(result).toBe(25);
|
||||
});
|
||||
test('Returns total price of recalibration items when there are multiple', () => {
|
||||
// Arrange
|
||||
const recalibrationItem = createDummyItemWithPartType('recal', partTypeStrings.RECALIBRATION, 25, 2);
|
||||
const thirdRecalibrationItem = createDummyItemWithPartType('third-recal', partTypeStrings.ADAS_RECALIBRATION, 35, 3);
|
||||
const lineItemWithRecal = {
|
||||
...glassLineItem,
|
||||
requiresRecalibration: true,
|
||||
childParts: [recalibrationItem, thirdRecalibrationItem]
|
||||
};
|
||||
const order = {
|
||||
lineItems: {
|
||||
...defaultLineItems,
|
||||
glassParts: [lineItemWithRecal]
|
||||
}
|
||||
};
|
||||
|
||||
// Act
|
||||
const result = getRecalibrationTotal(order);
|
||||
|
||||
// Assert
|
||||
expect(result).toBe(60);
|
||||
});
|
||||
|
||||
test('Returns 0 when no items require recalibration', () => {
|
||||
// Arrange
|
||||
const order = {
|
||||
lineItems: defaultLineItems
|
||||
};
|
||||
|
||||
// Act
|
||||
const result = getRecalibrationTotal(order);
|
||||
|
||||
// Assert
|
||||
expect(result).toBe(0);
|
||||
});
|
||||
|
||||
test('Returns 0 when line items are null', () => {
|
||||
// Arrange
|
||||
const order = {
|
||||
lineItems: nullLineItems
|
||||
};
|
||||
|
||||
// Act
|
||||
const result = getRecalibrationTotal(order);
|
||||
|
||||
// Assert
|
||||
expect(result).toBe(0);
|
||||
});
|
||||
|
||||
test('Filters out non-recalibration child parts', () => {
|
||||
// Arrange
|
||||
const recalibrationItem = createDummyItemWithPartType('recal', partTypeStrings.RECALIBRATION, 25, 2);
|
||||
const otherChildItem = createDummyItem('other-child', 15, 1);
|
||||
const lineItemWithRecal = {
|
||||
...glassLineItem,
|
||||
requiresRecalibration: true,
|
||||
childParts: [recalibrationItem, otherChildItem]
|
||||
};
|
||||
const order = {
|
||||
lineItems: {
|
||||
...defaultLineItems,
|
||||
glassParts: [lineItemWithRecal]
|
||||
}
|
||||
};
|
||||
|
||||
// Act
|
||||
const result = getRecalibrationTotal(order);
|
||||
|
||||
// Assert
|
||||
expect(result).toBe(25);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -60,6 +60,10 @@
|
|||
<div
|
||||
class="body-text"
|
||||
v-html="nextStepsBody"></div>
|
||||
<textBlock
|
||||
v-if="MAPolicy"
|
||||
cmsWidgetName="MASteeringText">
|
||||
</textBlock>
|
||||
<div
|
||||
v-if="isNoCompQuoteVisible"
|
||||
class="no-comp-price-text">
|
||||
|
|
@ -357,6 +361,9 @@ export default {
|
|||
return this.isITACQuoteVisible
|
||||
|| this.isNoCompQuoteVisible
|
||||
|| (this.showDeductibleOnly && this.deductibleValue > 0);
|
||||
},
|
||||
MAPolicy() {
|
||||
return useMainStore().customerData.addressQuestions.state === "MA";
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
|
|
|
|||
|
|
@ -7,7 +7,8 @@ import {
|
|||
regenerateUserId,
|
||||
regenerateDeviceId,
|
||||
setSessionIdIfUnset,
|
||||
setSessionKeyIfUnset
|
||||
setSessionKeyIfUnset,
|
||||
updateSessionIdCookie
|
||||
} from '@/helpers/cookie-helper';
|
||||
import applicationConfig from '@/constants/application-config';
|
||||
import queryStrings from '@/constants/query-strings';
|
||||
|
|
@ -52,12 +53,25 @@ export default {
|
|||
}
|
||||
return '';
|
||||
},
|
||||
logPageView(pageEvent) {
|
||||
async validateSession() {
|
||||
const emptySessionId = '00000000-0000-0000-0000-000000000000';
|
||||
|
||||
if (this.noSession()) {
|
||||
await this.initSession();
|
||||
}
|
||||
|
||||
const sessionId = getSessionIdValue();
|
||||
if (sessionId && sessionId !== emptySessionId) {
|
||||
updateSessionIdCookie();
|
||||
}
|
||||
},
|
||||
async logPageView(pageEvent) {
|
||||
const store = useMainStore();
|
||||
const currentPageName = this.getPageNameByQueryString();
|
||||
//await this.validateSession();
|
||||
|
||||
const payload = {
|
||||
userId: getDeviceIdValue(),
|
||||
userId: getUserIdValue(),
|
||||
sessionKey: getSessionKeyValue(),
|
||||
pageName: currentPageName,
|
||||
referralSequenceNumber: store.order.referralSequenceNumber,
|
||||
|
|
@ -69,15 +83,16 @@ export default {
|
|||
experimentsForUser: store.applicationUser.experiments
|
||||
};
|
||||
|
||||
store.logPageView(payload);
|
||||
await store.logPageView(payload);
|
||||
},
|
||||
|
||||
logCustomEvent(category, action, label, value) {
|
||||
async logCustomEvent(category, action, label, value) {
|
||||
const store = useMainStore();
|
||||
const currentPageName = this.getPageNameByQueryString();
|
||||
//await this.validateSession();
|
||||
|
||||
const payload = {
|
||||
userId: getDeviceIdValue(),
|
||||
userId: getUserIdValue(),
|
||||
sessionKey: getSessionKeyValue(),
|
||||
pageName: currentPageName,
|
||||
referralSequenceNumber: store.order.referralSequenceNumber,
|
||||
|
|
@ -91,9 +106,9 @@ export default {
|
|||
experimentsForUser: store.applicationUser.experiments
|
||||
};
|
||||
|
||||
store.logCustomEvent(payload);
|
||||
await store.logCustomEvent(payload);
|
||||
},
|
||||
pushEventToGA(category, action, label, pushToLogApp = false, valueToLogType = null, value = undefined) {
|
||||
async pushEventToGA(category, action, label, pushToLogApp = false, valueToLogType = null, value = undefined) {
|
||||
const currentPageName = this.getPageNameByQueryString();
|
||||
const labelToLog = getValueToLog(label, valueToLogType);
|
||||
|
||||
|
|
@ -109,14 +124,14 @@ export default {
|
|||
pushToDataLayerIfDefined(eventToBePushed);
|
||||
|
||||
if (pushToLogApp) {
|
||||
this.logCustomEvent(category, action, labelToLog, value);
|
||||
await this.logCustomEvent(category, action, labelToLog, value);
|
||||
}
|
||||
},
|
||||
pushGenericObjectToGA(object) {
|
||||
pushToDataLayerIfDefined(object);
|
||||
},
|
||||
|
||||
pushPageViewToGA() {
|
||||
async pushPageViewToGA() {
|
||||
const currentPageName = this.getPageNameByQueryString();
|
||||
const pageViewEvent = {
|
||||
event: GaEvents.PAGE_VIEW_EVENT,
|
||||
|
|
@ -126,7 +141,7 @@ export default {
|
|||
|
||||
pushToDataLayerIfDefined(pageViewEvent);
|
||||
|
||||
this.logPageView(analyticsPageEvents.ENTRY);
|
||||
await this.logPageView(analyticsPageEvents.ENTRY);
|
||||
},
|
||||
|
||||
pushOrderToDataLayer() {
|
||||
|
|
@ -533,6 +548,7 @@ export default {
|
|||
},
|
||||
|
||||
async initSession() {
|
||||
|
||||
regenerateDeviceId();
|
||||
regenerateUserId();
|
||||
|
||||
|
|
|
|||
|
|
@ -8,29 +8,32 @@ import {
|
|||
ValueToLogTypes
|
||||
} from '@/constants/analytics';
|
||||
import { useMainStore } from '@/store';
|
||||
import crypto from 'crypto';
|
||||
|
||||
global.crypto = crypto;
|
||||
|
||||
describe('analyticsMixin.js', () => {
|
||||
test('logPageView: calls dispatch with type and payload', () => {
|
||||
test('logPageView: calls dispatch with type and payload', async () => {
|
||||
const payload = {};
|
||||
|
||||
const testCookieValue = {
|
||||
sid: '10000000-0000-0000-0000-000000000001'
|
||||
};
|
||||
|
||||
setupCookies({ funnelCookieValue: JSON.stringify(testCookieValue) });
|
||||
setupCookies({ ISSCookieValue: JSON.stringify(testCookieValue) });
|
||||
|
||||
useMainStore().logPageView(payload);
|
||||
await analyticsMixin.methods.logPageView(payload);
|
||||
|
||||
expect(useMainStore().logPageView).toBeCalled();
|
||||
});
|
||||
|
||||
test('logCustomEvent: calls dispatch with type and payload', () => {
|
||||
useMainStore().logCustomEvent('someCat', 'someAction', 'someLabel', 'someVal');
|
||||
test('logCustomEvent: calls dispatch with type and payload', async () => {
|
||||
await analyticsMixin.methods.logCustomEvent('someCat', 'someAction', 'someLabel', 'someVal');
|
||||
|
||||
expect(useMainStore().logCustomEvent).toBeCalled();
|
||||
});
|
||||
|
||||
test('pushEventToGA, should call dataLayer push and logCustomEvent too', () => {
|
||||
test('pushEventToGA, should call dataLayer push and logCustomEvent too', async () => {
|
||||
// Arrange
|
||||
window.dataLayer = [];
|
||||
const mockDataLayer = [];
|
||||
|
|
@ -44,13 +47,13 @@ describe('analyticsMixin.js', () => {
|
|||
});
|
||||
|
||||
// Act
|
||||
analyticsMixin.methods.pushEventToGA('category', 'action', 'label', true);
|
||||
await analyticsMixin.methods.pushEventToGA('category', 'action', 'label', true);
|
||||
|
||||
// Assert
|
||||
expect(mockDataLayer).toEqual(expect.arrayContaining(window.dataLayer));
|
||||
});
|
||||
|
||||
test('pushEventToGA, should call dataLayer push and ValueToLogTypes.LAST_5 only logs last 5 of label', () => {
|
||||
test('pushEventToGA, should call dataLayer push and ValueToLogTypes.LAST_5 only logs last 5 of label', async () => {
|
||||
// Arrange
|
||||
window.dataLayer = [];
|
||||
const expectedDataLayer = [];
|
||||
|
|
@ -64,7 +67,7 @@ describe('analyticsMixin.js', () => {
|
|||
});
|
||||
|
||||
// Act
|
||||
analyticsMixin.methods.pushEventToGA(
|
||||
await analyticsMixin.methods.pushEventToGA(
|
||||
'category',
|
||||
'action',
|
||||
'1111122222333333',
|
||||
|
|
@ -76,7 +79,7 @@ describe('analyticsMixin.js', () => {
|
|||
expect(expectedDataLayer).toEqual(expect.arrayContaining(window.dataLayer));
|
||||
});
|
||||
|
||||
test('pushEventToGA, should call dataLayer push and ValueToLogTypes.LAST_5 logs only the last 3 characters for a 3 character string', () => {
|
||||
test('pushEventToGA, should call dataLayer push and ValueToLogTypes.LAST_5 logs only the last 3 characters for a 3 character string', async () => {
|
||||
// Arrange
|
||||
window.dataLayer = [];
|
||||
const expectedDataLayer = [];
|
||||
|
|
@ -90,7 +93,7 @@ describe('analyticsMixin.js', () => {
|
|||
});
|
||||
|
||||
// Act
|
||||
analyticsMixin.methods.pushEventToGA(
|
||||
await analyticsMixin.methods.pushEventToGA(
|
||||
'category',
|
||||
'action',
|
||||
'111',
|
||||
|
|
|
|||
|
|
@ -35,14 +35,10 @@ const routes = [
|
|||
return await GoToAccessIsDenied(next);
|
||||
}
|
||||
|
||||
await analyticsMixin.methods.validateSession();
|
||||
|
||||
// Do not run these for the main entry page - as it is not part of the user flow.
|
||||
if (issPageToUse !== issPageValues.ENTRY_PAGE) {
|
||||
if (analyticsMixin.methods.noSession()) {
|
||||
await analyticsMixin.methods.initSession();
|
||||
} else {
|
||||
updateSessionIdCookie();
|
||||
}
|
||||
|
||||
try {
|
||||
await runExperiments(issPageToUse);
|
||||
} catch (error) {
|
||||
|
|
|
|||
|
|
@ -1120,7 +1120,7 @@ export const useMainStore = defineStore({
|
|||
.then((response) => {
|
||||
const recalResponse = response.data;
|
||||
if (recalResponse && recalResponse.recalibrationParts && recalResponse.recalibrationParts.length > 0) {
|
||||
this.addGlassPartRecalibrationInfo(partNumberChecked, recalResponse.recalibrationParts[0]);
|
||||
this.addGlassPartRecalibrationInfo(partNumberChecked, recalResponse.recalibrationParts);
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
|
@ -1128,15 +1128,17 @@ export const useMainStore = defineStore({
|
|||
await Promise.allSettled(recalPromises);
|
||||
}
|
||||
},
|
||||
addGlassPartRecalibrationInfo(partNumber, recalPartInformation) {
|
||||
addGlassPartRecalibrationInfo(partNumber, recalPartArray) {
|
||||
const glassPart = this.lineItems.glassParts.find((gp) => gp.partNumber === partNumber);
|
||||
if (glassPart) {
|
||||
const recalChildPart = glassPart.childParts?.find((cp) => cp.partNumber === recalPartInformation.partNumber);
|
||||
if (!recalChildPart) {
|
||||
if (!Array.isArray(glassPart.childParts) || !glassPart.childParts.length) {
|
||||
glassPart.childParts = [];
|
||||
for (const recalPartInformation of recalPartArray) {
|
||||
const recalChildPart = glassPart.childParts?.find((cp) => cp.partNumber === recalPartInformation.partNumber);
|
||||
if (!recalChildPart) {
|
||||
if (!Array.isArray(glassPart.childParts) || !glassPart.childParts.length) {
|
||||
glassPart.childParts = [];
|
||||
}
|
||||
glassPart.childParts.push(recalPartInformation);
|
||||
}
|
||||
glassPart.childParts.push(recalPartInformation);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
@ -2560,7 +2562,7 @@ export const useMainStore = defineStore({
|
|||
});
|
||||
}
|
||||
},
|
||||
logPageView({ userId, sessionKey, pageName, referralSequenceNumber, parentAccountNumber, sessionId, action, event, shouldUseSessionId, experimentsForUser }) {
|
||||
async logPageView({ userId, sessionKey, pageName, referralSequenceNumber, parentAccountNumber, sessionId, action, event, shouldUseSessionId, experimentsForUser }) {
|
||||
const payload = {
|
||||
userId,
|
||||
sessionKey,
|
||||
|
|
@ -2588,7 +2590,7 @@ export const useMainStore = defineStore({
|
|||
}
|
||||
);
|
||||
},
|
||||
logCustomEvent({ userId, sessionKey, pageName, sessionId, category, action, label, value, shouldUseSessionId, experimentsForUser }) {
|
||||
async logCustomEvent({ userId, sessionKey, pageName, sessionId, category, action, label, value, shouldUseSessionId, experimentsForUser }) {
|
||||
if (pageName == null || pageName.length === 0) { pageName = 'none'; }
|
||||
|
||||
const payload = {
|
||||
|
|
@ -2625,7 +2627,7 @@ export const useMainStore = defineStore({
|
|||
this.logExperimentIfExists(issPage, experimentUniverses.ISS_FEATURETOGGLE_AREFEES_HIDDEN);
|
||||
this.logExperimentIfExists(issPage, experimentUniverses.ISS_FEATURETOGGLE_AREFEES_OVERRIDDEN);
|
||||
},
|
||||
initializeSession({ userId, sessionId, userAgent, referrer }) {
|
||||
async initializeSession({ userId, sessionId, userAgent, referrer }) {
|
||||
const payload = {
|
||||
applicationName: applicationConfig.APPLICATION_NAME,
|
||||
userId,
|
||||
|
|
|
|||
Loading…
Reference in a new issue