From 9500337421aff33f0cea892526e776827062912d Mon Sep 17 00:00:00 2001
From: Matt Sykes
Date: Thu, 30 Nov 2023 15:34:50 -0500
Subject: [PATCH 01/36] Make separate analytics APPLICATION_NAME
---
src/constants/application-config.js | 1 +
src/store/index.js | 6 +++---
2 files changed, 4 insertions(+), 3 deletions(-)
diff --git a/src/constants/application-config.js b/src/constants/application-config.js
index b5233d170..1e2324ba7 100644
--- a/src/constants/application-config.js
+++ b/src/constants/application-config.js
@@ -6,6 +6,7 @@ const applicationConfig = {
COOKIE_PATH: "/",
CURRENT_ENVIRONMENT: process.env.VUE_APP_CURRENT_ENVIRONMENT, // "Localhost", "Dev", "QA", and "Prod"
APPLICATION_NAME: "FixMyGlass",
+ ANALYTICS_APPLICATION_NAME: "FixMyGlassNextGen",
APPLICATION_ABBREVIATION: "fmg",
PAGE_QUERYSTRING: "fmgPage",
SITE_ENTRY_TRIGGER_VALUE: "FixMyGlass",
diff --git a/src/store/index.js b/src/store/index.js
index efaf5b428..684ca83e1 100644
--- a/src/store/index.js
+++ b/src/store/index.js
@@ -1076,7 +1076,7 @@ export const actions = {
sessionKey: sessionKey,
sessionId: sessionId,
pageName: pageName,
- applicationName: applicationConfig.APPLICATION_NAME,
+ applicationName: applicationConfig.ANALYTICS_APPLICATION_NAME,
action: action,
event: event,
shouldUseSessionId: shouldUseSessionId,
@@ -1124,7 +1124,7 @@ export const actions = {
sessionKey: sessionKey,
sessionId: sessionId,
pageName: pageName,
- applicationName: applicationConfig.APPLICATION_NAME,
+ applicationName: applicationConfig.ANALYTICS_APPLICATION_NAME,
category: category,
action: action,
label: label,
@@ -1153,7 +1153,7 @@ export const actions = {
},
initializeSession(context, { userId, sessionId, userAgent, referrer }) {
var payload = {
- applicationName: applicationConfig.APPLICATION_NAME,
+ applicationName: applicationConfig.ANALYTICS_APPLICATION_NAME,
userId: userId,
deviceId: userId,
sessionId: sessionId,
From a79a3204841152a2d1b859ac16e3e8f8b1cee25c Mon Sep 17 00:00:00 2001
From: Chloe Herd
Date: Thu, 30 Nov 2023 16:28:20 -0500
Subject: [PATCH 02/36] Add new cookie ids
---
src/constants/cookie-names.js | 3 +++
1 file changed, 3 insertions(+)
diff --git a/src/constants/cookie-names.js b/src/constants/cookie-names.js
index 5fab52899..0d8d0b05f 100644
--- a/src/constants/cookie-names.js
+++ b/src/constants/cookie-names.js
@@ -3,6 +3,9 @@ import { applicationConfig } from "@/constants/application-config.js";
const cookieNames = {
FUNNEL_SESSION_INFO: `FunnelSessionInfo-${applicationConfig.CURRENT_ENVIRONMENT}`,
+ FUNNEL_SESSION_KEY: `FunnelSessionKey-${applicationConfig.CURRENT_ENVIRONMENT}`,
+ FUNNEL_USER_ID: `FunnelUserId-${applicationConfig.CURRENT_ENVIRONMENT}`,
+
// Existing Safelite.com cookies
DXDEV: "dxdev",
SESSION_ID: "sid",
From edd8158148035e00b08632f72acd27b38e654511 Mon Sep 17 00:00:00 2001
From: Chloe Herd
Date: Thu, 30 Nov 2023 17:35:21 -0500
Subject: [PATCH 03/36] Iteration 1
---
src/constants/cookie-names.js | 2 +-
.../heritage-integration/cookie-helper.js | 24 +++-
src/mixins/analytics-mixin.js | 125 +++++++++++++++---
3 files changed, 128 insertions(+), 23 deletions(-)
diff --git a/src/constants/cookie-names.js b/src/constants/cookie-names.js
index 0d8d0b05f..bf6bc130a 100644
--- a/src/constants/cookie-names.js
+++ b/src/constants/cookie-names.js
@@ -5,7 +5,7 @@ const cookieNames = {
FUNNEL_SESSION_KEY: `FunnelSessionKey-${applicationConfig.CURRENT_ENVIRONMENT}`,
FUNNEL_USER_ID: `FunnelUserId-${applicationConfig.CURRENT_ENVIRONMENT}`,
-
+
// Existing Safelite.com cookies
DXDEV: "dxdev",
SESSION_ID: "sid",
diff --git a/src/helpers/heritage-integration/cookie-helper.js b/src/helpers/heritage-integration/cookie-helper.js
index 1ef43bff0..71a1051f2 100644
--- a/src/helpers/heritage-integration/cookie-helper.js
+++ b/src/helpers/heritage-integration/cookie-helper.js
@@ -82,7 +82,7 @@ export function getDeviceIdValue() {
Gets value of skey cookie, returns 0 if not found.
*/
export function getSessionKeyValue() {
- const cookieValue = getCookieValueByName(cookieNames.SESSION_KEY);
+ const cookieValue = getCookieValueByName(cookieNames.FUNNEL_SESSION_KEY);
if (cookieValue) {
return cookieValue;
@@ -111,6 +111,16 @@ export function updateSessionIdCookie() {
createOrUpdateCookie(cookieNames.SESSION_ID, getSessionIdValue(), { maxAge: 60 * 30 });
}
+export function getUserIdValue() {
+ const cookieValue = getCookieValueByName(cookieNames.FUNNEL_USER_ID);
+
+ if(cookieValue) {
+ return cookieValue;
+ }
+
+ return "00000000-0000-0000-0000-000000000000";
+}
+
export function setCookieProperties(
properties,
{ useDefaultFunnelCookieAttributes = true, maxAge, isSecure }
@@ -126,6 +136,18 @@ export function setCookieProperties(
}
}
+export function isCookieSet(name) {
+ const val = getCookieValueByName(name);
+
+ return !!val;
+}
+
+export function refreshCookieExpiration(name, expirationTime) {
+ if (isCookieSet(name)) {
+ createOrUpdateCookie(name, getCookieValueByName(name), { maxAge: expirationTime });
+ }
+}
+
/*
===========================
= PRIVATE FUNCTIONS =
diff --git a/src/mixins/analytics-mixin.js b/src/mixins/analytics-mixin.js
index 37615f68b..65c77c44e 100644
--- a/src/mixins/analytics-mixin.js
+++ b/src/mixins/analytics-mixin.js
@@ -4,6 +4,9 @@ import {
getDeviceIdValue,
getSessionIdValue,
getSessionKeyValue,
+ getUserIdValue,
+ isCookieSet,
+ refreshCookieExpiration,
} from "@/helpers/heritage-integration/cookie-helper";
import { queryStrings } from "@/constants/query-strings";
import { experimentSettings } from "@/constants/experiments";
@@ -135,39 +138,102 @@ export default {
};
},
- async initSession() {
- const sid = getSessionIdValue();
- const skey = getSessionKeyValue();
- const referrer =
- applicationConfig.CURRENT_ENVIRONMENT != "Localhost" ? document.referrer : null;
+ // async initSession() {
+ // const sid = getSessionIdValue();
+ // const skey = getSessionKeyValue();
+ // const referrer =
+ // applicationConfig.CURRENT_ENVIRONMENT != "Localhost" ? document.referrer : null;
- var payload = {
- userId: getDeviceIdValue(),
- sessionId: sid,
- userAgent: navigator.userAgent,
- referrer: referrer,
+ // var payload = {
+ // userId: getDeviceIdValue(),
+ // sessionId: sid,
+ // userAgent: navigator.userAgent,
+ // referrer: referrer,
+ // };
+
+ // const response = await baseMixin.methods.dispatchStoreAction(
+ // storeActions.INITIALIZE_SESSION,
+ // payload,
+ // false
+ // );
+
+ // if (response?.data) {
+ // if (response?.data.sessionKey && skey === 0) {
+ // setCookieProperties(
+ // { [cookieNames.SESSION_KEY]: response?.data.sessionKey },
+ // {
+ // useDefaultFunnelCookieAttributes: false,
+ // }
+ // );
+ // }
+ // if (response?.data.sessionId && sid === "00000000-0000-0000-0000-000000000000") {
+ // setCookieProperties(
+ // { [cookieNames.SESSION_ID]: response?.data.sessionId },
+ // {
+ // maxAge: 60 * 30, // 30 minutes
+ // }
+ // );
+ // }
+ // }
+ // },
+
+ async initSession() {
+ if (!isCookieSet(cookieNames.FUNNEL_USER_ID)) {
+ setCookieProperties(
+ {
+ [cookieNames.FUNNEL_USER_ID]: crypto.randomUUID(),
+ },
+ { maxAge: 7 * 24 * 60 * 60 }
+ );
+ }
+ if (!isCookieSet(cookieNames.DXDEV)) {
+ setCookieProperties(
+ {
+ [cookieNames.DXDEV]: crypto.randomUUID(),
+ },
+ { maxAge: 365 * 24 * 60 * 60 }
+ );
+ }
+
+ const userId = getUserIdValue(); // cookieNames.FUNNEL_USER_ID
+ const deviceId = getDeviceIdValue(); // cookieNames.DXDEV
+ const sessionId = getSessionIdValue(); // cookieNames.SESSION_ID
+ const userAgent = navigator.userAgent; // navigator.userAgent
+ const refferer = applicationConfig.CURRENT_ENVIRONMENT != "Localhost" ? document.referrer : null; // see above
+
+ const payload = {
+ userId: userId,
+ deviceId: deviceId,
+ sessionId: sessionId,
+ userAgent: userAgent,
+ refferer: refferer,
};
- const response = await baseMixin.methods.dispatchStoreAction(
+ const response = await baseMixin.dispatchStoreAction(
storeActions.INITIALIZE_SESSION,
payload,
false
);
- if (response?.data) {
- if (response?.data.sessionKey && skey === 0) {
+ if(response?.data) {
+ if(response.data.sessionKey && !isCookieSet(cookieNames.FUNNEL_SESSION_KEY)) {
setCookieProperties(
- { [cookieNames.SESSION_KEY]: response?.data.sessionKey },
{
- useDefaultFunnelCookieAttributes: false,
+ [cookieNames.FUNNEL_SESSION_KEY]: response.data.sessionKey,
+ },
+ {
+ maxAge: 30 * 60
}
);
}
- if (response?.data.sessionId && sid === "00000000-0000-0000-0000-000000000000") {
+
+ if(response.data.sessionId && !isCookieSet(cookieNames.SESSION_ID)) {
setCookieProperties(
- { [cookieNames.SESSION_ID]: response?.data.sessionId },
{
- maxAge: 60 * 30, // 30 minutes
+ [cookieNames.SESSION_ID]: response.data.sessionId
+ },
+ {
+ maxAge: 30 * 60
}
);
}
@@ -175,12 +241,29 @@ export default {
},
noSession() {
- return (
- getSessionKeyValue() === 0 ||
- getSessionIdValue() === "00000000-0000-0000-0000-000000000000"
+ return !(
+ isCookieSet(cookieNames.SESSION_ID) &&
+ isCookieSet(cookieNames.DXDEV) &&
+ isCookieSet(cookieNames.FUNNEL_SESSION_KEY) &&
+ isCookieSet(cookieNames.FUNNEL_USER_ID)
);
},
+ async validateSession() {
+ if (this.noSession()) {
+ await this.initSession();
+ }
+
+ this.refreshSessionExpiration();
+ },
+
+ refreshSessionExpiration() {
+ refreshCookieExpiration(cookieNames.SESSION_ID, 30 * 60);
+ refreshCookieExpiration(cookieNames.DXDEV, 365 * 24 * 60 * 60);
+ refreshCookieExpiration(cookieNames.FUNNEL_USER_ID, 7 * 24 * 60 * 60);
+ refreshCookieExpiration(cookieNames.FUNNEL_SESSION_KEY, 30 * 60);
+ },
+
removeParamsFromEndpoint(endpoint) {
const endpointWithoutParams = endpoint.split("?")[0];
const numSlashesBeforeParams = 6;
From 4510241bddc75abffb2f91b5f2944c1b955169aa Mon Sep 17 00:00:00 2001
From: Chloe Herd
Date: Fri, 1 Dec 2023 08:12:19 -0500
Subject: [PATCH 04/36] Cleanup
---
.../heritage-integration/cookie-helper.js | 2 +-
src/mixins/analytics-mixin.js | 56 +++----------------
src/router/index.js | 6 +-
3 files changed, 11 insertions(+), 53 deletions(-)
diff --git a/src/helpers/heritage-integration/cookie-helper.js b/src/helpers/heritage-integration/cookie-helper.js
index 71a1051f2..1e1db1f1e 100644
--- a/src/helpers/heritage-integration/cookie-helper.js
+++ b/src/helpers/heritage-integration/cookie-helper.js
@@ -114,7 +114,7 @@ export function updateSessionIdCookie() {
export function getUserIdValue() {
const cookieValue = getCookieValueByName(cookieNames.FUNNEL_USER_ID);
- if(cookieValue) {
+ if (cookieValue) {
return cookieValue;
}
diff --git a/src/mixins/analytics-mixin.js b/src/mixins/analytics-mixin.js
index 65c77c44e..f793f4825 100644
--- a/src/mixins/analytics-mixin.js
+++ b/src/mixins/analytics-mixin.js
@@ -138,45 +138,6 @@ export default {
};
},
- // async initSession() {
- // const sid = getSessionIdValue();
- // const skey = getSessionKeyValue();
- // const referrer =
- // applicationConfig.CURRENT_ENVIRONMENT != "Localhost" ? document.referrer : null;
-
- // var payload = {
- // userId: getDeviceIdValue(),
- // sessionId: sid,
- // userAgent: navigator.userAgent,
- // referrer: referrer,
- // };
-
- // const response = await baseMixin.methods.dispatchStoreAction(
- // storeActions.INITIALIZE_SESSION,
- // payload,
- // false
- // );
-
- // if (response?.data) {
- // if (response?.data.sessionKey && skey === 0) {
- // setCookieProperties(
- // { [cookieNames.SESSION_KEY]: response?.data.sessionKey },
- // {
- // useDefaultFunnelCookieAttributes: false,
- // }
- // );
- // }
- // if (response?.data.sessionId && sid === "00000000-0000-0000-0000-000000000000") {
- // setCookieProperties(
- // { [cookieNames.SESSION_ID]: response?.data.sessionId },
- // {
- // maxAge: 60 * 30, // 30 minutes
- // }
- // );
- // }
- // }
- // },
-
async initSession() {
if (!isCookieSet(cookieNames.FUNNEL_USER_ID)) {
setCookieProperties(
@@ -199,7 +160,8 @@ export default {
const deviceId = getDeviceIdValue(); // cookieNames.DXDEV
const sessionId = getSessionIdValue(); // cookieNames.SESSION_ID
const userAgent = navigator.userAgent; // navigator.userAgent
- const refferer = applicationConfig.CURRENT_ENVIRONMENT != "Localhost" ? document.referrer : null; // see above
+ const refferer =
+ applicationConfig.CURRENT_ENVIRONMENT != "Localhost" ? document.referrer : null; // see above
const payload = {
userId: userId,
@@ -209,31 +171,31 @@ export default {
refferer: refferer,
};
- const response = await baseMixin.dispatchStoreAction(
+ const response = await baseMixin.methods.dispatchStoreAction(
storeActions.INITIALIZE_SESSION,
payload,
false
);
- if(response?.data) {
- if(response.data.sessionKey && !isCookieSet(cookieNames.FUNNEL_SESSION_KEY)) {
+ if (response?.data) {
+ if (response.data.sessionKey && !isCookieSet(cookieNames.FUNNEL_SESSION_KEY)) {
setCookieProperties(
{
[cookieNames.FUNNEL_SESSION_KEY]: response.data.sessionKey,
},
{
- maxAge: 30 * 60
+ maxAge: 30 * 60,
}
);
}
- if(response.data.sessionId && !isCookieSet(cookieNames.SESSION_ID)) {
+ if (response.data.sessionId && !isCookieSet(cookieNames.SESSION_ID)) {
setCookieProperties(
{
- [cookieNames.SESSION_ID]: response.data.sessionId
+ [cookieNames.SESSION_ID]: response.data.sessionId,
},
{
- maxAge: 30 * 60
+ maxAge: 30 * 60,
}
);
}
diff --git a/src/router/index.js b/src/router/index.js
index e2188997a..7769d8a2d 100644
--- a/src/router/index.js
+++ b/src/router/index.js
@@ -38,11 +38,7 @@ const routes = [
async beforeEnter(to, from, next) {
// If we have no query string, or we don't have the FmgPage query string.
try {
- if (analyticsMixin.methods.noSession()) {
- await analyticsMixin.methods.initSession();
- } else {
- updateSessionIdCookie();
- }
+ await analyticsMixin.methods.validateSession();
if (getFunnelCookie()?.SuppressConceptFunnel) {
await navigateToHeritageFunnel({ shouldSaveSession: false });
From 0ba926d20c9fa8114687a1eaa8726c9b2bcf8c28 Mon Sep 17 00:00:00 2001
From: Chloe Herd
Date: Fri, 1 Dec 2023 08:37:22 -0500
Subject: [PATCH 05/36] Move all specific cookie logic to cookie-helper
---
.../heritage-integration/cookie-helper.js | 80 ++++++++++++++++---
src/mixins/analytics-mixin.js | 63 ++++-----------
2 files changed, 84 insertions(+), 59 deletions(-)
diff --git a/src/helpers/heritage-integration/cookie-helper.js b/src/helpers/heritage-integration/cookie-helper.js
index 1e1db1f1e..56736d340 100644
--- a/src/helpers/heritage-integration/cookie-helper.js
+++ b/src/helpers/heritage-integration/cookie-helper.js
@@ -78,6 +78,38 @@ export function getDeviceIdValue() {
return "00000000-0000-0000-0000-000000000000";
}
+export function regenerateDeviceId() {
+ if (!isCookieSet(cookieNames.DXDEV)) {
+ setCookieProperties(
+ {
+ [cookieNames.DXDEV]: `did=${crypto.randomUUID()}`,
+ },
+ { maxAge: 365 * 24 * 60 * 60 }
+ );
+ }
+}
+
+export function getUserIdValue() {
+ const cookieValue = getCookieValueByName(cookieNames.FUNNEL_USER_ID);
+
+ if (cookieValue) {
+ return cookieValue;
+ }
+
+ return "00000000-0000-0000-0000-000000000000";
+}
+
+export function regenerateUserId() {
+ if (!isCookieSet(cookieNames.FUNNEL_USER_ID)) {
+ setCookieProperties(
+ {
+ [cookieNames.FUNNEL_USER_ID]: crypto.randomUUID(),
+ },
+ { maxAge: 7 * 24 * 60 * 60 }
+ );
+ }
+}
+
/*
Gets value of skey cookie, returns 0 if not found.
*/
@@ -91,6 +123,17 @@ export function getSessionKeyValue() {
return 0;
}
+export function setSessionKeyIfUnset(value) {
+ if (!isCookieSet(cookieNames.FUNNEL_SESSION_KEY)) {
+ setCookieProperties(
+ {
+ [cookieNames.FUNNEL_SESSION_KEY]: value,
+ },
+ { maxAge: 30 * 60 }
+ );
+ }
+}
+
/*
Gets value of skey cookie, returns 0 if not found.
*/
@@ -104,6 +147,17 @@ export function getSessionIdValue() {
return "00000000-0000-0000-0000-000000000000";
}
+export function setSessionIdIfUnset(value) {
+ if (!isCookieSet(cookieNames.SESSION_ID)) {
+ setCookieProperties(
+ {
+ [cookieNames.SESSION_ID]: value,
+ },
+ { maxAge: 30 * 60 }
+ );
+ }
+}
+
/*
Updates session ID cookie with new expiration date
*/
@@ -111,16 +165,6 @@ export function updateSessionIdCookie() {
createOrUpdateCookie(cookieNames.SESSION_ID, getSessionIdValue(), { maxAge: 60 * 30 });
}
-export function getUserIdValue() {
- const cookieValue = getCookieValueByName(cookieNames.FUNNEL_USER_ID);
-
- if (cookieValue) {
- return cookieValue;
- }
-
- return "00000000-0000-0000-0000-000000000000";
-}
-
export function setCookieProperties(
properties,
{ useDefaultFunnelCookieAttributes = true, maxAge, isSecure }
@@ -142,6 +186,22 @@ export function isCookieSet(name) {
return !!val;
}
+export function areAllSessionCookiesSet() {
+ return (
+ isCookieSet(cookieNames.SESSION_ID) &&
+ isCookieSet(cookieNames.DXDEV) &&
+ isCookieSet(cookieNames.FUNNEL_SESSION_KEY) &&
+ isCookieSet(cookieNames.FUNNEL_USER_ID)
+ );
+}
+
+export function refreshSessionExpiration() {
+ refreshCookieExpiration(cookieNames.SESSION_ID, 30 * 60);
+ refreshCookieExpiration(cookieNames.DXDEV, 365 * 24 * 60 * 60);
+ refreshCookieExpiration(cookieNames.FUNNEL_USER_ID, 7 * 24 * 60 * 60);
+ refreshCookieExpiration(cookieNames.FUNNEL_SESSION_KEY, 30 * 60);
+}
+
export function refreshCookieExpiration(name, expirationTime) {
if (isCookieSet(name)) {
createOrUpdateCookie(name, getCookieValueByName(name), { maxAge: expirationTime });
diff --git a/src/mixins/analytics-mixin.js b/src/mixins/analytics-mixin.js
index f793f4825..de408218c 100644
--- a/src/mixins/analytics-mixin.js
+++ b/src/mixins/analytics-mixin.js
@@ -6,7 +6,12 @@ import {
getSessionKeyValue,
getUserIdValue,
isCookieSet,
- refreshCookieExpiration,
+ regenerateDeviceId,
+ regenerateUserId,
+ refreshSessionExpiration,
+ areAllSessionCookiesSet,
+ setSessionIdIfUnset,
+ setSessionKeyIfUnset,
} from "@/helpers/heritage-integration/cookie-helper";
import { queryStrings } from "@/constants/query-strings";
import { experimentSettings } from "@/constants/experiments";
@@ -139,22 +144,8 @@ export default {
},
async initSession() {
- if (!isCookieSet(cookieNames.FUNNEL_USER_ID)) {
- setCookieProperties(
- {
- [cookieNames.FUNNEL_USER_ID]: crypto.randomUUID(),
- },
- { maxAge: 7 * 24 * 60 * 60 }
- );
- }
- if (!isCookieSet(cookieNames.DXDEV)) {
- setCookieProperties(
- {
- [cookieNames.DXDEV]: crypto.randomUUID(),
- },
- { maxAge: 365 * 24 * 60 * 60 }
- );
- }
+ regenerateDeviceId();
+ regenerateUserId();
const userId = getUserIdValue(); // cookieNames.FUNNEL_USER_ID
const deviceId = getDeviceIdValue(); // cookieNames.DXDEV
@@ -178,37 +169,18 @@ export default {
);
if (response?.data) {
- if (response.data.sessionKey && !isCookieSet(cookieNames.FUNNEL_SESSION_KEY)) {
- setCookieProperties(
- {
- [cookieNames.FUNNEL_SESSION_KEY]: response.data.sessionKey,
- },
- {
- maxAge: 30 * 60,
- }
- );
+ if (response.data.sessionKey) {
+ setSessionKeyIfUnset(response.data.sessionKey);
}
- if (response.data.sessionId && !isCookieSet(cookieNames.SESSION_ID)) {
- setCookieProperties(
- {
- [cookieNames.SESSION_ID]: response.data.sessionId,
- },
- {
- maxAge: 30 * 60,
- }
- );
+ if (response.data.sessionId) {
+ setSessionIdIfUnset(response.data.sessionId);
}
}
},
noSession() {
- return !(
- isCookieSet(cookieNames.SESSION_ID) &&
- isCookieSet(cookieNames.DXDEV) &&
- isCookieSet(cookieNames.FUNNEL_SESSION_KEY) &&
- isCookieSet(cookieNames.FUNNEL_USER_ID)
- );
+ return !areAllSessionCookiesSet();
},
async validateSession() {
@@ -216,14 +188,7 @@ export default {
await this.initSession();
}
- this.refreshSessionExpiration();
- },
-
- refreshSessionExpiration() {
- refreshCookieExpiration(cookieNames.SESSION_ID, 30 * 60);
- refreshCookieExpiration(cookieNames.DXDEV, 365 * 24 * 60 * 60);
- refreshCookieExpiration(cookieNames.FUNNEL_USER_ID, 7 * 24 * 60 * 60);
- refreshCookieExpiration(cookieNames.FUNNEL_SESSION_KEY, 30 * 60);
+ refreshSessionExpiration();
},
removeParamsFromEndpoint(endpoint) {
From c6a50eb67ddaf4f13120d72ba93c99d005bd6ede Mon Sep 17 00:00:00 2001
From: hiteshkumar87
Date: Fri, 1 Dec 2023 19:07:27 +0530
Subject: [PATCH 06/36] Update confirmation.vue
Back to Safelite button redirecting to environment content site.
---
src/layouts/confirmation/confirmation.vue | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/layouts/confirmation/confirmation.vue b/src/layouts/confirmation/confirmation.vue
index 51546a97e..32c36c161 100644
--- a/src/layouts/confirmation/confirmation.vue
+++ b/src/layouts/confirmation/confirmation.vue
@@ -300,7 +300,7 @@ export default {
return serviceLocationReqs && scheduleReqs && customerReqs;
},
forwardButtonAction() {
- window.location.assign("//www.safelite.com/");
+ window.location.assign(location.protocol + "//" + location.host);
},
},
components: {
From b4792236d8de27f0ae82329e0909afa603c8b216 Mon Sep 17 00:00:00 2001
From: Scott Kiener
Date: Fri, 1 Dec 2023 08:46:50 -0500
Subject: [PATCH 07/36] CSR-1857 | Exclude promos from lineItems sent to
safelite-hop
---
src/layouts/payment/payment.vue | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/layouts/payment/payment.vue b/src/layouts/payment/payment.vue
index 6de58dc3c..559a44ee2 100644
--- a/src/layouts/payment/payment.vue
+++ b/src/layouts/payment/payment.vue
@@ -532,7 +532,7 @@ export default {
}
cartItems.forEach((item) => {
- if (item.name !== null) {
+ if (item.name !== null && item.category != "promos") {
lineItems.push(`${item.name}|${(item.salesTax + item.subTotal).toFixed(2)}|1`);
}
});
From 921a3efbfd210c299562722b1305d7374d1ae5a7 Mon Sep 17 00:00:00 2001
From: Chloe Herd
Date: Fri, 1 Dec 2023 09:08:32 -0500
Subject: [PATCH 08/36] Define cookie TTLs as constants
---
src/constants/cookie-names.js | 21 +++++++++++++++-
.../heritage-integration/cookie-helper.js | 24 +++++++++++--------
2 files changed, 34 insertions(+), 11 deletions(-)
diff --git a/src/constants/cookie-names.js b/src/constants/cookie-names.js
index bf6bc130a..d62934cf5 100644
--- a/src/constants/cookie-names.js
+++ b/src/constants/cookie-names.js
@@ -12,4 +12,23 @@ const cookieNames = {
SESSION_KEY: "skey",
};
-export { cookieNames };
+const cookieExpirations = {
+ SESSION_ID: convertToSeconds({ minutes: 30 }),
+ DXDEV: convertToSeconds({ years: 1 }),
+ FUNNEL_USER_ID: convertToSeconds({ weeks: 1 }),
+ FUNNEL_SESSION_KEY: convertToSeconds({ minutes: 30 }),
+};
+
+export { cookieNames, cookieExpirations };
+
+function convertToSeconds({ years, months, weeks, days, hours, minutes, seconds }) {
+ let total = seconds ?? 0;
+ total += (minutes ?? 0) * 60;
+ total += (hours ?? 0) * 60 * 60;
+ total += (days ?? 0) * 24 * 60 * 60;
+ total += (weeks ?? 0) * 7 * 24 * 60 * 60;
+ total += (months ?? 0) * 30 * 24 * 60 * 60;
+ total += (years ?? 0) * 365 * 24 * 60 * 60;
+
+ return total;
+}
diff --git a/src/helpers/heritage-integration/cookie-helper.js b/src/helpers/heritage-integration/cookie-helper.js
index 56736d340..50896cab2 100644
--- a/src/helpers/heritage-integration/cookie-helper.js
+++ b/src/helpers/heritage-integration/cookie-helper.js
@@ -1,4 +1,4 @@
-import { cookieNames } from "@/constants/cookie-names";
+import { cookieNames, cookieExpirations } from "@/constants/cookie-names";
import store from "@/store";
import { applicationConfig } from "@/constants/application-config";
@@ -84,7 +84,7 @@ export function regenerateDeviceId() {
{
[cookieNames.DXDEV]: `did=${crypto.randomUUID()}`,
},
- { maxAge: 365 * 24 * 60 * 60 }
+ { maxAge: cookieExpirations.DXDEV }
);
}
}
@@ -105,7 +105,7 @@ export function regenerateUserId() {
{
[cookieNames.FUNNEL_USER_ID]: crypto.randomUUID(),
},
- { maxAge: 7 * 24 * 60 * 60 }
+ { maxAge: cookieExpirations.FUNNEL_USER_ID }
);
}
}
@@ -129,7 +129,7 @@ export function setSessionKeyIfUnset(value) {
{
[cookieNames.FUNNEL_SESSION_KEY]: value,
},
- { maxAge: 30 * 60 }
+ { maxAge: cookieExpirations.FUNNEL_SESSION_KEY }
);
}
}
@@ -153,7 +153,7 @@ export function setSessionIdIfUnset(value) {
{
[cookieNames.SESSION_ID]: value,
},
- { maxAge: 30 * 60 }
+ { maxAge: cookieExpirations.SESSION_ID }
);
}
}
@@ -162,7 +162,9 @@ export function setSessionIdIfUnset(value) {
Updates session ID cookie with new expiration date
*/
export function updateSessionIdCookie() {
- createOrUpdateCookie(cookieNames.SESSION_ID, getSessionIdValue(), { maxAge: 60 * 30 });
+ createOrUpdateCookie(cookieNames.SESSION_ID, getSessionIdValue(), {
+ maxAge: cookieExpirations.SESSION_ID,
+ });
}
export function setCookieProperties(
@@ -196,10 +198,12 @@ export function areAllSessionCookiesSet() {
}
export function refreshSessionExpiration() {
- refreshCookieExpiration(cookieNames.SESSION_ID, 30 * 60);
- refreshCookieExpiration(cookieNames.DXDEV, 365 * 24 * 60 * 60);
- refreshCookieExpiration(cookieNames.FUNNEL_USER_ID, 7 * 24 * 60 * 60);
- refreshCookieExpiration(cookieNames.FUNNEL_SESSION_KEY, 30 * 60);
+ console.log(cookieExpirations);
+
+ refreshCookieExpiration(cookieNames.SESSION_ID, cookieExpirations.SESSION_ID);
+ refreshCookieExpiration(cookieNames.DXDEV, cookieExpirations.DXDEV);
+ refreshCookieExpiration(cookieNames.FUNNEL_USER_ID, cookieExpirations.FUNNEL_USER_ID);
+ refreshCookieExpiration(cookieNames.FUNNEL_SESSION_KEY, cookieExpirations.FUNNEL_SESSION_KEY);
}
export function refreshCookieExpiration(name, expirationTime) {
From 999d274d88a9e632fa7e0242796c9bcd6b410311 Mon Sep 17 00:00:00 2001
From: Chloe Herd
Date: Fri, 1 Dec 2023 09:11:10 -0500
Subject: [PATCH 09/36] Cleanup imports
---
src/mixins/analytics-mixin.js | 3 ---
1 file changed, 3 deletions(-)
diff --git a/src/mixins/analytics-mixin.js b/src/mixins/analytics-mixin.js
index de408218c..7b7a2d762 100644
--- a/src/mixins/analytics-mixin.js
+++ b/src/mixins/analytics-mixin.js
@@ -1,11 +1,9 @@
import { storeActions } from "@/constants/store-actions";
import {
- setCookieProperties,
getDeviceIdValue,
getSessionIdValue,
getSessionKeyValue,
getUserIdValue,
- isCookieSet,
regenerateDeviceId,
regenerateUserId,
refreshSessionExpiration,
@@ -23,7 +21,6 @@ import {
GaEvents,
ValueToLogTypes,
} from "@/constants/analytics";
-import { cookieNames } from "@/constants/cookie-names";
import store from "@/store";
import baseMixin from "@/mixins/base-mixin";
From 648a43ba81dd21458960064d5bd60f5379622749 Mon Sep 17 00:00:00 2001
From: Chloe Herd
Date: Fri, 1 Dec 2023 09:38:24 -0500
Subject: [PATCH 10/36] Remove log
---
src/helpers/heritage-integration/cookie-helper.js | 2 --
1 file changed, 2 deletions(-)
diff --git a/src/helpers/heritage-integration/cookie-helper.js b/src/helpers/heritage-integration/cookie-helper.js
index 50896cab2..abb1c0a67 100644
--- a/src/helpers/heritage-integration/cookie-helper.js
+++ b/src/helpers/heritage-integration/cookie-helper.js
@@ -198,8 +198,6 @@ export function areAllSessionCookiesSet() {
}
export function refreshSessionExpiration() {
- console.log(cookieExpirations);
-
refreshCookieExpiration(cookieNames.SESSION_ID, cookieExpirations.SESSION_ID);
refreshCookieExpiration(cookieNames.DXDEV, cookieExpirations.DXDEV);
refreshCookieExpiration(cookieNames.FUNNEL_USER_ID, cookieExpirations.FUNNEL_USER_ID);
From 411976efe59d8dfdaf64b1674ade2657dff3003c Mon Sep 17 00:00:00 2001
From: Chloe Herd
Date: Fri, 1 Dec 2023 09:38:40 -0500
Subject: [PATCH 11/36] Use correct deviceId in initialize
---
src/store/index.js | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/store/index.js b/src/store/index.js
index 684ca83e1..55a2ba120 100644
--- a/src/store/index.js
+++ b/src/store/index.js
@@ -1151,11 +1151,11 @@ export const actions = {
}
);
},
- initializeSession(context, { userId, sessionId, userAgent, referrer }) {
+ initializeSession(context, { userId, deviceId, sessionId, userAgent, referrer }) {
var payload = {
applicationName: applicationConfig.ANALYTICS_APPLICATION_NAME,
userId: userId,
- deviceId: userId,
+ deviceId: deviceId,
sessionId: sessionId,
userAgent: userAgent,
operatorId: "WEB",
From 53aed87e1d814a2b15238a7ba7c983b0da688a33 Mon Sep 17 00:00:00 2001
From: Chloe Herd
Date: Fri, 1 Dec 2023 09:42:11 -0500
Subject: [PATCH 12/36] Use correct userId for analytics logging
---
src/mixins/analytics-mixin.js | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/mixins/analytics-mixin.js b/src/mixins/analytics-mixin.js
index 7b7a2d762..8dd0c7f96 100644
--- a/src/mixins/analytics-mixin.js
+++ b/src/mixins/analytics-mixin.js
@@ -35,7 +35,7 @@ export default {
logPageView(pageEvent) {
const currentPageName = getPageNameByQueryString();
var payload = {
- userId: getDeviceIdValue(),
+ userId: getUserIdValue(),
sessionKey: getSessionKeyValue(),
pageName: currentPageName,
sessionId: getSessionIdValue(),
@@ -54,7 +54,7 @@ export default {
const currentPageName = getPageNameByQueryString();
var payload = {
- userId: getDeviceIdValue(),
+ userId: getUserIdValue(),
sessionKey: getSessionKeyValue(),
pageName: currentPageName,
sessionId: getSessionIdValue(),
From ad5014ac6f4fc1f2c6431bc4cf844288506bbb7e Mon Sep 17 00:00:00 2001
From: Bryan Mauger
Date: Fri, 1 Dec 2023 10:29:51 -0500
Subject: [PATCH 13/36] CSR-1819 remove unneeded accessibility spans.
---
src/fmg-components/cart/cart.vue | 24 +++++++-----------------
1 file changed, 7 insertions(+), 17 deletions(-)
diff --git a/src/fmg-components/cart/cart.vue b/src/fmg-components/cart/cart.vue
index d5ef09542..4e6aeb1da 100644
--- a/src/fmg-components/cart/cart.vue
+++ b/src/fmg-components/cart/cart.vue
@@ -16,8 +16,7 @@
-
- {{ screenReaderPackagePriceText }}
+
{{ getFormattedAmount("", packagePrice) }}
@@ -64,39 +63,29 @@
{{ recycleFeeCartItem.name }}
-
{{ screenReaderRecycleFeeText }}{{ getFormattedAmount(cartItem.category, cartItem.subTotal) }}{{ getFormattedAmount(cartItem.category, cartItem.subTotal) }}
{{ subtotalText }}{{ screenReaderSubTotalText }}{{ getFormattedAmount("", subTotal) }}{{ getFormattedAmount("", subTotal) }}
{{ salesTaxText }}{{ screenReaderSalesTaxText }}{{ getFormattedAmount("", salesTax) }}{{ getFormattedAmount("", salesTax) }}
{{ amountPaidText }}{{ screenReaderAmountPaidText }}{{ getFormattedAmount("", amountPaid) }}{{ getFormattedAmount("", amountPaid) }}
{{ amountDueText }}{{ screenReaderTotalAmountDueText }}{{ getFormattedAmount("", amountDue) }}{{ getFormattedAmount("", amountDue) }}
@@ -136,6 +125,7 @@ export default {
allowItemRemoval: Boolean,
recyclingModalCmsWidgetName: String,
showAsPaid: Boolean,
+ cmsWidgetName: String,
},
data() {
return {
From c2996187bbed7145e2e5defef49dc1a1b877f3de Mon Sep 17 00:00:00 2001
From: Chloe Herd
Date: Fri, 1 Dec 2023 10:30:15 -0500
Subject: [PATCH 14/36] Ensure session state is valid before logging
---
src/mixins/analytics-mixin.js | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/src/mixins/analytics-mixin.js b/src/mixins/analytics-mixin.js
index 8dd0c7f96..dcadb3f07 100644
--- a/src/mixins/analytics-mixin.js
+++ b/src/mixins/analytics-mixin.js
@@ -32,8 +32,10 @@ export default {
return getPageNameByQueryString();
},
- logPageView(pageEvent) {
+ async logPageView(pageEvent) {
const currentPageName = getPageNameByQueryString();
+ await this.validateSession();
+
var payload = {
userId: getUserIdValue(),
sessionKey: getSessionKeyValue(),
@@ -50,8 +52,9 @@ export default {
baseMixin.methods.dispatchStoreAction(storeActions.LOG_PAGE_VIEW, payload, false);
},
- logCustomEvent(category, action, label, value) {
+ async logCustomEvent(category, action, label, value) {
const currentPageName = getPageNameByQueryString();
+ await this.validateSession();
var payload = {
userId: getUserIdValue(),
From 088060a354d5217bb83f9fc6d622760066c3d131 Mon Sep 17 00:00:00 2001
From: Bryan Mauger
Date: Fri, 1 Dec 2023 10:31:30 -0500
Subject: [PATCH 15/36] Remove unneeded prop.
---
src/fmg-components/cart/cart.vue | 1 -
1 file changed, 1 deletion(-)
diff --git a/src/fmg-components/cart/cart.vue b/src/fmg-components/cart/cart.vue
index 4e6aeb1da..29ce7aca8 100644
--- a/src/fmg-components/cart/cart.vue
+++ b/src/fmg-components/cart/cart.vue
@@ -125,7 +125,6 @@ export default {
allowItemRemoval: Boolean,
recyclingModalCmsWidgetName: String,
showAsPaid: Boolean,
- cmsWidgetName: String,
},
data() {
return {
From 42d60f4e22f29c8a0208bd6fe4da56098e153da9 Mon Sep 17 00:00:00 2001
From: Chloe Herd
Date: Fri, 1 Dec 2023 11:32:33 -0500
Subject: [PATCH 16/36] Update existing unit test suite
---
src/helpers/unit-test-helper.js | 3 +-
src/mixins/analytics-mixin.js | 16 ++++---
src/mixins/analytics-mixin.spec.js | 72 +++++++++++++++++++++++++-----
3 files changed, 74 insertions(+), 17 deletions(-)
diff --git a/src/helpers/unit-test-helper.js b/src/helpers/unit-test-helper.js
index 467b38c2b..123dc9d40 100644
--- a/src/helpers/unit-test-helper.js
+++ b/src/helpers/unit-test-helper.js
@@ -100,7 +100,8 @@ export const cookies = {
someOtherCookie: "{}",
dxdev: "did=21b9b94a-ec23-42c1-aaac-e2ae4e4dbffe",
sid: "cba0c3d1-3c1b-4305-bb56-31aa50f58e27",
- skey: "12345",
+ [cookieNames.FUNNEL_SESSION_KEY]: "12345",
+ [cookieNames.FUNNEL_USER_ID]: "11aec5e8-92ba-4dc9-a8b6-179a916d8d7a",
};
// Removes test cookies for testing cookie-helper and order-helper
diff --git a/src/mixins/analytics-mixin.js b/src/mixins/analytics-mixin.js
index dcadb3f07..6ea36a903 100644
--- a/src/mixins/analytics-mixin.js
+++ b/src/mixins/analytics-mixin.js
@@ -49,7 +49,7 @@ export default {
parentAccountNumber: store.getters.order.payment.parentAccountNumber,
};
- baseMixin.methods.dispatchStoreAction(storeActions.LOG_PAGE_VIEW, payload, false);
+ await baseMixin.methods.dispatchStoreAction(storeActions.LOG_PAGE_VIEW, payload, false);
},
async logCustomEvent(category, action, label, value) {
@@ -71,10 +71,14 @@ export default {
parentAccountNumber: store.getters.order.payment.parentAccountNumber,
};
- baseMixin.methods.dispatchStoreAction(storeActions.LOG_CUSTOM_EVENT, payload, false);
+ await baseMixin.methods.dispatchStoreAction(
+ storeActions.LOG_CUSTOM_EVENT,
+ payload,
+ false
+ );
},
- pushEventToGA(category, action, label, pushToLogApp = false, valueToLogType = null) {
+ async pushEventToGA(category, action, label, pushToLogApp = false, valueToLogType = null) {
const currentPageName = getPageNameByQueryString();
const labelToLog = getValueToLog(label, valueToLogType);
@@ -90,11 +94,11 @@ export default {
pushToDataLayerIfDefined(eventToBePushed);
if (pushToLogApp) {
- this.logCustomEvent(category, action, labelToLog, undefined);
+ await this.logCustomEvent(category, action, labelToLog, undefined);
}
},
- pushPageViewToGA() {
+ async pushPageViewToGA() {
const currentPageName = getPageNameByQueryString();
const pageViewEvent = {
event: GaEvents.PAGE_VIEW_EVENT,
@@ -104,7 +108,7 @@ export default {
pushToDataLayerIfDefined(pageViewEvent);
- this.logPageView(analyticsPageEvents.ENTRY);
+ await this.logPageView(analyticsPageEvents.ENTRY);
},
pushExperimentsToDataLayer() {
diff --git a/src/mixins/analytics-mixin.spec.js b/src/mixins/analytics-mixin.spec.js
index 0426ca297..8f7cfceaa 100644
--- a/src/mixins/analytics-mixin.spec.js
+++ b/src/mixins/analytics-mixin.spec.js
@@ -11,8 +11,20 @@ import {
} from "@/constants/analytics";
import store from "@/store";
+// Mock only the regenerate functions; window.crypto is not available in testing.
+jest.mock("@/helpers/heritage-integration/cookie-helper", () => {
+ const originalModule = jest.requireActual("@/helpers/heritage-integration/cookie-helper");
+
+ return {
+ __esModule: true,
+ ...originalModule,
+ regenerateDeviceId: jest.fn(),
+ regenerateUserId: jest.fn(),
+ };
+});
+
describe("analyticsMixin.js", () => {
- test("logPageView: calls dispatch with type and payload", () => {
+ test("logPageView: calls dispatch with type and payload", async () => {
const type = "";
const payload = {};
@@ -21,6 +33,9 @@ describe("analyticsMixin.js", () => {
{
actionName: storeActions.LOG_PAGE_VIEW,
},
+ {
+ actionName: storeActions.INITIALIZE_SESSION,
+ },
],
};
const mocks = setupMocksForJsFiles(mockData);
@@ -31,27 +46,35 @@ describe("analyticsMixin.js", () => {
setupCookies({ funnelCookieValue: JSON.stringify(testCookieValue) });
- analyticsMixin.methods.logPageView(type, payload);
+ await analyticsMixin.methods.logPageView(type, payload);
expect(mocks.baseMixin.methods.dispatchStoreAction).toBeCalled();
});
- test("logCustomEvent: calls dispatch with type and payload", () => {
+ test("logCustomEvent: calls dispatch with type and payload", async () => {
const mockData = {
actionList: [
{
actionName: storeActions.LOG_CUSTOM_EVENT,
},
+ {
+ actionName: storeActions.INITIALIZE_SESSION,
+ },
],
};
const mocks = setupMocksForJsFiles(mockData);
- analyticsMixin.methods.logCustomEvent("someCat", "someAction", "someLabel", "someVal");
+ await analyticsMixin.methods.logCustomEvent(
+ "someCat",
+ "someAction",
+ "someLabel",
+ "someVal"
+ );
expect(mocks.baseMixin.methods.dispatchStoreAction).toBeCalled();
});
- test("pushEventToGA, should call dataLayer push and logCustomEvent too", () => {
+ test("pushEventToGA, should call dataLayer push and logCustomEvent too", async () => {
// Arrange
window.dataLayer = [];
const mockData = {
@@ -59,6 +82,9 @@ describe("analyticsMixin.js", () => {
{
actionName: storeActions.LOG_CUSTOM_EVENT,
},
+ {
+ actionName: storeActions.INITIALIZE_SESSION,
+ },
],
};
const mocks = setupMocksForJsFiles(mockData);
@@ -73,14 +99,14 @@ 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));
expect(mocks.baseMixin.methods.dispatchStoreAction).toBeCalled();
});
- 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 = [];
var expectedDataLayer = [];
@@ -93,8 +119,21 @@ describe("analyticsMixin.js", () => {
path: "/fmg/?fmgPage=",
});
+ const mockData = {
+ actionList: [
+ {
+ actionName: storeActions.LOG_CUSTOM_EVENT,
+ },
+ {
+ actionName: storeActions.INITIALIZE_SESSION,
+ },
+ ],
+ };
+
+ const mocks = setupMocksForJsFiles(mockData);
+
// Act
- analyticsMixin.methods.pushEventToGA(
+ await analyticsMixin.methods.pushEventToGA(
"category",
"action",
"1111122222333333",
@@ -106,7 +145,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 = [];
var expectedDataLayer = [];
@@ -119,8 +158,21 @@ describe("analyticsMixin.js", () => {
path: "/fmg/?fmgPage=",
});
+ const mockData = {
+ actionList: [
+ {
+ actionName: storeActions.LOG_CUSTOM_EVENT,
+ },
+ {
+ actionName: storeActions.INITIALIZE_SESSION,
+ },
+ ],
+ };
+
+ const mocks = setupMocksForJsFiles(mockData);
+
// Act
- analyticsMixin.methods.pushEventToGA(
+ await analyticsMixin.methods.pushEventToGA(
"category",
"action",
"111",
From 2106738f5d9a7e3f3c9898bb7fbbb2bed0138f73 Mon Sep 17 00:00:00 2001
From: Bryan Mauger
Date: Fri, 1 Dec 2023 13:30:32 -0500
Subject: [PATCH 17/36] Format code.
---
src/fmg-components/cart/cart.vue | 15 +++++----------
1 file changed, 5 insertions(+), 10 deletions(-)
diff --git a/src/fmg-components/cart/cart.vue b/src/fmg-components/cart/cart.vue
index 29ce7aca8..cd50a8fda 100644
--- a/src/fmg-components/cart/cart.vue
+++ b/src/fmg-components/cart/cart.vue
@@ -63,30 +63,25 @@
{{ recycleFeeCartItem.name }}
- {{ getFormattedAmount(cartItem.category, cartItem.subTotal) }}
+ {{ getFormattedAmount(cartItem.category, cartItem.subTotal) }}
{{ subtotalText }}{{ getFormattedAmount("", subTotal) }}
+ >{{ getFormattedAmount("", subTotal) }}
{{ salesTaxText }}{{ getFormattedAmount("", salesTax) }}
+ >{{ getFormattedAmount("", salesTax) }}
{{ amountPaidText }}{{ getFormattedAmount("", amountPaid) }}
+ >{{ getFormattedAmount("", amountPaid) }}
{{ amountDueText }}{{ getFormattedAmount("", amountDue) }}
+ >{{ getFormattedAmount("", amountDue) }}
From 3cd95431ff9caf77c186bab110cc6f339b465318 Mon Sep 17 00:00:00 2001
From: CarlNation <32103961+CarlNation@users.noreply.github.com>
Date: Fri, 1 Dec 2023 14:39:21 -0500
Subject: [PATCH 18/36] CSR-1858
ctu corrections
---
.../mobile-location-modal-questions.vue | 1 +
.../service-location/service-location.vue | 27 +++++++++++++++++++
2 files changed, 28 insertions(+)
diff --git a/src/layouts/service-location/mobile-location-modal-questions/mobile-location-modal-questions.vue b/src/layouts/service-location/mobile-location-modal-questions/mobile-location-modal-questions.vue
index 8bac8dbb4..762af0d72 100644
--- a/src/layouts/service-location/mobile-location-modal-questions/mobile-location-modal-questions.vue
+++ b/src/layouts/service-location/mobile-location-modal-questions/mobile-location-modal-questions.vue
@@ -252,6 +252,7 @@ export default {
this.$emit("updated-mobile-fee-part", mobileFeePart);
this.$emit("updated-serviceability", serviceabilityDetails.data);
this.$emit("updated-contains-military-base", zipCodeData.containsMilitaryBase);
+ this.$emit("updated-mobile-ctu", zipCodeData.zipCodeCtu);
// update the page level model
this.$emit("update:modelValue", this.internalModel);
diff --git a/src/layouts/service-location/service-location.vue b/src/layouts/service-location/service-location.vue
index 0a74ab21e..1c25b8f40 100644
--- a/src/layouts/service-location/service-location.vue
+++ b/src/layouts/service-location/service-location.vue
@@ -83,6 +83,7 @@
@updated-mobile-fee-part="setMobileFeePart"
@updated-serviceability="setServiceabilityDetails"
@updated-contains-military-base="setContainsMilitaryBase"
+ @updated-mobile-ctu="setCtuForMobile"
validationRules="mobile-location-required"
ref="mobileLocationQuestions"
linkWidgetName="MobileLocationLinkWidget"
@@ -128,6 +129,7 @@ import contentGroupModal from "@/fmg-components/content-group-modal/content-grou
// Supporting files
import baseMixin from "@/mixins/base-mixin.js";
+import { AppointmentTypeStrings } from "@/constants/schedule-constants";
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
import { settleAllPromises } from "@/helpers/layout-helper";
@@ -374,6 +376,9 @@ export default {
this.zipContainsMilitaryBase = val;
}
},
+ setCtuForMobile(val) {
+ this.zipCodeCtu = val;
+ },
setMobileFeePart(mobileFeePart) {
this.mobileFeePart = mobileFeePart;
},
@@ -472,6 +477,28 @@ export default {
}
},
async forwardButtonAction() {
+ // clear items not needed for appointmentType
+ if (this.selectedAppointmentType == AppointmentTypeStrings.IN_SHOP) {
+ // if we have a provider.zipCodeCtu that's different than the servicelocation.zipCodeCtu then they
+ // may have selected a shop in a different ctu. change the servicelocation zip/ctu if different
+ if (this.zipCodeCtu != this.selectedProvider.address.zipCodeCtu) {
+ this.zipCodeCtu = this.selectedProvider.address.zipCodeCtu;
+ this.zipCode = this.selectedProvider.address.zipCode;
+ }
+
+ this.city = null;
+ this.streetAddress = null;
+ }
+
+ if (this.selectedAppointmentType == AppointmentTypeStrings.MOBILE &&
+ this.selectedProvider && this.selectedProvider.address) {
+ this.selectedProvider.address.streetAddress = null;
+ this.selectedProvider.address.city = null;
+ this.selectedProvider.address.state = null;
+ this.selectedProvider.address.zipCode = null;
+ this.selectedProvider.address.zipCodeCtu = null;
+ }
+
await this.dispatchStoreAction(
this.storeActions.SAVE_SERVICE_LOCATION,
{
From 7783d233d2909f0f618b417d89c41a71779cec44 Mon Sep 17 00:00:00 2001
From: CarlNation
Date: Fri, 1 Dec 2023 14:43:03 -0500
Subject: [PATCH 19/36] csr-1853 prettier
---
src/layouts/service-location/service-location.vue | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/src/layouts/service-location/service-location.vue b/src/layouts/service-location/service-location.vue
index 1c25b8f40..e6cb2138e 100644
--- a/src/layouts/service-location/service-location.vue
+++ b/src/layouts/service-location/service-location.vue
@@ -479,7 +479,7 @@ export default {
async forwardButtonAction() {
// clear items not needed for appointmentType
if (this.selectedAppointmentType == AppointmentTypeStrings.IN_SHOP) {
- // if we have a provider.zipCodeCtu that's different than the servicelocation.zipCodeCtu then they
+ // if we have a provider.zipCodeCtu that's different than the servicelocation.zipCodeCtu then they
// may have selected a shop in a different ctu. change the servicelocation zip/ctu if different
if (this.zipCodeCtu != this.selectedProvider.address.zipCodeCtu) {
this.zipCodeCtu = this.selectedProvider.address.zipCodeCtu;
@@ -490,8 +490,11 @@ export default {
this.streetAddress = null;
}
- if (this.selectedAppointmentType == AppointmentTypeStrings.MOBILE &&
- this.selectedProvider && this.selectedProvider.address) {
+ if (
+ this.selectedAppointmentType == AppointmentTypeStrings.MOBILE &&
+ this.selectedProvider &&
+ this.selectedProvider.address
+ ) {
this.selectedProvider.address.streetAddress = null;
this.selectedProvider.address.city = null;
this.selectedProvider.address.state = null;
From 82e2e041def20be3794b1140414504cd3ed94166 Mon Sep 17 00:00:00 2001
From: Chloe Herd
Date: Fri, 1 Dec 2023 15:27:05 -0500
Subject: [PATCH 20/36] Fix typo
---
src/mixins/analytics-mixin.js | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/mixins/analytics-mixin.js b/src/mixins/analytics-mixin.js
index 6ea36a903..d3fa4d0dd 100644
--- a/src/mixins/analytics-mixin.js
+++ b/src/mixins/analytics-mixin.js
@@ -155,7 +155,7 @@ export default {
const deviceId = getDeviceIdValue(); // cookieNames.DXDEV
const sessionId = getSessionIdValue(); // cookieNames.SESSION_ID
const userAgent = navigator.userAgent; // navigator.userAgent
- const refferer =
+ const referrer =
applicationConfig.CURRENT_ENVIRONMENT != "Localhost" ? document.referrer : null; // see above
const payload = {
@@ -163,7 +163,7 @@ export default {
deviceId: deviceId,
sessionId: sessionId,
userAgent: userAgent,
- refferer: refferer,
+ referrer: referrer,
};
const response = await baseMixin.methods.dispatchStoreAction(
From 0630faa6a5d4d0b01931c1b34ddfc0e39a0e2b2b Mon Sep 17 00:00:00 2001
From: CarlNation
Date: Tue, 5 Dec 2023 05:31:10 -0500
Subject: [PATCH 21/36] CSR-1867
introduced by defect CSR-1858 needing to reset zipcode and ctu when selecting a location in a different ctu. fix is to not execute zipcode watch logic while navigating forward.
---
.../service-location/service-location.vue | 25 +++++++++++--------
1 file changed, 15 insertions(+), 10 deletions(-)
diff --git a/src/layouts/service-location/service-location.vue b/src/layouts/service-location/service-location.vue
index e6cb2138e..bfec46932 100644
--- a/src/layouts/service-location/service-location.vue
+++ b/src/layouts/service-location/service-location.vue
@@ -183,6 +183,7 @@ export default {
zipContainsMilitaryBase: false,
zipCodeCtu: null,
shopProviderData: null,
+ navigatingForward: false,
};
},
async beforeRouteEnter(to, from, next) {
@@ -477,6 +478,8 @@ export default {
}
},
async forwardButtonAction() {
+ this.navigatingForward = true;
+
// clear items not needed for appointmentType
if (this.selectedAppointmentType == AppointmentTypeStrings.IN_SHOP) {
// if we have a provider.zipCodeCtu that's different than the servicelocation.zipCodeCtu then they
@@ -537,16 +540,18 @@ export default {
watch: {
zipCode: {
handler(newValue) {
- getShopProviderData(this.zipCode).then(async (result) => {
- this.shopProviderData = result.data;
- if (this.selectedAppointmentType === "Mobile") {
- this.selectedProvider = new Provider(
- this.shopProviderData.mobileProviderNumber
- );
- } else {
- this.selectedProvider = new Provider();
- }
- });
+ if (!this.navigatingForward) {
+ getShopProviderData(this.zipCode).then(async (result) => {
+ this.shopProviderData = result.data;
+ if (this.selectedAppointmentType === "Mobile") {
+ this.selectedProvider = new Provider(
+ this.shopProviderData.mobileProviderNumber
+ );
+ } else {
+ this.selectedProvider = new Provider();
+ }
+ });
+ }
},
},
selectedAppointmentType: {
From 25f56e51c4dfe9e2491940bace7a52577e0d8414 Mon Sep 17 00:00:00 2001
From: Chloe Herd
Date: Tue, 5 Dec 2023 09:31:08 -0500
Subject: [PATCH 22/36] Remove unneeded damage check
---
src/store/index.js | 10 +---------
src/store/store.spec.js | 2 +-
2 files changed, 2 insertions(+), 10 deletions(-)
diff --git a/src/store/index.js b/src/store/index.js
index 574df8012..a094a8a15 100644
--- a/src/store/index.js
+++ b/src/store/index.js
@@ -2495,15 +2495,7 @@ export const actions = {
isVinOptionalVehicle(context) {
//Optional for carIds with only a single windshield
- if (
- singleWindshieldCarIds.find((item) => item === context.state.order.vehicle.carId) &&
- context.state.order.damage.glassToReplace.length == 1 &&
- context.state.order.damage.glassToReplace.find(
- (glassToReplace) =>
- glassToReplace.glassLocation.toLowerCase() ===
- damageLocationsSelected.WINDSHIELD.toLowerCase()
- )
- ) {
+ if (singleWindshieldCarIds.find((item) => item === context.state.order.vehicle.carId)) {
return true;
}
//Optional for specific YMMSs
diff --git a/src/store/store.spec.js b/src/store/store.spec.js
index e7c004090..8353ec0d8 100644
--- a/src/store/store.spec.js
+++ b/src/store/store.spec.js
@@ -3329,7 +3329,7 @@ describe("isVinOptionalVehicle", () => {
"CR00062396",
"make3",
[{ glassLocation: "windshield" }, { glassLocation: "driver" }],
- false,
+ true,
],
["CR00066428", "make4", [{ glassLocation: "rear" }], false],
];
From 57d2b4ee0ee3833ee13fd2ab6c7d029798bb6a81 Mon Sep 17 00:00:00 2001
From: Bryan Mauger
Date: Tue, 5 Dec 2023 09:38:11 -0500
Subject: [PATCH 23/36] CSR-1860 fix styling for select input.
---
public/css/hop-styling.css | 2 ++
public/scss/hop-styling.scss | 2 ++
2 files changed, 4 insertions(+)
diff --git a/public/css/hop-styling.css b/public/css/hop-styling.css
index cd94e3024..68e556d53 100644
--- a/public/css/hop-styling.css
+++ b/public/css/hop-styling.css
@@ -73,6 +73,8 @@ body select {
background-position: 95% 50%;
background-size: 15px 9px;
appearance: none;
+ font-size: 16px;
+ color: #000;
}
body .creditCardSpecific div {
padding: 8px 0;
diff --git a/public/scss/hop-styling.scss b/public/scss/hop-styling.scss
index 5f21c46dd..ed8e8e14c 100644
--- a/public/scss/hop-styling.scss
+++ b/public/scss/hop-styling.scss
@@ -85,6 +85,8 @@ body {
background-position: 95% 50%;
background-size: 15px 9px;
appearance: none;
+ font-size: 16px;
+ color: #000;
}
.creditCardSpecific {
From f45d73e297dfaf979a75dc40ca8beb584263f7fd Mon Sep 17 00:00:00 2001
From: Chloe Herd
Date: Tue, 5 Dec 2023 10:49:05 -0500
Subject: [PATCH 24/36] Tests for deviceID
---
.../cookie-helper.spec.js | 91 +++++++++++++++----
src/helpers/unit-test-helper.js | 8 ++
2 files changed, 83 insertions(+), 16 deletions(-)
diff --git a/src/helpers/heritage-integration/cookie-helper.spec.js b/src/helpers/heritage-integration/cookie-helper.spec.js
index 5df2ae925..8abd265e5 100644
--- a/src/helpers/heritage-integration/cookie-helper.spec.js
+++ b/src/helpers/heritage-integration/cookie-helper.spec.js
@@ -3,10 +3,19 @@ import {
getDeviceIdValue,
getSessionKeyValue,
getSessionIdValue,
+ setCookieProperties,
+ regenerateDeviceId,
} from "@/helpers/heritage-integration/cookie-helper.js";
-import { removeAllTestCookies, setupCookies } from "@/helpers/unit-test-helper";
+import { cookieNames } from "@/constants/cookie-names";
+import { removeAllTestCookies, setupCookies, setupCrypto } from "@/helpers/unit-test-helper";
+
+const randomUUID = "68d89736-c277-46f1-8fee-c3dacdb23c08";
describe("cookies", () => {
+ beforeEach(() => {
+ setupCrypto(randomUUID);
+ });
+
afterEach(() => {
removeAllTestCookies();
});
@@ -106,30 +115,80 @@ describe("cookies", () => {
});
});
- describe("getDeviceIdValue", () => {
- test("getDeviceIdValue, should return GUID", () => {
- // Arrange
- setupCookies({});
+ describe("Device Id", () => {
+ describe("getDeviceIdValue", () => {
+ test("getDeviceIdValue, should return GUID", () => {
+ // Arrange
+ setupCookies({});
- // Act
- const result = getDeviceIdValue();
+ // Act
+ const result = getDeviceIdValue();
- //Assert
- expect(result).toBe("21b9b94a-ec23-42c1-aaac-e2ae4e4dbffe");
+ //Assert
+ expect(result).toBe("21b9b94a-ec23-42c1-aaac-e2ae4e4dbffe");
+ });
+
+ test("Should return 0s if unset", () => {
+ //Arrange
+ //Act
+ const result = getDeviceIdValue();
+
+ //Assert
+ expect(result).toBe("00000000-0000-0000-0000-000000000000");
+ });
+
+ test("Should return id even if cookie contains other data", () => {
+ //Arrange
+ setCookieProperties({
+ [cookieNames.DXDEV]: "did=f4a1a9e8-b3f3-4936-8c30-2f06a98644af&tz=-300&tzd=1",
+ }, {});
+
+ //Act
+ const result = getDeviceIdValue();
+
+ //Assert
+ expect(result).toBe("f4a1a9e8-b3f3-4936-8c30-2f06a98644af");
+ });
});
- test("getSessionKeyValue, should return session key int", () => {
- // Arrange
- setupCookies({});
+ describe("regenerateDeviceId", () => {
+ test("Generates a new id if unset", () => {
+ // Arrange
+ // Act
+ regenerateDeviceId();
+ const result = getDeviceIdValue();
- // Act
- const result = getSessionKeyValue();
+ // Assert
+ expect(result).not.toBe("00000000-0000-0000-0000-000000000000");
+ expect(global.crypto.randomUUID).toBeCalled();
+ });
- //Assert
- expect(result).toBe("12345");
+ test("Does not create a new id if already set", () => {
+ // Arrange
+ setupCookies({});
+
+ // Act
+ regenerateDeviceId();
+ const result = getDeviceIdValue();
+
+ // Assert
+ expect(result).toBe("21b9b94a-ec23-42c1-aaac-e2ae4e4dbffe");
+ expect(global.crypto.randomUUID).not.toBeCalled();
+ });
});
});
+ test("getSessionKeyValue, should return session key int", () => {
+ // Arrange
+ setupCookies({});
+
+ // Act
+ const result = getSessionKeyValue();
+
+ //Assert
+ expect(result).toBe("12345");
+ });
+
describe("getSessionIdValue", () => {
test("getSessionIdValue, should return GUID", () => {
// Arrange
diff --git a/src/helpers/unit-test-helper.js b/src/helpers/unit-test-helper.js
index 123dc9d40..457dd47fb 100644
--- a/src/helpers/unit-test-helper.js
+++ b/src/helpers/unit-test-helper.js
@@ -139,6 +139,14 @@ export function setupCookies({ funnelCookieValue = "", includeHeritageCookie = t
});
}
+export function setupCrypto(mockValue) {
+ global.crypto = {
+ randomUUID: jest.fn()
+ };
+
+ global.crypto.randomUUID.mockImplementation(() => mockValue);
+}
+
// Private methods
function setupBaseMixinDispatchStoreAction(mockData) {
if (mockData.actionList !== undefined) {
From aa59d955cb1a5faace71bf34286cfedfd6428e4b Mon Sep 17 00:00:00 2001
From: Chloe Herd
Date: Tue, 5 Dec 2023 11:35:51 -0500
Subject: [PATCH 25/36] UserId + Formatting
---
.../cookie-helper.spec.js | 62 ++++++++++++++++++-
src/helpers/unit-test-helper.js | 2 +-
2 files changed, 60 insertions(+), 4 deletions(-)
diff --git a/src/helpers/heritage-integration/cookie-helper.spec.js b/src/helpers/heritage-integration/cookie-helper.spec.js
index 8abd265e5..349b2206a 100644
--- a/src/helpers/heritage-integration/cookie-helper.spec.js
+++ b/src/helpers/heritage-integration/cookie-helper.spec.js
@@ -5,6 +5,8 @@ import {
getSessionIdValue,
setCookieProperties,
regenerateDeviceId,
+ getUserIdValue,
+ regenerateUserId,
} from "@/helpers/heritage-integration/cookie-helper.js";
import { cookieNames } from "@/constants/cookie-names";
import { removeAllTestCookies, setupCookies, setupCrypto } from "@/helpers/unit-test-helper";
@@ -139,9 +141,13 @@ describe("cookies", () => {
test("Should return id even if cookie contains other data", () => {
//Arrange
- setCookieProperties({
- [cookieNames.DXDEV]: "did=f4a1a9e8-b3f3-4936-8c30-2f06a98644af&tz=-300&tzd=1",
- }, {});
+ setCookieProperties(
+ {
+ [cookieNames.DXDEV]:
+ "did=f4a1a9e8-b3f3-4936-8c30-2f06a98644af&tz=-300&tzd=1",
+ },
+ {}
+ );
//Act
const result = getDeviceIdValue();
@@ -178,6 +184,56 @@ describe("cookies", () => {
});
});
+ describe("User Id", () => {
+ describe("getUserIdValue", () => {
+ test("Should return GUID", () => {
+ // Arrange
+ setupCookies({});
+
+ // Act
+ const result = getUserIdValue();
+
+ //Assert
+ expect(result).toBe("11aec5e8-92ba-4dc9-a8b6-179a916d8d7a");
+ });
+
+ test("Should return 0s if unset", () => {
+ //Arrange
+ //Act
+ const result = getUserIdValue();
+
+ //Assert
+ expect(result).toBe("00000000-0000-0000-0000-000000000000");
+ });
+ });
+
+ describe("regenerateUserId", () => {
+ test("Generates a new id if unset", () => {
+ // Arrange
+ // Act
+ regenerateUserId();
+ const result = getUserIdValue();
+
+ // Assert
+ expect(result).not.toBe("00000000-0000-0000-0000-000000000000");
+ expect(global.crypto.randomUUID).toBeCalled();
+ });
+
+ test("Does not create a new id if already set", () => {
+ // Arrange
+ setupCookies({});
+
+ // Act
+ regenerateUserId();
+ const result = getUserIdValue();
+
+ // Assert
+ expect(result).toBe("11aec5e8-92ba-4dc9-a8b6-179a916d8d7a");
+ expect(global.crypto.randomUUID).not.toBeCalled();
+ });
+ });
+ });
+
test("getSessionKeyValue, should return session key int", () => {
// Arrange
setupCookies({});
diff --git a/src/helpers/unit-test-helper.js b/src/helpers/unit-test-helper.js
index 457dd47fb..2cd580df0 100644
--- a/src/helpers/unit-test-helper.js
+++ b/src/helpers/unit-test-helper.js
@@ -141,7 +141,7 @@ export function setupCookies({ funnelCookieValue = "", includeHeritageCookie = t
export function setupCrypto(mockValue) {
global.crypto = {
- randomUUID: jest.fn()
+ randomUUID: jest.fn(),
};
global.crypto.randomUUID.mockImplementation(() => mockValue);
From 736aee68e990e82d5f862890661fc7c84ab396d3 Mon Sep 17 00:00:00 2001
From: Chloe Herd
Date: Tue, 5 Dec 2023 11:46:31 -0500
Subject: [PATCH 26/36] Session Key
---
.../cookie-helper.spec.js | 54 ++++++++++++++++---
1 file changed, 47 insertions(+), 7 deletions(-)
diff --git a/src/helpers/heritage-integration/cookie-helper.spec.js b/src/helpers/heritage-integration/cookie-helper.spec.js
index 349b2206a..c5cbc5bee 100644
--- a/src/helpers/heritage-integration/cookie-helper.spec.js
+++ b/src/helpers/heritage-integration/cookie-helper.spec.js
@@ -7,6 +7,7 @@ import {
regenerateDeviceId,
getUserIdValue,
regenerateUserId,
+ setSessionKeyIfUnset,
} from "@/helpers/heritage-integration/cookie-helper.js";
import { cookieNames } from "@/constants/cookie-names";
import { removeAllTestCookies, setupCookies, setupCrypto } from "@/helpers/unit-test-helper";
@@ -234,15 +235,54 @@ describe("cookies", () => {
});
});
- test("getSessionKeyValue, should return session key int", () => {
- // Arrange
- setupCookies({});
+ describe("Session Key", () => {
+ describe("getSessionKeyValue", () => {
+ test("Should return session key int", () => {
+ // Arrange
+ setupCookies({});
- // Act
- const result = getSessionKeyValue();
+ // Act
+ const result = getSessionKeyValue();
- //Assert
- expect(result).toBe("12345");
+ //Assert
+ expect(result).toBe("12345");
+ });
+
+ test("Should return 0 if unset", () => {
+ // Arrange
+
+ // Act
+ const result = getSessionKeyValue();
+
+ //Assert
+ expect(result).toBe(0);
+ });
+ });
+
+ describe("setSessionKeyIfUnset", () => {
+ test("Should set the cookie if not previously set", () => {
+ // Arrange
+
+ // Act
+ setSessionKeyIfUnset("54321");
+ const result = getSessionKeyValue();
+
+ // Assert
+ expect(result).toBe("54321");
+ });
+
+ test("Should not set the cookie if previously set", () => {
+ // Arrange
+ setupCookies({});
+
+ // Act
+ setSessionKeyIfUnset("54321");
+ const result = getSessionKeyValue();
+
+ // Assert
+ expect(result).toBe("12345");
+ });
+ });
});
describe("getSessionIdValue", () => {
From 1f0a0870c932fd2511129c4356c9695068c78220 Mon Sep 17 00:00:00 2001
From: Chloe Herd
Date: Tue, 5 Dec 2023 12:40:37 -0500
Subject: [PATCH 27/36] Session Id
---
.../cookie-helper.spec.js | 51 +++++++++++++++++++
1 file changed, 51 insertions(+)
diff --git a/src/helpers/heritage-integration/cookie-helper.spec.js b/src/helpers/heritage-integration/cookie-helper.spec.js
index c5cbc5bee..99a502559 100644
--- a/src/helpers/heritage-integration/cookie-helper.spec.js
+++ b/src/helpers/heritage-integration/cookie-helper.spec.js
@@ -8,6 +8,7 @@ import {
getUserIdValue,
regenerateUserId,
setSessionKeyIfUnset,
+ setSessionIdIfUnset,
} from "@/helpers/heritage-integration/cookie-helper.js";
import { cookieNames } from "@/constants/cookie-names";
import { removeAllTestCookies, setupCookies, setupCrypto } from "@/helpers/unit-test-helper";
@@ -285,6 +286,56 @@ describe("cookies", () => {
});
});
+ describe("Session Id", () => {
+ describe("getSessionIdValue", () => {
+ test("Should return session id", () => {
+ // Arrange
+ setupCookies({});
+
+ // Act
+ const result = getSessionIdValue();
+
+ //Assert
+ expect(result).toBe("cba0c3d1-3c1b-4305-bb56-31aa50f58e27");
+ });
+
+ test("Should return 0s if unset", () => {
+ // Arrange
+
+ // Act
+ const result = getSessionIdValue();
+
+ //Assert
+ expect(result).toBe("00000000-0000-0000-0000-000000000000");
+ });
+ });
+
+ describe("setSessionIdIfUnset", () => {
+ test("Should set the cookie if not previously set", () => {
+ // Arrange
+
+ // Act
+ setSessionIdIfUnset("f01f463a-a02c-4d1a-8aaf-6ca920ae5f02");
+ const result = getSessionIdValue();
+
+ // Assert
+ expect(result).toBe("f01f463a-a02c-4d1a-8aaf-6ca920ae5f02");
+ });
+
+ test("Should not set the cookie if previously set", () => {
+ // Arrange
+ setupCookies({});
+
+ // Act
+ setSessionIdIfUnset("f01f463a-a02c-4d1a-8aaf-6ca920ae5f02");
+ const result = getSessionIdValue();
+
+ // Assert
+ expect(result).toBe("cba0c3d1-3c1b-4305-bb56-31aa50f58e27");
+ });
+ });
+ });
+
describe("getSessionIdValue", () => {
test("getSessionIdValue, should return GUID", () => {
// Arrange
From 48756a9683262c4c4af4ecaf78c923b4bdeafec1 Mon Sep 17 00:00:00 2001
From: Chloe Herd
Date: Tue, 5 Dec 2023 12:44:01 -0500
Subject: [PATCH 28/36] Cleanup
---
.../heritage-integration/cookie-helper.spec.js | 13 -------------
1 file changed, 13 deletions(-)
diff --git a/src/helpers/heritage-integration/cookie-helper.spec.js b/src/helpers/heritage-integration/cookie-helper.spec.js
index 99a502559..73cc388d6 100644
--- a/src/helpers/heritage-integration/cookie-helper.spec.js
+++ b/src/helpers/heritage-integration/cookie-helper.spec.js
@@ -335,17 +335,4 @@ describe("cookies", () => {
});
});
});
-
- describe("getSessionIdValue", () => {
- test("getSessionIdValue, should return GUID", () => {
- // Arrange
- setupCookies({});
-
- // Act
- const result = getSessionIdValue();
-
- //Assert
- expect(result).toBe("cba0c3d1-3c1b-4305-bb56-31aa50f58e27");
- });
- });
});
From 4be83e96493cdd5a5a6d16634995c6d1f2e7d8be Mon Sep 17 00:00:00 2001
From: Chloe Herd
Date: Tue, 5 Dec 2023 13:08:41 -0500
Subject: [PATCH 29/36] Is Cookie Set
---
.../cookie-helper.spec.js | 40 +++++++++++++++++++
1 file changed, 40 insertions(+)
diff --git a/src/helpers/heritage-integration/cookie-helper.spec.js b/src/helpers/heritage-integration/cookie-helper.spec.js
index 73cc388d6..55b4a73ff 100644
--- a/src/helpers/heritage-integration/cookie-helper.spec.js
+++ b/src/helpers/heritage-integration/cookie-helper.spec.js
@@ -9,6 +9,7 @@ import {
regenerateUserId,
setSessionKeyIfUnset,
setSessionIdIfUnset,
+ isCookieSet,
} from "@/helpers/heritage-integration/cookie-helper.js";
import { cookieNames } from "@/constants/cookie-names";
import { removeAllTestCookies, setupCookies, setupCrypto } from "@/helpers/unit-test-helper";
@@ -335,4 +336,43 @@ describe("cookies", () => {
});
});
});
+
+ describe("isCookieSet", () => {
+ test("Returns true if cookie is set and unexpired", () => {
+ // Arrange
+ setupCookies({});
+
+ // Act
+ const result = isCookieSet(cookieNames.SESSION_ID);
+
+ // Assert
+ expect(result).toBe(true);
+ });
+
+ test("Returns false if never set", () => {
+ // Arrange
+ // Act
+ const result = isCookieSet(cookieNames.SESSION_ID);
+
+ // Assert
+ expect(result).toBe(false);
+ });
+
+ test("Returns false if cookie is expired", () => {
+ // Arrange
+ setupCookies({});
+
+ // Act
+ setCookieProperties(
+ {
+ [cookieNames.SESSION_ID]: "test",
+ },
+ { maxAge: 0 }
+ );
+ const result = isCookieSet(cookieNames.SESSION_ID);
+
+ // Assert
+ expect(result).toBe(false);
+ });
+ });
});
From 67c9b1609bd1cd9422969c52beebefa4739149de Mon Sep 17 00:00:00 2001
From: Chloe Herd
Date: Tue, 5 Dec 2023 14:00:28 -0500
Subject: [PATCH 30/36] Final cookie tests
---
.../cookie-helper.spec.js | 26 +++++++++++++++++++
1 file changed, 26 insertions(+)
diff --git a/src/helpers/heritage-integration/cookie-helper.spec.js b/src/helpers/heritage-integration/cookie-helper.spec.js
index 55b4a73ff..0929e0ed6 100644
--- a/src/helpers/heritage-integration/cookie-helper.spec.js
+++ b/src/helpers/heritage-integration/cookie-helper.spec.js
@@ -10,6 +10,7 @@ import {
setSessionKeyIfUnset,
setSessionIdIfUnset,
isCookieSet,
+ refreshCookieExpiration,
} from "@/helpers/heritage-integration/cookie-helper.js";
import { cookieNames } from "@/constants/cookie-names";
import { removeAllTestCookies, setupCookies, setupCrypto } from "@/helpers/unit-test-helper";
@@ -375,4 +376,29 @@ describe("cookies", () => {
expect(result).toBe(false);
});
});
+
+ describe("refreshCookieExpiration", () => {
+ test("Preserves value", () => {
+ // Arrange
+ setupCookies({});
+
+ // Act
+ const result1 = getSessionIdValue();
+ refreshCookieExpiration(cookieNames.SESSION_ID, 1000000);
+ const result2 = getSessionIdValue();
+
+ // Assert
+ expect(result1).toBe(result2);
+ });
+
+ test("Does not set cookie if not already set", () => {
+ // Arrange
+
+ // Act
+ refreshCookieExpiration(cookieNames.SESSION_ID, 1000000);
+ const result = isCookieSet(cookieNames.SESSION_ID);
+
+ expect(result).toBe(false);
+ });
+ });
});
From ef5a6a55e3771edf64706ca3f79feed281e92b34 Mon Sep 17 00:00:00 2001
From: Chloe Herd
Date: Tue, 5 Dec 2023 14:08:05 -0500
Subject: [PATCH 31/36] Properly mock crypto module
---
src/mixins/analytics-mixin.spec.js | 17 +++++------------
1 file changed, 5 insertions(+), 12 deletions(-)
diff --git a/src/mixins/analytics-mixin.spec.js b/src/mixins/analytics-mixin.spec.js
index 8f7cfceaa..7e04215af 100644
--- a/src/mixins/analytics-mixin.spec.js
+++ b/src/mixins/analytics-mixin.spec.js
@@ -1,5 +1,5 @@
import analyticsMixin from "@/mixins/analytics-mixin";
-import { setupMocksForJsFiles, setupCookies } from "@/helpers/unit-test-helper.js";
+import { setupMocksForJsFiles, setupCookies, setupCrypto } from "@/helpers/unit-test-helper.js";
import { storeActions } from "@/constants/store-actions";
import {
analyticsPageEvents,
@@ -11,19 +11,12 @@ import {
} from "@/constants/analytics";
import store from "@/store";
-// Mock only the regenerate functions; window.crypto is not available in testing.
-jest.mock("@/helpers/heritage-integration/cookie-helper", () => {
- const originalModule = jest.requireActual("@/helpers/heritage-integration/cookie-helper");
-
- return {
- __esModule: true,
- ...originalModule,
- regenerateDeviceId: jest.fn(),
- regenerateUserId: jest.fn(),
- };
-});
describe("analyticsMixin.js", () => {
+ beforeEach(() => {
+ setupCrypto();
+ });
+
test("logPageView: calls dispatch with type and payload", async () => {
const type = "";
const payload = {};
From 9b9001d67a36b9f00fc0302fe6b3f0394a448eed Mon Sep 17 00:00:00 2001
From: Chloe Herd
Date: Tue, 5 Dec 2023 18:06:12 -0500
Subject: [PATCH 32/36] Tests for initsession
---
src/mixins/analytics-mixin.spec.js | 133 ++++++++++++++++++++++++++++-
1 file changed, 130 insertions(+), 3 deletions(-)
diff --git a/src/mixins/analytics-mixin.spec.js b/src/mixins/analytics-mixin.spec.js
index 7e04215af..567d9154e 100644
--- a/src/mixins/analytics-mixin.spec.js
+++ b/src/mixins/analytics-mixin.spec.js
@@ -1,5 +1,10 @@
import analyticsMixin from "@/mixins/analytics-mixin";
-import { setupMocksForJsFiles, setupCookies, setupCrypto } from "@/helpers/unit-test-helper.js";
+import {
+ setupMocksForJsFiles,
+ setupCookies,
+ setupCrypto,
+ removeAllTestCookies,
+} from "@/helpers/unit-test-helper.js";
import { storeActions } from "@/constants/store-actions";
import {
analyticsPageEvents,
@@ -10,11 +15,17 @@ import {
ValueToLogTypes,
} from "@/constants/analytics";
import store from "@/store";
-
+import {
+ getDeviceIdValue,
+ getSessionIdValue,
+ getSessionKeyValue,
+ getUserIdValue,
+} from "@/helpers/heritage-integration/cookie-helper";
describe("analyticsMixin.js", () => {
beforeEach(() => {
- setupCrypto();
+ removeAllTestCookies();
+ setupCrypto("7e4727f3-9a3d-4c59-9cb3-6f4121b5ea94");
});
test("logPageView: calls dispatch with type and payload", async () => {
@@ -341,4 +352,120 @@ describe("analyticsMixin.js", () => {
//Assert
expect(gaLabels).toEqual(GaLabels);
});
+ describe("initSession", () => {
+ test("Generates random values for userId and deviceId if not present", async () => {
+ // Arrange
+ const mockData = {
+ actionList: [
+ {
+ actionName: storeActions.LOG_CUSTOM_EVENT,
+ },
+ {
+ actionName: storeActions.INITIALIZE_SESSION,
+ data: {
+ sessionKey: "12345",
+ sessionId: "4f1eba4a-4dd5-4144-9a6b-1363c1e5e54f",
+ },
+ },
+ ],
+ };
+ const mocks = setupMocksForJsFiles(mockData);
+
+ // Act
+ await analyticsMixin.methods.initSession();
+ const userId = getUserIdValue();
+ const deviceId = getDeviceIdValue();
+
+ // Assert
+ expect(userId).not.toBe("00000000-0000-0000-0000-000000000000");
+ expect(deviceId).not.toBe("00000000-0000-0000-0000-000000000000");
+ });
+
+ test("Pulls sessionId and sessionKey from api if not set", async () => {
+ // Arrange
+ const mockData = {
+ actionList: [
+ {
+ actionName: storeActions.LOG_CUSTOM_EVENT,
+ },
+ {
+ actionName: storeActions.INITIALIZE_SESSION,
+ data: {
+ sessionKey: "54321",
+ sessionId: "4f1eba4a-4dd5-4144-9a6b-1363c1e5e54f",
+ },
+ },
+ ],
+ };
+ const mocks = setupMocksForJsFiles(mockData);
+
+ // Act
+ await analyticsMixin.methods.initSession();
+ const sessionId = getSessionIdValue();
+ const sessionKey = getSessionKeyValue();
+
+ // Assert
+ expect(sessionId).toBe("4f1eba4a-4dd5-4144-9a6b-1363c1e5e54f");
+ expect(sessionKey).toBe("54321");
+ });
+
+ test("Does not overwrite values that are already set", async () => {
+ // Arrange
+ const mockData = {
+ actionList: [
+ {
+ actionName: storeActions.LOG_CUSTOM_EVENT,
+ },
+ {
+ actionName: storeActions.INITIALIZE_SESSION,
+ data: {
+ sessionKey: "54321",
+ sessionId: "4f1eba4a-4dd5-4144-9a6b-1363c1e5e54f",
+ },
+ },
+ ],
+ };
+ const mocks = setupMocksForJsFiles(mockData);
+ setupCookies({});
+
+ // Act
+ await analyticsMixin.methods.initSession();
+
+ const userId = getUserIdValue();
+ const deviceId = getDeviceIdValue();
+ const sessionId = getSessionIdValue();
+ const sessionKey = getSessionKeyValue();
+
+ // Assert
+ expect(userId).toBe("11aec5e8-92ba-4dc9-a8b6-179a916d8d7a");
+ expect(deviceId).toBe("21b9b94a-ec23-42c1-aaac-e2ae4e4dbffe");
+ expect(sessionId).toBe("cba0c3d1-3c1b-4305-bb56-31aa50f58e27");
+ expect(sessionKey).toBe("12345");
+ });
+
+ test("Calls dispatchStoreAction", async () => {
+ // Arrange
+ const mockData = {
+ actionList: [
+ {
+ actionName: storeActions.LOG_CUSTOM_EVENT,
+ },
+ {
+ actionName: storeActions.INITIALIZE_SESSION,
+ data: {
+ sessionKey: "12345",
+ sessionId: "4f1eba4a-4dd5-4144-9a6b-1363c1e5e54f",
+ },
+ },
+ ],
+ };
+ const mocks = setupMocksForJsFiles(mockData);
+
+ // Act
+ await analyticsMixin.methods.initSession();
+
+ // Assert
+ expect(mocks.baseMixin.methods.dispatchStoreAction).toBeCalled();
+ });
+ });
});
From be4524e5adf464647da408c3a5955a42ff9de21c Mon Sep 17 00:00:00 2001
From: Chloe Herd
Date: Wed, 6 Dec 2023 10:19:11 -0500
Subject: [PATCH 33/36] Loader tests
---
src/ux-components/loader/loader.spec.js | 54 +++++++++++++++++++++++++
1 file changed, 54 insertions(+)
diff --git a/src/ux-components/loader/loader.spec.js b/src/ux-components/loader/loader.spec.js
index fb1eea21e..d56c4e0ed 100644
--- a/src/ux-components/loader/loader.spec.js
+++ b/src/ux-components/loader/loader.spec.js
@@ -28,4 +28,58 @@ describe("loader.vue", () => {
loaderPosition: "left",
});
});
+
+ describe("Blocking interaction on page", () => {
+ test("Does capture clicks if enabled (default)", async () => {
+ // Arrange
+ const div = document.createElement("div");
+ div.id = "parent";
+ document.body.appendChild(div);
+
+ const parentClickFn = jest.fn();
+
+ div.addEventListener("click", parentClickFn);
+
+ const wrapper = shallowMount(loader, {
+ props: {},
+ attachTo: "#parent",
+ });
+
+ // Act
+ await wrapper.trigger("click");
+
+ // Assert
+ expect(parentClickFn).not.toBeCalled();
+
+ // Cleanup
+ document.body.removeChild(div);
+ });
+
+ test("Does not capture clicks if disabled", async () => {
+ // Arrange
+ const div = document.createElement("div");
+ div.id = "parent";
+ document.body.appendChild(div);
+
+ const parentClickFn = jest.fn();
+
+ div.addEventListener("click", parentClickFn);
+
+ const wrapper = shallowMount(loader, {
+ props: {
+ allowPageInteraction: true,
+ },
+ attachTo: "#parent",
+ });
+
+ // Act
+ await wrapper.trigger("click");
+
+ // Assert
+ expect(parentClickFn).toBeCalled();
+
+ // Cleanup
+ document.body.removeChild(div);
+ });
+ });
});
From 8b7229608c37aef4894db7fabb864a559a508ab2 Mon Sep 17 00:00:00 2001
From: Bryan Mauger
Date: Wed, 6 Dec 2023 10:37:18 -0500
Subject: [PATCH 34/36] CSR-1729 add label copy for textarea.
---
.../textarea-question/textarea-question.vue | 33 +++++++++++--------
.../customer-details/customer-details.vue | 1 +
2 files changed, 20 insertions(+), 14 deletions(-)
diff --git a/src/digital-components/textarea-question/textarea-question.vue b/src/digital-components/textarea-question/textarea-question.vue
index eda3a6f9c..27eeda216 100644
--- a/src/digital-components/textarea-question/textarea-question.vue
+++ b/src/digital-components/textarea-question/textarea-question.vue
@@ -1,12 +1,13 @@
-
+
- {{ remainingCount }}/{{ maxLength }} characters remaining
-
-
+ tabindex="-1"
+ class="caption mt-2 mb-0 w-100"
+ id="charactersRemaining"
+ :class="[urgentCountdown ? 'urgent-countdown' : '']">
+ {{ remainingCount }}/{{ maxLength }} characters remaining
+
+
+
-