Initial adds for analytics and logging.
This commit is contained in:
parent
05844d2500
commit
ce5b402cbd
14 changed files with 2151 additions and 0 deletions
36
src/constants/analytics.js
Normal file
36
src/constants/analytics.js
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
const analyticsPageEvents = {
|
||||||
|
ENTRY: "ENTRY",
|
||||||
|
EVENT: "EVENT",
|
||||||
|
};
|
||||||
|
|
||||||
|
// GA Constants
|
||||||
|
const GaEvents = {
|
||||||
|
GENERIC_EVENT: "event",
|
||||||
|
PAGE_VIEW_EVENT: "logPageview",
|
||||||
|
};
|
||||||
|
|
||||||
|
const GaCategories = {
|
||||||
|
API_RESPONSE: "Api_Response",
|
||||||
|
EVOX: "Evox",
|
||||||
|
};
|
||||||
|
|
||||||
|
const GaActions = {
|
||||||
|
RESULT: "Result",
|
||||||
|
CLICKED: "Clicked",
|
||||||
|
VIF: "vif",
|
||||||
|
SUBMITTED: "Submitted",
|
||||||
|
};
|
||||||
|
|
||||||
|
const GaLabels = {
|
||||||
|
SUCCESS: "Success",
|
||||||
|
ERROR: "Error",
|
||||||
|
LICENSE_PLATE_LOOKUP: "License_Plate_Look_Up",
|
||||||
|
VIN_LOOKUP: "Vin_Look_Up",
|
||||||
|
ADDRESS_LOOKUP: "Address_Look_up",
|
||||||
|
};
|
||||||
|
|
||||||
|
const ValueToLogTypes = {
|
||||||
|
LAST_5: "last_5",
|
||||||
|
};
|
||||||
|
|
||||||
|
export { analyticsPageEvents, GaCategories, GaActions, GaLabels, GaEvents, ValueToLogTypes };
|
||||||
12
src/constants/cookie-names.js
Normal file
12
src/constants/cookie-names.js
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
import { applicationConfig } from "@/constants/application-config.js";
|
||||||
|
|
||||||
|
const cookieNames = {
|
||||||
|
FUNNEL_SESSION_INFO: `FunnelSessionInfo-${applicationConfig.CURRENT_ENVIRONMENT}`,
|
||||||
|
|
||||||
|
// Existing Safelite.com cookies
|
||||||
|
DXDEV: "dxdev",
|
||||||
|
SESSION_ID: "sid",
|
||||||
|
SESSION_KEY: "skey",
|
||||||
|
};
|
||||||
|
|
||||||
|
export { cookieNames };
|
||||||
14
src/constants/experiments.js
Normal file
14
src/constants/experiments.js
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
const experimentUniverses = {
|
||||||
|
CONCEPT_FUNNEL: "ConceptFunnel",
|
||||||
|
};
|
||||||
|
|
||||||
|
const experimentSettings = {
|
||||||
|
GOOGLE_CUSTOM_DIMENSION_INDEX: "Google Custom Dimension Index",
|
||||||
|
};
|
||||||
|
|
||||||
|
const experimentTriggers = {
|
||||||
|
SITE_ENTRY: "SiteEntry",
|
||||||
|
PAGE_ENTRY: "PageEntry",
|
||||||
|
};
|
||||||
|
|
||||||
|
export { experimentUniverses, experimentSettings, experimentTriggers };
|
||||||
209
src/helpers/heritage-integration/cookie-helper.js
Normal file
209
src/helpers/heritage-integration/cookie-helper.js
Normal file
|
|
@ -0,0 +1,209 @@
|
||||||
|
import { cookieNames } from "@/constants/cookie-names";
|
||||||
|
import store from "@/store";
|
||||||
|
import { applicationConfig } from "@/constants/application-config";
|
||||||
|
|
||||||
|
/*
|
||||||
|
Will update the cookie if present, or create a new one if not.
|
||||||
|
*/
|
||||||
|
export function updateOrCreateFunnelCookie() {
|
||||||
|
const wasClaimRegistrationDelayed = getFunnelCookie()?.HasDelayedClaimRegistration;
|
||||||
|
const shouldSuppressConceptFunnel = getFunnelCookie()?.SuppressConceptFunnel;
|
||||||
|
|
||||||
|
// Set up cookie with all the props.
|
||||||
|
setFunnelCookieProperties({
|
||||||
|
LastTouched: new Date().toUTCString(),
|
||||||
|
SavedSessionTimeoutDate: store.getters.applicationUser.savedSessionTimeout,
|
||||||
|
DidHeritageFunnelUpdateLast: false,
|
||||||
|
ShouldResetState: false,
|
||||||
|
ReferralNumber: store.getters.order.referralNumber,
|
||||||
|
ReferralDate: store.getters.order.referralDate,
|
||||||
|
ReferralCorrelationId: store.getters.order.referralCorrelationId,
|
||||||
|
ReferralParentAccountNumber: store.getters.order.accountNumber,
|
||||||
|
HasDelayedClaimRegistration: wasClaimRegistrationDelayed,
|
||||||
|
SuppressConceptFunnel: shouldSuppressConceptFunnel,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Gets the current instance of the funnel cookie.
|
||||||
|
Returns null if cookie isn't valid JSON.
|
||||||
|
*/
|
||||||
|
export function getFunnelCookie() {
|
||||||
|
const cookieJson = document.cookie
|
||||||
|
?.split("; ")
|
||||||
|
?.find((row) => row.startsWith(`${cookieNames.FUNNEL_SESSION_INFO}=`))
|
||||||
|
?.split("=")[1];
|
||||||
|
|
||||||
|
try {
|
||||||
|
return JSON.parse(cookieJson);
|
||||||
|
} catch (error) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Removes cookie from browser.
|
||||||
|
*/
|
||||||
|
export function deleteFunnelCookie() {
|
||||||
|
createOrUpdateCookie(cookieNames.FUNNEL_SESSION_INFO, undefined, { maxAge: 0 });
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Gets cookie domain value. Localhost will be empty "".
|
||||||
|
*/
|
||||||
|
export function getCookieDomainValue() {
|
||||||
|
return isLocalhost() ? "" : `domain=${getDomainWithoutSubdomain()};`;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Gets value of dxdev cookie, and then extracts "did" value from it.
|
||||||
|
Returns empty string if cookie not found or "did" string not present.
|
||||||
|
*/
|
||||||
|
export function getDeviceIdValue() {
|
||||||
|
// Sometimes these cookie contains more than the device ID.
|
||||||
|
const cookieValue = getCookieValueByName(cookieNames.DXDEV);
|
||||||
|
const cookieValuesSplit = cookieValue.split("=");
|
||||||
|
|
||||||
|
// If this is the only value, just use that.
|
||||||
|
if (cookieValuesSplit.length === 2 && cookieValuesSplit[0] === "did") {
|
||||||
|
return cookieValuesSplit[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
const cookieValueMatch = cookieValue.match("^did=[a-f0-9]{8}(?:-[a-f0-9]{4}){3}-[a-f0-9]{12}");
|
||||||
|
if (cookieValueMatch) {
|
||||||
|
return cookieValueMatch[0].split("=")[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
return "00000000-0000-0000-0000-000000000000";
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Gets value of skey cookie, returns 0 if not found.
|
||||||
|
*/
|
||||||
|
export function getSessionKeyValue() {
|
||||||
|
const cookieValue = getCookieValueByName(cookieNames.SESSION_KEY);
|
||||||
|
|
||||||
|
if (cookieValue) {
|
||||||
|
return cookieValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Gets value of skey cookie, returns 0 if not found.
|
||||||
|
*/
|
||||||
|
export function getSessionIdValue() {
|
||||||
|
const cookieValue = getCookieValueByName(cookieNames.SESSION_ID);
|
||||||
|
|
||||||
|
if (cookieValue) {
|
||||||
|
return cookieValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return "00000000-0000-0000-0000-000000000000";
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Updates session ID cookie with new expiration date
|
||||||
|
*/
|
||||||
|
export function updateSessionIdCookie() {
|
||||||
|
createOrUpdateCookie(cookieNames.SESSION_ID, getSessionIdValue(), { maxAge: 60 * 30 });
|
||||||
|
}
|
||||||
|
|
||||||
|
export function setCookieProperties(
|
||||||
|
properties,
|
||||||
|
{ useDefaultFunnelCookieAttributes = true, maxAge, isSecure }
|
||||||
|
) {
|
||||||
|
if (typeof properties == "object") {
|
||||||
|
Object.keys(properties).forEach((key) => {
|
||||||
|
createOrUpdateCookie(key, properties[key], {
|
||||||
|
useDefaultFunnelCookieAttributes,
|
||||||
|
maxAge,
|
||||||
|
isSecure,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
===========================
|
||||||
|
= PRIVATE FUNCTIONS =
|
||||||
|
===========================
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
Used to set properties on the funnel cookie.
|
||||||
|
Takes an object with properties to set. Will overwrite existing properties.
|
||||||
|
*/
|
||||||
|
function setFunnelCookieProperties(properties) {
|
||||||
|
if (typeof properties == "object") {
|
||||||
|
let cookie = getFunnelCookie();
|
||||||
|
|
||||||
|
if (cookie !== null) {
|
||||||
|
Object.keys(properties).forEach((key) => {
|
||||||
|
cookie[key] = properties[key];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const cookieValueJson = JSON.stringify(cookie ?? {});
|
||||||
|
createOrUpdateCookie(cookieNames.FUNNEL_SESSION_INFO, cookieValueJson, {});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Used to create a cookie.
|
||||||
|
`useDefaultFunnelCookieAttributes` will set the path and domain to our defaults
|
||||||
|
*/
|
||||||
|
function createOrUpdateCookie(
|
||||||
|
key,
|
||||||
|
value = "",
|
||||||
|
{ useDefaultFunnelCookieAttributes = true, maxAge, isSecure = true }
|
||||||
|
) {
|
||||||
|
let cookieToAdd = `${key}=${value}; `;
|
||||||
|
|
||||||
|
if (useDefaultFunnelCookieAttributes) {
|
||||||
|
cookieToAdd += `path=${applicationConfig.COOKIE_PATH}; ${getCookieDomainValue()} `;
|
||||||
|
}
|
||||||
|
if (isSecure && !isLocalhost()) {
|
||||||
|
cookieToAdd += `secure; `;
|
||||||
|
}
|
||||||
|
if (!isNaN(maxAge)) {
|
||||||
|
cookieToAdd += `max-age=${maxAge};`;
|
||||||
|
}
|
||||||
|
|
||||||
|
document.cookie = cookieToAdd;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Gets current domain without the subdomain for cookie.
|
||||||
|
*/
|
||||||
|
function getDomainWithoutSubdomain() {
|
||||||
|
let url = location.hostname;
|
||||||
|
if (isLocalhost()) {
|
||||||
|
return "localhost";
|
||||||
|
}
|
||||||
|
|
||||||
|
const urlParts = url.split(".");
|
||||||
|
|
||||||
|
return `.${urlParts
|
||||||
|
.slice(0)
|
||||||
|
.slice(-(urlParts.length === 4 ? 3 : 2))
|
||||||
|
.join(".")}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Gets cookie value by name, returns empty string if not found.
|
||||||
|
*/
|
||||||
|
function getCookieValueByName(name) {
|
||||||
|
const value = "; " + document.cookie;
|
||||||
|
const parts = value.split("; " + name + "=");
|
||||||
|
|
||||||
|
if (parts.length === 2) {
|
||||||
|
return parts.pop().split(";").shift();
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
function isLocalhost() {
|
||||||
|
return location.hostname.includes("localhost");
|
||||||
|
}
|
||||||
145
src/helpers/heritage-integration/cookie-helper.spec.js
Normal file
145
src/helpers/heritage-integration/cookie-helper.spec.js
Normal file
|
|
@ -0,0 +1,145 @@
|
||||||
|
import {
|
||||||
|
getFunnelCookie,
|
||||||
|
getDeviceIdValue,
|
||||||
|
getSessionKeyValue,
|
||||||
|
getSessionIdValue,
|
||||||
|
} from "@/helpers/heritage-integration/cookie-helper.js";
|
||||||
|
import { removeAllTestCookies, setupCookies } from "@/helpers/unit-test-helper";
|
||||||
|
|
||||||
|
describe("cookies", () => {
|
||||||
|
afterEach(() => {
|
||||||
|
removeAllTestCookies();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("getFunnelCookie method", () => {
|
||||||
|
test("gets correct value when cookie is present", () => {
|
||||||
|
// Arrange
|
||||||
|
const testReferralNumber = 1566818;
|
||||||
|
const testReferralDate = "2022-03-15T10:56:24.597";
|
||||||
|
const testReferralCorrelationId = "404d2b04-f86e-45c3-b373-127b6217b060";
|
||||||
|
const testShouldResetState = false;
|
||||||
|
const testDidHeritageFunnelUpdateLast = true;
|
||||||
|
|
||||||
|
const testCookieValue = {
|
||||||
|
ReferralNumber: testReferralNumber,
|
||||||
|
ReferralDate: testReferralDate,
|
||||||
|
ReferralCorrelationId: testReferralCorrelationId,
|
||||||
|
ShouldResetState: testShouldResetState,
|
||||||
|
DidHeritageFunnelUpdateLast: testDidHeritageFunnelUpdateLast,
|
||||||
|
SuppressConceptFunnel: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
setupCookies({ funnelCookieValue: JSON.stringify(testCookieValue) });
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = getFunnelCookie();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(result).toEqual(testCookieValue);
|
||||||
|
expect(typeof result).toEqual("object");
|
||||||
|
expect(result.ReferralNumber).toEqual(testReferralNumber);
|
||||||
|
expect(result.ReferralDate).toEqual(testReferralDate);
|
||||||
|
expect(result.ReferralCorrelationId).toEqual(testReferralCorrelationId);
|
||||||
|
expect(result.ShouldResetState).toEqual(testShouldResetState);
|
||||||
|
expect(result.DidHeritageFunnelUpdateLast).toEqual(testDidHeritageFunnelUpdateLast);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("returns empty object when value is empty object", () => {
|
||||||
|
// Arrange
|
||||||
|
const testCookieValue = {};
|
||||||
|
setupCookies({ funnelCookieValue: JSON.stringify(testCookieValue) });
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = getFunnelCookie();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(result).toEqual(testCookieValue);
|
||||||
|
expect(typeof result).toEqual("object");
|
||||||
|
expect(Object.keys(result)).toHaveLength(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("returns null when value is empty string", () => {
|
||||||
|
// Arrange
|
||||||
|
const testCookieValue = "";
|
||||||
|
setupCookies({ funnelCookieValue: testCookieValue });
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = getFunnelCookie();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(result).toEqual(null);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("returns null when funnel cookie doesn't exist", () => {
|
||||||
|
// Arrange
|
||||||
|
setupCookies({ includeHeritageCookie: false });
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = getFunnelCookie();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(result).toEqual(null);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("gets correct cookie value", () => {
|
||||||
|
// Arrange
|
||||||
|
const testCookieValue = { test: "testValue" };
|
||||||
|
|
||||||
|
setupCookies({ funnelCookieValue: JSON.stringify(testCookieValue) });
|
||||||
|
|
||||||
|
// Act
|
||||||
|
const actualCookieValue = getFunnelCookie();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(actualCookieValue).toEqual(testCookieValue);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("getCookieValue: Gets null cookie value", () => {
|
||||||
|
// Arrange
|
||||||
|
setupCookies({ includeHeritageCookie: false });
|
||||||
|
|
||||||
|
// Act
|
||||||
|
const actualCookieValue = getFunnelCookie();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(actualCookieValue).toBeNull();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("getDeviceIdValue", () => {
|
||||||
|
test("getDeviceIdValue, should return GUID", () => {
|
||||||
|
// Arrange
|
||||||
|
setupCookies({});
|
||||||
|
|
||||||
|
// Act
|
||||||
|
const result = getDeviceIdValue();
|
||||||
|
|
||||||
|
//Assert
|
||||||
|
expect(result).toBe("21b9b94a-ec23-42c1-aaac-e2ae4e4dbffe");
|
||||||
|
});
|
||||||
|
|
||||||
|
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
|
||||||
|
setupCookies({});
|
||||||
|
|
||||||
|
// Act
|
||||||
|
const result = getSessionIdValue();
|
||||||
|
|
||||||
|
//Assert
|
||||||
|
expect(result).toBe("cba0c3d1-3c1b-4305-bb56-31aa50f58e27");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
150
src/helpers/heritage-integration/navigation-helper.js
Normal file
150
src/helpers/heritage-integration/navigation-helper.js
Normal file
|
|
@ -0,0 +1,150 @@
|
||||||
|
import { queryStrings } from "@/constants/query-strings";
|
||||||
|
import { externalUrls } from "@/router/router-constants/externalUrl-values";
|
||||||
|
import { lazyLoadComponent } from "@/router/dynamic-routing/component-loader.js";
|
||||||
|
import { saveSession } from "@/helpers/heritage-integration/order-helper.js";
|
||||||
|
import { fmgPageValues } from "@/router/router-constants/fmgPage-values";
|
||||||
|
import store from "@/store";
|
||||||
|
import router from "@/router";
|
||||||
|
|
||||||
|
/*
|
||||||
|
If the user has visited the funnel before this method will determine the bets place to
|
||||||
|
drop them so they don't start at the beginning again. This method will return 'heritage' if
|
||||||
|
the user has an existing order and they come back in from the Safelite.com CTA.
|
||||||
|
*/
|
||||||
|
export async function getPageToRouteExistingOrderTo(toRoute = {}, existingHeritageOrder = false) {
|
||||||
|
// If the user is coming in via the Safelite.Com CTA
|
||||||
|
if (toRoute.query[queryStrings.START_TYPE] === "fmg") {
|
||||||
|
// If they have an existing order, return 'heritage' for the page name.
|
||||||
|
if (existingHeritageOrder) {
|
||||||
|
return fmgPageValues.HERITAGE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return await getLatestPageForRedirection();
|
||||||
|
}
|
||||||
|
|
||||||
|
// If navigating to a specific page, and that page is not part of the vin pages.
|
||||||
|
// Return that page, so that it can navigate like normal.
|
||||||
|
if (toRoute.query[queryStrings.FMG_PAGE] !== undefined && !isVinRelatedPage(toRoute)) {
|
||||||
|
return overrideYmmsDirectionIfNeeded(toRoute);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If this is not a direct link to a page using fmgPage, not from Safelite.com CTA or this is a vin related page.
|
||||||
|
// Get the latest page for redirection.
|
||||||
|
const latestPageRoute = await getLatestPageForRedirection();
|
||||||
|
|
||||||
|
return latestPageRoute;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Used to navigate to the heritage funnel with the correct query string and url.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export async function navigateToHeritageFunnel(shouldSaveSession = true) {
|
||||||
|
// Create the order (or save existing order) when navigating to Heritage Funnel.
|
||||||
|
if (shouldSaveSession) {
|
||||||
|
await saveSession();
|
||||||
|
}
|
||||||
|
|
||||||
|
router.navigateToExternalUrl(externalUrls.HERITAGE_FUNNEL, {
|
||||||
|
corid: store.getters.order.referralCorrelationId,
|
||||||
|
src: "concept-funnel",
|
||||||
|
conceptsqid: store.getters.applicationUser.savedSessionId,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Logic for getting the last "valid" page a user visited.
|
||||||
|
*/
|
||||||
|
async function getLatestPageForRedirection() {
|
||||||
|
// If this is a non-CTA navigation, determine where to send the user based on page prerequisites.
|
||||||
|
// This also works if a user has a 'fmg' start_type query string but no current order.
|
||||||
|
// That shouldn't happen, but it's possible.
|
||||||
|
const vehicleMakeComponent = await getLazyLoadedComponent(fmgPageValues.VEHICLE_MAKE);
|
||||||
|
const vehicleModelComponent = await getLazyLoadedComponent(fmgPageValues.VEHICLE_MODEL);
|
||||||
|
const vehicleStyleComponent = await getLazyLoadedComponent(fmgPageValues.VEHICLE_STYLE);
|
||||||
|
const vehicleDamageComponent = await getLazyLoadedComponent(fmgPageValues.VEHICLE_DAMAGE);
|
||||||
|
const estimateComponent = await getLazyLoadedComponent(fmgPageValues.ESTIMATE);
|
||||||
|
const vinLookupComponent = await getLazyLoadedComponent(fmgPageValues.VIN_LOOKUP);
|
||||||
|
const partQuestionsComponent = await getLazyLoadedComponent(fmgPageValues.PART_QUESTIONS);
|
||||||
|
const vehiclePartsComponent = await getLazyLoadedComponent(fmgPageValues.VEHICLE_PARTS);
|
||||||
|
const moldingQuestionsComponent = await getLazyLoadedComponent(fmgPageValues.MOLDING_QUESTIONS);
|
||||||
|
const capabilityQuestionsComponent = await getLazyLoadedComponent(
|
||||||
|
fmgPageValues.CAPABILITY_QUESTIONS
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!vehicleMakeComponent.methods.arePagePrerequisitesValid()) {
|
||||||
|
return fmgPageValues.VEHICLE_YEAR;
|
||||||
|
} else if (!vehicleModelComponent.methods.arePagePrerequisitesValid()) {
|
||||||
|
return fmgPageValues.VEHICLE_MAKE;
|
||||||
|
} else if (!vehicleStyleComponent.methods.arePagePrerequisitesValid()) {
|
||||||
|
return fmgPageValues.VEHICLE_MODEL;
|
||||||
|
} else if (!vehicleDamageComponent.methods.arePagePrerequisitesValid()) {
|
||||||
|
return fmgPageValues.VEHICLE_STYLE;
|
||||||
|
} else if (!estimateComponent.methods.arePagePrerequisitesValid()) {
|
||||||
|
return fmgPageValues.VEHICLE_DAMAGE;
|
||||||
|
} else {
|
||||||
|
if (capabilityQuestionsComponent.methods.arePagePrerequisitesValid()) {
|
||||||
|
return fmgPageValues.CAPABILITY_QUESTIONS;
|
||||||
|
} else if (moldingQuestionsComponent.methods.arePagePrerequisitesValid()) {
|
||||||
|
return fmgPageValues.MOLDING_QUESTIONS;
|
||||||
|
} else if (vehiclePartsComponent.methods.arePagePrerequisitesValid()) {
|
||||||
|
return fmgPageValues.VEHICLE_PARTS;
|
||||||
|
} else if (partQuestionsComponent.methods.arePagePrerequisitesValid()) {
|
||||||
|
return fmgPageValues.PART_QUESTIONS;
|
||||||
|
} else if (
|
||||||
|
vinLookupComponent.methods.arePagePrerequisitesValid() &&
|
||||||
|
!store.getters.damage.isRepair
|
||||||
|
) {
|
||||||
|
return fmgPageValues.VIN_LOOKUP;
|
||||||
|
} else {
|
||||||
|
return fmgPageValues.ESTIMATE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Overrides functionality to go to the YMMS pages in certain cases.
|
||||||
|
If this is not one of the cases, it returns the 'to' fmgPage value.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* istanbul ignore next */
|
||||||
|
function overrideYmmsDirectionIfNeeded(toRoute) {
|
||||||
|
const fmgPageValue = toRoute.query[queryStrings.FMG_PAGE];
|
||||||
|
|
||||||
|
if (store.getters.payment.insuranceCoverage.isVerified) {
|
||||||
|
switch (fmgPageValue) {
|
||||||
|
case fmgPageValues.VEHICLE_YEAR:
|
||||||
|
case fmgPageValues.VEHICLE_MAKE:
|
||||||
|
case fmgPageValues.VEHICLE_MODEL:
|
||||||
|
case fmgPageValues.VEHICLE_STYLE: {
|
||||||
|
return fmgPageValues.VEHICLE_DAMAGE;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
return fmgPageValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return fmgPageValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Determine if the page is a vin related page.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* istanbul ignore next */
|
||||||
|
function isVinRelatedPage(toRoute) {
|
||||||
|
const fmgPageValue = toRoute.query[queryStrings.FMG_PAGE];
|
||||||
|
|
||||||
|
return (
|
||||||
|
fmgPageValue === fmgPageValues.VIN_LOOKUP ||
|
||||||
|
fmgPageValue === fmgPageValues.LICENSE_PLATE_LOOKUP ||
|
||||||
|
fmgPageValue === fmgPageValues.ADDRESS_LOOKUP ||
|
||||||
|
fmgPageValue === fmgPageValues.ADDRESS_VEHICLES ||
|
||||||
|
fmgPageValue === fmgPageValues.ESTIMATE
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getLazyLoadedComponent(pageName) {
|
||||||
|
return (await lazyLoadComponent(pageName)()).default;
|
||||||
|
}
|
||||||
445
src/helpers/heritage-integration/navigation-helper.spec.js
Normal file
445
src/helpers/heritage-integration/navigation-helper.spec.js
Normal file
|
|
@ -0,0 +1,445 @@
|
||||||
|
import {
|
||||||
|
getPageToRouteExistingOrderTo,
|
||||||
|
navigateToHeritageFunnel,
|
||||||
|
} from "@/helpers/heritage-integration/navigation-helper";
|
||||||
|
import * as orderHelper from "@/helpers/heritage-integration/order-helper";
|
||||||
|
import { lazyLoadComponent } from "@/router/dynamic-routing/component-loader.js";
|
||||||
|
import { storeActions } from "@/constants/store-actions";
|
||||||
|
import { setupMocksForJsFiles, getMockOrderInfo } from "@/helpers/unit-test-helper.js";
|
||||||
|
import { externalUrls } from "@/router/router-constants/externalUrl-values";
|
||||||
|
import { queryStrings } from "@/constants/query-strings";
|
||||||
|
import { fmgPageValues } from "@/router/router-constants/fmgPage-values";
|
||||||
|
|
||||||
|
import store from "@/store";
|
||||||
|
import router from "@/router";
|
||||||
|
|
||||||
|
// Mock Lazy Load
|
||||||
|
jest.mock("@/router/dynamic-routing/component-loader.js", () => ({
|
||||||
|
lazyLoadComponent: jest.fn(),
|
||||||
|
}));
|
||||||
|
|
||||||
|
describe("getPageToRouteExistingOrderTo", () => {
|
||||||
|
test("should return vehicle-year", async () => {
|
||||||
|
// Arrange
|
||||||
|
const toRoute = {
|
||||||
|
query: {},
|
||||||
|
};
|
||||||
|
|
||||||
|
// Mock out the lazy load calls for all components.
|
||||||
|
mockLazyLoadComponentReturnValues({
|
||||||
|
[fmgPageValues.VEHICLE_MAKE]: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Act
|
||||||
|
const result = await getPageToRouteExistingOrderTo(toRoute, false);
|
||||||
|
|
||||||
|
//Assert
|
||||||
|
expect(result).toBe(fmgPageValues.VEHICLE_YEAR);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("should return vehicle-make", async () => {
|
||||||
|
// Arrange
|
||||||
|
const toRoute = {
|
||||||
|
query: {},
|
||||||
|
};
|
||||||
|
|
||||||
|
// Mock out the lazy load calls for all components.
|
||||||
|
mockLazyLoadComponentReturnValues({
|
||||||
|
[fmgPageValues.VEHICLE_MAKE]: true,
|
||||||
|
[fmgPageValues.VEHICLE_MODEL]: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Act
|
||||||
|
const result = await getPageToRouteExistingOrderTo(toRoute, false);
|
||||||
|
|
||||||
|
//Assert
|
||||||
|
expect(result).toBe(fmgPageValues.VEHICLE_MAKE);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("should return vehicle-model", async () => {
|
||||||
|
// Arrange
|
||||||
|
const toRoute = {
|
||||||
|
query: {},
|
||||||
|
};
|
||||||
|
|
||||||
|
// Mock out the lazy load calls for all components.
|
||||||
|
mockLazyLoadComponentReturnValues({
|
||||||
|
[fmgPageValues.VEHICLE_MAKE]: true,
|
||||||
|
[fmgPageValues.VEHICLE_MODEL]: true,
|
||||||
|
[fmgPageValues.VEHICLE_STYLE]: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Act
|
||||||
|
const result = await getPageToRouteExistingOrderTo(toRoute, false);
|
||||||
|
|
||||||
|
//Assert
|
||||||
|
expect(result).toBe(fmgPageValues.VEHICLE_MODEL);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("should return vehicle-style", async () => {
|
||||||
|
// Arrange
|
||||||
|
const toRoute = {
|
||||||
|
query: {},
|
||||||
|
};
|
||||||
|
|
||||||
|
// Mock out the lazy load calls for all components.
|
||||||
|
mockLazyLoadComponentReturnValues({
|
||||||
|
[fmgPageValues.VEHICLE_MAKE]: true,
|
||||||
|
[fmgPageValues.VEHICLE_MODEL]: true,
|
||||||
|
[fmgPageValues.VEHICLE_STYLE]: true,
|
||||||
|
[fmgPageValues.VEHICLE_DAMAGE]: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Act
|
||||||
|
const result = await getPageToRouteExistingOrderTo(toRoute, false);
|
||||||
|
|
||||||
|
//Assert
|
||||||
|
expect(result).toBe(fmgPageValues.VEHICLE_STYLE);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("should return vehicle-damage", async () => {
|
||||||
|
// Arrange
|
||||||
|
const toRoute = {
|
||||||
|
query: {},
|
||||||
|
};
|
||||||
|
|
||||||
|
// Mock out the lazy load calls for all components.
|
||||||
|
mockLazyLoadComponentReturnValues({
|
||||||
|
[fmgPageValues.VEHICLE_MAKE]: true,
|
||||||
|
[fmgPageValues.VEHICLE_MODEL]: true,
|
||||||
|
[fmgPageValues.VEHICLE_STYLE]: true,
|
||||||
|
[fmgPageValues.VEHICLE_DAMAGE]: true,
|
||||||
|
[fmgPageValues.ESTIMATE]: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Act
|
||||||
|
const result = await getPageToRouteExistingOrderTo(toRoute, false);
|
||||||
|
|
||||||
|
//Assert
|
||||||
|
expect(result).toBe(fmgPageValues.VEHICLE_DAMAGE);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("user has YMMS and no vehicle questions > should return vin-lookup", async () => {
|
||||||
|
// Arrange
|
||||||
|
const toRoute = {
|
||||||
|
query: {},
|
||||||
|
};
|
||||||
|
|
||||||
|
// Mock out the lazy load calls for all components.
|
||||||
|
mockLazyLoadComponentReturnValues({
|
||||||
|
[fmgPageValues.VEHICLE_MAKE]: true,
|
||||||
|
[fmgPageValues.VEHICLE_MODEL]: true,
|
||||||
|
[fmgPageValues.VEHICLE_STYLE]: true,
|
||||||
|
[fmgPageValues.VEHICLE_DAMAGE]: true,
|
||||||
|
[fmgPageValues.ESTIMATE]: true,
|
||||||
|
[fmgPageValues.CAPABILITY_QUESTIONS]: false,
|
||||||
|
[fmgPageValues.MOLDING_QUESTIONS]: false,
|
||||||
|
[fmgPageValues.VEHICLE_PARTS]: false,
|
||||||
|
[fmgPageValues.PART_QUESTIONS]: false,
|
||||||
|
[fmgPageValues.VIN_LOOKUP]: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Act
|
||||||
|
const result = await getPageToRouteExistingOrderTo(toRoute, false);
|
||||||
|
|
||||||
|
//Assert
|
||||||
|
expect(result).toBe(fmgPageValues.VIN_LOOKUP);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("user has YMMS but no questions or carId > should return estimate", async () => {
|
||||||
|
// Arrange
|
||||||
|
const toRoute = {
|
||||||
|
query: {},
|
||||||
|
};
|
||||||
|
|
||||||
|
// Mock out the lazy load calls for all components.
|
||||||
|
mockLazyLoadComponentReturnValues({
|
||||||
|
[fmgPageValues.VEHICLE_MAKE]: true,
|
||||||
|
[fmgPageValues.VEHICLE_MODEL]: true,
|
||||||
|
[fmgPageValues.VEHICLE_STYLE]: true,
|
||||||
|
[fmgPageValues.VEHICLE_DAMAGE]: true,
|
||||||
|
[fmgPageValues.ESTIMATE]: true,
|
||||||
|
[fmgPageValues.CAPABILITY_QUESTIONS]: false,
|
||||||
|
[fmgPageValues.MOLDING_QUESTIONS]: false,
|
||||||
|
[fmgPageValues.VEHICLE_PARTS]: false,
|
||||||
|
[fmgPageValues.PART_QUESTIONS]: false,
|
||||||
|
[fmgPageValues.VIN_LOOKUP]: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Act
|
||||||
|
const result = await getPageToRouteExistingOrderTo(toRoute, false);
|
||||||
|
|
||||||
|
//Assert
|
||||||
|
expect(result).toBe(fmgPageValues.ESTIMATE);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("user has capability questions and molding questions > should return capability questions", async () => {
|
||||||
|
// Arrange
|
||||||
|
const toRoute = {
|
||||||
|
query: {},
|
||||||
|
};
|
||||||
|
|
||||||
|
// Mock out the lazy load calls for all components.
|
||||||
|
mockLazyLoadComponentReturnValues({
|
||||||
|
[fmgPageValues.VEHICLE_MAKE]: true,
|
||||||
|
[fmgPageValues.VEHICLE_MODEL]: true,
|
||||||
|
[fmgPageValues.VEHICLE_STYLE]: true,
|
||||||
|
[fmgPageValues.VEHICLE_DAMAGE]: true,
|
||||||
|
[fmgPageValues.ESTIMATE]: true,
|
||||||
|
[fmgPageValues.CAPABILITY_QUESTIONS]: true,
|
||||||
|
[fmgPageValues.MOLDING_QUESTIONS]: true,
|
||||||
|
[fmgPageValues.VEHICLE_PARTS]: false,
|
||||||
|
[fmgPageValues.PART_QUESTIONS]: false,
|
||||||
|
[fmgPageValues.VIN_LOOKUP]: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Act
|
||||||
|
const result = await getPageToRouteExistingOrderTo(toRoute, false);
|
||||||
|
|
||||||
|
//Assert
|
||||||
|
expect(result).toBe(fmgPageValues.CAPABILITY_QUESTIONS);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("user has molding questions and part questions > should return molding questions", async () => {
|
||||||
|
// Arrange
|
||||||
|
const toRoute = {
|
||||||
|
query: {},
|
||||||
|
};
|
||||||
|
|
||||||
|
// Mock out the lazy load calls for all components.
|
||||||
|
mockLazyLoadComponentReturnValues({
|
||||||
|
[fmgPageValues.VEHICLE_MAKE]: true,
|
||||||
|
[fmgPageValues.VEHICLE_MODEL]: true,
|
||||||
|
[fmgPageValues.VEHICLE_STYLE]: true,
|
||||||
|
[fmgPageValues.VEHICLE_DAMAGE]: true,
|
||||||
|
[fmgPageValues.ESTIMATE]: true,
|
||||||
|
[fmgPageValues.CAPABILITY_QUESTIONS]: false,
|
||||||
|
[fmgPageValues.MOLDING_QUESTIONS]: true,
|
||||||
|
[fmgPageValues.VEHICLE_PARTS]: false,
|
||||||
|
[fmgPageValues.PART_QUESTIONS]: true,
|
||||||
|
[fmgPageValues.VIN_LOOKUP]: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Act
|
||||||
|
const result = await getPageToRouteExistingOrderTo(toRoute, false);
|
||||||
|
|
||||||
|
//Assert
|
||||||
|
expect(result).toBe(fmgPageValues.MOLDING_QUESTIONS);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("user has vehicle parts questions > should return vehicle-parts", async () => {
|
||||||
|
// Arrange
|
||||||
|
const toRoute = {
|
||||||
|
query: {},
|
||||||
|
};
|
||||||
|
|
||||||
|
// Mock out the lazy load calls for all components.
|
||||||
|
mockLazyLoadComponentReturnValues({
|
||||||
|
[fmgPageValues.VEHICLE_MAKE]: true,
|
||||||
|
[fmgPageValues.VEHICLE_MODEL]: true,
|
||||||
|
[fmgPageValues.VEHICLE_STYLE]: true,
|
||||||
|
[fmgPageValues.VEHICLE_DAMAGE]: true,
|
||||||
|
[fmgPageValues.ESTIMATE]: true,
|
||||||
|
[fmgPageValues.CAPABILITY_QUESTIONS]: false,
|
||||||
|
[fmgPageValues.MOLDING_QUESTIONS]: false,
|
||||||
|
[fmgPageValues.VEHICLE_PARTS]: true,
|
||||||
|
[fmgPageValues.PART_QUESTIONS]: true,
|
||||||
|
[fmgPageValues.VIN_LOOKUP]: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Act
|
||||||
|
const result = await getPageToRouteExistingOrderTo(toRoute, false);
|
||||||
|
|
||||||
|
//Assert
|
||||||
|
expect(result).toBe(fmgPageValues.VEHICLE_PARTS);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("user has part questions > should return part-questions", async () => {
|
||||||
|
// Arrange
|
||||||
|
const toRoute = {
|
||||||
|
query: {},
|
||||||
|
};
|
||||||
|
|
||||||
|
// Mock out the lazy load calls for all components.
|
||||||
|
mockLazyLoadComponentReturnValues({
|
||||||
|
[fmgPageValues.VEHICLE_MAKE]: true,
|
||||||
|
[fmgPageValues.VEHICLE_MODEL]: true,
|
||||||
|
[fmgPageValues.VEHICLE_STYLE]: true,
|
||||||
|
[fmgPageValues.VEHICLE_DAMAGE]: true,
|
||||||
|
[fmgPageValues.ESTIMATE]: true,
|
||||||
|
[fmgPageValues.CAPABILITY_QUESTIONS]: false,
|
||||||
|
[fmgPageValues.MOLDING_QUESTIONS]: false,
|
||||||
|
[fmgPageValues.VEHICLE_PARTS]: false,
|
||||||
|
[fmgPageValues.PART_QUESTIONS]: true,
|
||||||
|
[fmgPageValues.VIN_LOOKUP]: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Act
|
||||||
|
const result = await getPageToRouteExistingOrderTo(toRoute, false);
|
||||||
|
|
||||||
|
//Assert
|
||||||
|
expect(result).toBe(fmgPageValues.PART_QUESTIONS);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("existing order > should return heritage", async () => {
|
||||||
|
// Arrange
|
||||||
|
const toRoute = {
|
||||||
|
query: {
|
||||||
|
[queryStrings.START_TYPE]: "fmg",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
const result = await getPageToRouteExistingOrderTo(toRoute, true);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(result).toBe(fmgPageValues.HERITAGE);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("navigateToHeritageFunnel", () => {
|
||||||
|
test("should save session", async () => {
|
||||||
|
// Arrange
|
||||||
|
const mockReferralNumber = "2";
|
||||||
|
const mockCorrelationId = "55";
|
||||||
|
const mockReferralDate = "2022";
|
||||||
|
const mockAccountNumber = "167132";
|
||||||
|
const mockSavedSessionId = "xxx-xxx-xxx";
|
||||||
|
const mockCrmCustomerId = "xxx-xxx-xxx";
|
||||||
|
|
||||||
|
const mockOrderInfo = getMockOrderInfo(
|
||||||
|
mockReferralNumber,
|
||||||
|
mockCorrelationId,
|
||||||
|
mockReferralDate,
|
||||||
|
mockAccountNumber,
|
||||||
|
mockSavedSessionId,
|
||||||
|
mockCrmCustomerId
|
||||||
|
);
|
||||||
|
|
||||||
|
const mockData = {
|
||||||
|
actionList: [
|
||||||
|
{
|
||||||
|
actionName: storeActions.SAVE_SESSION,
|
||||||
|
data: mockOrderInfo,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
setupMocksForJsFiles(mockData);
|
||||||
|
const saveSessionFunction = jest.spyOn(orderHelper, "saveSession");
|
||||||
|
router.navigateToExternalUrl = jest.fn();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await navigateToHeritageFunnel();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(saveSessionFunction).toHaveBeenCalled();
|
||||||
|
|
||||||
|
// Should save before we navigate to heritage by default
|
||||||
|
const saveSessionFunctionCallOrder = saveSessionFunction.mock.invocationCallOrder[0];
|
||||||
|
const routerNavigateFunctionCallOrder =
|
||||||
|
router.navigateToExternalUrl.mock.invocationCallOrder[0];
|
||||||
|
expect(saveSessionFunctionCallOrder).toBeLessThan(routerNavigateFunctionCallOrder);
|
||||||
|
saveSessionFunction.mockRestore();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("should go to heritage funnel", async () => {
|
||||||
|
// Arrange
|
||||||
|
const mockReferralNumber = "2";
|
||||||
|
const mockCorrelationId = "55";
|
||||||
|
const mockReferralDate = "2022";
|
||||||
|
const mockAccountNumber = "167132";
|
||||||
|
const mockSavedSessionId = "xxx-xxx-xxx";
|
||||||
|
const mockCrmCustomerId = "xxx-xxx-xxx";
|
||||||
|
|
||||||
|
const mockOrderInfo = getMockOrderInfo(
|
||||||
|
mockReferralNumber,
|
||||||
|
mockCorrelationId,
|
||||||
|
mockReferralDate,
|
||||||
|
mockAccountNumber,
|
||||||
|
mockSavedSessionId,
|
||||||
|
mockCrmCustomerId
|
||||||
|
);
|
||||||
|
|
||||||
|
const mockData = {
|
||||||
|
actionList: [
|
||||||
|
{
|
||||||
|
actionName: storeActions.SAVE_SESSION,
|
||||||
|
data: mockOrderInfo,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
setupMocksForJsFiles(mockData);
|
||||||
|
|
||||||
|
store.getters.order.referralCorrelationId = mockCorrelationId;
|
||||||
|
|
||||||
|
router.navigateToExternalUrl = jest.fn();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await navigateToHeritageFunnel();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(router.navigateToExternalUrl).toHaveBeenCalled();
|
||||||
|
expect(router.navigateToExternalUrl).toHaveBeenCalledWith(
|
||||||
|
externalUrls.HERITAGE_FUNNEL,
|
||||||
|
expect.objectContaining({
|
||||||
|
corid: mockCorrelationId,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("should not save session, but should still navigate", async () => {
|
||||||
|
// Arrange
|
||||||
|
const mockReferralNumber = "2";
|
||||||
|
const mockCorrelationId = "55";
|
||||||
|
const mockReferralDate = "2022";
|
||||||
|
|
||||||
|
const mockOrderInfo = getMockOrderInfo(
|
||||||
|
mockReferralNumber,
|
||||||
|
mockCorrelationId,
|
||||||
|
mockReferralDate
|
||||||
|
);
|
||||||
|
|
||||||
|
const mockData = {
|
||||||
|
actionList: [
|
||||||
|
{
|
||||||
|
actionName: storeActions.SAVE_SESSION,
|
||||||
|
data: mockOrderInfo,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
setupMocksForJsFiles(mockData);
|
||||||
|
const saveSessionFunction = jest.spyOn(orderHelper, "saveSession");
|
||||||
|
router.navigateToExternalUrl = jest.fn();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await navigateToHeritageFunnel(false);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(saveSessionFunction).not.toHaveBeenCalled();
|
||||||
|
expect(router.navigateToExternalUrl).toHaveBeenCalled();
|
||||||
|
saveSessionFunction.mockRestore();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* `arePagePrerequisitesValidObject` is an object where the keys are fmgPageValue names and the values are booleans that indicate
|
||||||
|
* whether arePagePrerequisitesValid is true or false
|
||||||
|
*/
|
||||||
|
function mockLazyLoadComponentReturnValues(arePagePrerequisitesValidObject = {}) {
|
||||||
|
lazyLoadComponent.mockImplementation((pageName) => {
|
||||||
|
return async () => {
|
||||||
|
return Promise.resolve({
|
||||||
|
default: {
|
||||||
|
methods: {
|
||||||
|
arePagePrerequisitesValid: jest
|
||||||
|
.fn()
|
||||||
|
.mockReturnValueOnce(arePagePrerequisitesValidObject[pageName]),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
113
src/helpers/heritage-integration/order-helper.js
Normal file
113
src/helpers/heritage-integration/order-helper.js
Normal file
|
|
@ -0,0 +1,113 @@
|
||||||
|
import { storeActions } from "@/constants/store-actions.js";
|
||||||
|
import {
|
||||||
|
getFunnelCookie,
|
||||||
|
updateOrCreateFunnelCookie,
|
||||||
|
deleteFunnelCookie,
|
||||||
|
} from "@/helpers/heritage-integration/cookie-helper.js";
|
||||||
|
import baseMixin from "@/mixins/base-mixin";
|
||||||
|
import store from "@/store";
|
||||||
|
import { storeMutations } from "@/constants/store-mutations";
|
||||||
|
|
||||||
|
/*
|
||||||
|
Will call API and hydrate state with data from API if present. If there is no order present
|
||||||
|
method will return null. If the cookie dictates the state should be reset
|
||||||
|
it will reset the state and go back to the start of the funnel.
|
||||||
|
|
||||||
|
*/
|
||||||
|
export async function loadSessionIfPresent() {
|
||||||
|
const funnelCookie = getFunnelCookie();
|
||||||
|
|
||||||
|
// Do nothing if there is no cookie, correlation id, or referral number.
|
||||||
|
if (
|
||||||
|
funnelCookie == null ||
|
||||||
|
funnelCookie.ReferralCorrelationId == null ||
|
||||||
|
!funnelCookie.ReferralNumber
|
||||||
|
) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset state if cookie says to.
|
||||||
|
if (funnelCookie.ShouldResetState) {
|
||||||
|
baseMixin.methods.dispatchStoreAction(storeActions.RESET_STATE);
|
||||||
|
deleteFunnelCookie();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load referral if there is a cookie, and it doesn't indicate it needs a state reset.
|
||||||
|
return (
|
||||||
|
await loadSession(
|
||||||
|
funnelCookie.ReferralNumber,
|
||||||
|
funnelCookie.ReferralDate,
|
||||||
|
funnelCookie.ReferralCorrelationId,
|
||||||
|
funnelCookie.ReferralParentAccountNumber
|
||||||
|
)
|
||||||
|
).data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Will call API to save existing order, or create new one depending where it's called from.
|
||||||
|
This will also set Referral information in the store after saving, and then
|
||||||
|
update the cookie.
|
||||||
|
*/
|
||||||
|
export async function saveSession() {
|
||||||
|
var saveSessionPromise;
|
||||||
|
if (store.getters.applicationUser.saveSessionPromise) {
|
||||||
|
// queue newest request after current saveSessionPromise resolves
|
||||||
|
saveSessionPromise = store.getters.applicationUser.saveSessionPromise.then(() => {
|
||||||
|
// get a new saveSessionPromise
|
||||||
|
return saveSessionHelper();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// create an initial saveSessionPromise
|
||||||
|
saveSessionPromise = saveSessionHelper();
|
||||||
|
}
|
||||||
|
store.commit(storeMutations.UPDATE_SAVE_SESSION_PROMISE, saveSessionPromise);
|
||||||
|
// await here to allow for a caller to await and make the function synchronous
|
||||||
|
await saveSessionPromise;
|
||||||
|
}
|
||||||
|
|
||||||
|
// PRIVATE FUNCTIONS //
|
||||||
|
|
||||||
|
/*
|
||||||
|
Calls API to load session given the referral number, referralDate, and referralCorrelationId
|
||||||
|
and returns the response.
|
||||||
|
*/
|
||||||
|
async function loadSession(referralNumber, referralDate, referralCorrelationId, accountNumber) {
|
||||||
|
// await the saveSessionPromise in the store to make sure we're loading up to date information
|
||||||
|
await store.getters.applicationUser.saveSessionPromise;
|
||||||
|
const response = await baseMixin.methods.dispatchStoreAction(
|
||||||
|
storeActions.LOAD_SESSION,
|
||||||
|
{
|
||||||
|
referralNumber: referralNumber.toString(),
|
||||||
|
referralDate: referralDate,
|
||||||
|
referralCorrelationId: referralCorrelationId,
|
||||||
|
accountNumber: accountNumber?.toString(),
|
||||||
|
},
|
||||||
|
false
|
||||||
|
);
|
||||||
|
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Encapsulates asynchronous Save Session logic inside a promise to allow for Save Session queuing
|
||||||
|
*/
|
||||||
|
async function saveSessionHelper() {
|
||||||
|
const savedSessionInfo = await baseMixin.methods.dispatchStoreAction(storeActions.SAVE_SESSION);
|
||||||
|
// Update the store with information received from the saveSession response
|
||||||
|
await baseMixin.methods.dispatchStoreAction(
|
||||||
|
storeActions.UPDATE_STORE_WITH_SAVE_SESSION_RESPONSE,
|
||||||
|
{
|
||||||
|
referralNumber: savedSessionInfo.data.referralNumber.toString(),
|
||||||
|
referralCorrelationId: savedSessionInfo.data.referralCorrelationId,
|
||||||
|
referralDate: savedSessionInfo.data.referralDate,
|
||||||
|
accountNumber: savedSessionInfo.data.accountNumber.toString(),
|
||||||
|
savedSessionId: savedSessionInfo.data.savedSessionId,
|
||||||
|
crmCustomerId: savedSessionInfo.data.crmCustomerId.toString(),
|
||||||
|
},
|
||||||
|
false
|
||||||
|
);
|
||||||
|
|
||||||
|
// Update the cookie with the referral information when saved.
|
||||||
|
updateOrCreateFunnelCookie();
|
||||||
|
}
|
||||||
236
src/helpers/heritage-integration/order-helper.spec.js
Normal file
236
src/helpers/heritage-integration/order-helper.spec.js
Normal file
|
|
@ -0,0 +1,236 @@
|
||||||
|
import * as cookieHelper from "@/helpers/heritage-integration/cookie-helper";
|
||||||
|
import { loadSessionIfPresent, saveSession } from "@/helpers/heritage-integration/order-helper";
|
||||||
|
import { cookieNames } from "@/constants/cookie-names";
|
||||||
|
import {
|
||||||
|
setupMocksForJsFiles,
|
||||||
|
removeAllTestCookies,
|
||||||
|
getMockOrderInfo,
|
||||||
|
setupCookies,
|
||||||
|
} from "@/helpers/unit-test-helper.js";
|
||||||
|
import { storeActions } from "@/constants/store-actions";
|
||||||
|
import router from "@/router";
|
||||||
|
|
||||||
|
describe("loadSessionIfPresent", () => {
|
||||||
|
afterEach(() => {
|
||||||
|
removeAllTestCookies();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("ShouldResetState == true => funnel cookie is deleted", () => {
|
||||||
|
// Arrange
|
||||||
|
cookieHelper.deleteFunnelCookie = jest.spyOn(cookieHelper, "deleteFunnelCookie");
|
||||||
|
const testShouldResetState = true;
|
||||||
|
|
||||||
|
const testCookieValue = {
|
||||||
|
ShouldResetState: testShouldResetState,
|
||||||
|
ReferralCorrelationId: "xxx",
|
||||||
|
ReferralNumber: "12345",
|
||||||
|
};
|
||||||
|
|
||||||
|
document.cookie = `${cookieNames.FUNNEL_SESSION_INFO}=${JSON.stringify(
|
||||||
|
testCookieValue
|
||||||
|
)}; path=/; ${cookieHelper.getCookieDomainValue()}`;
|
||||||
|
|
||||||
|
// Act
|
||||||
|
loadSessionIfPresent();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(cookieHelper.deleteFunnelCookie).toHaveBeenCalled();
|
||||||
|
expect(document.cookie).toBe("");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("ShouldResetState == true => reset store", () => {
|
||||||
|
// Arrange
|
||||||
|
cookieHelper.getFunnelCookie = jest
|
||||||
|
.spyOn(cookieHelper, "getFunnelCookie")
|
||||||
|
.mockReturnValueOnce({
|
||||||
|
ShouldResetState: true,
|
||||||
|
ReferralCorrelationId: "xxx-xxx-xxx",
|
||||||
|
ReferralNumber: "12345",
|
||||||
|
});
|
||||||
|
|
||||||
|
const mockData = {
|
||||||
|
actionList: [
|
||||||
|
{
|
||||||
|
actionName: storeActions.RESET_STATE,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
var mocks = setupMocksForJsFiles(mockData);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
loadSessionIfPresent();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(cookieHelper.getFunnelCookie).toHaveBeenCalled();
|
||||||
|
expect(mocks.baseMixin.methods.dispatchStoreAction).toHaveBeenCalledWith(
|
||||||
|
storeActions.RESET_STATE
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("Funnel cookie is null => store is unchanged", () => {
|
||||||
|
// Arrange
|
||||||
|
cookieHelper.getFunnelCookie = jest
|
||||||
|
.spyOn(cookieHelper, "getFunnelCookie")
|
||||||
|
.mockReturnValueOnce(null);
|
||||||
|
|
||||||
|
const mockData = {
|
||||||
|
actionList: [
|
||||||
|
{
|
||||||
|
actionName: storeActions.RESET_STATE,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
var mocks = setupMocksForJsFiles(mockData);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
loadSessionIfPresent();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(cookieHelper.getFunnelCookie).toHaveBeenCalled();
|
||||||
|
expect(mocks.baseMixin.methods.dispatchStoreAction).not.toHaveBeenCalledWith(
|
||||||
|
storeActions.RESET_STATE
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("Funnel cookie valid, should call loadSession", async () => {
|
||||||
|
// Arrange
|
||||||
|
cookieHelper.getFunnelCookie = jest
|
||||||
|
.spyOn(cookieHelper, "getFunnelCookie")
|
||||||
|
.mockReturnValueOnce({
|
||||||
|
ShouldResetState: false,
|
||||||
|
ReferralNumber: 123456,
|
||||||
|
ReferralCorrelationId: "yyy-yyy-yyyy",
|
||||||
|
ReferralDate: new Date(),
|
||||||
|
});
|
||||||
|
|
||||||
|
const mockData = {
|
||||||
|
actionList: [
|
||||||
|
{
|
||||||
|
actionName: storeActions.LOAD_SESSION,
|
||||||
|
data: { ReferralNumber: 123456, vehicle: { year: 2010 } },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
var mocks = setupMocksForJsFiles(mockData);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
const result = await loadSessionIfPresent();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(cookieHelper.getFunnelCookie).toHaveBeenCalled();
|
||||||
|
expect(mocks.baseMixin.methods.dispatchStoreAction).not.toHaveBeenCalledWith(
|
||||||
|
storeActions.LOAD_SESSION
|
||||||
|
);
|
||||||
|
expect(result.ReferralNumber).toBe(123456);
|
||||||
|
expect(result.vehicle.year).toBe(2010);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("saveSession", () => {
|
||||||
|
afterEach(() => {
|
||||||
|
removeAllTestCookies();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("saveSession => should set state order values", async () => {
|
||||||
|
// Arrange
|
||||||
|
const mockReferralNumber = "2";
|
||||||
|
const mockCorrelationId = "55";
|
||||||
|
const mockReferralDate = "2022";
|
||||||
|
const mockAccountNumber = "167132";
|
||||||
|
const mockSavedSessionId = "xxx-xxx-xxx";
|
||||||
|
const mockCrmCustomerId = "xxx-xxx-xxx";
|
||||||
|
|
||||||
|
const mockOrderInfo = getMockOrderInfo(
|
||||||
|
mockReferralNumber,
|
||||||
|
mockCorrelationId,
|
||||||
|
mockReferralDate,
|
||||||
|
mockAccountNumber,
|
||||||
|
mockSavedSessionId,
|
||||||
|
mockCrmCustomerId
|
||||||
|
);
|
||||||
|
|
||||||
|
const mockData = {
|
||||||
|
actionList: [
|
||||||
|
{
|
||||||
|
actionName: storeActions.SAVE_SESSION,
|
||||||
|
data: mockOrderInfo,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
actionName: storeActions.UPDATE_STORE_WITH_SAVE_SESSION_RESPONSE,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
const mocks = setupMocksForJsFiles(mockData);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await saveSession();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(mocks.baseMixin.methods.dispatchStoreAction).toHaveBeenCalledWith(
|
||||||
|
storeActions.SAVE_SESSION
|
||||||
|
);
|
||||||
|
expect(mocks.baseMixin.methods.dispatchStoreAction).toHaveBeenCalledWith(
|
||||||
|
storeActions.UPDATE_STORE_WITH_SAVE_SESSION_RESPONSE,
|
||||||
|
{
|
||||||
|
referralNumber: mockReferralNumber,
|
||||||
|
referralDate: mockReferralDate,
|
||||||
|
referralCorrelationId: mockCorrelationId,
|
||||||
|
accountNumber: mockAccountNumber,
|
||||||
|
savedSessionId: mockSavedSessionId,
|
||||||
|
crmCustomerId: mockCrmCustomerId,
|
||||||
|
},
|
||||||
|
false
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("saveSession => should update DidHeritageFunnelUpdateLast cookie value to false", async () => {
|
||||||
|
// Arrange
|
||||||
|
const mockReferralNumber = 1566818;
|
||||||
|
const mockReferralDate = "2022-03-15T10:56:24.597";
|
||||||
|
const mockReferralCorrelationId = "404d2b04-f86e-45c3-b373-127b6217b060";
|
||||||
|
const mockAccountNumber = "167132";
|
||||||
|
const mockSavedSessionId = "xxx-xxx-xxx";
|
||||||
|
const mockCrmCustomerId = "xxx-xxx-xxx";
|
||||||
|
|
||||||
|
const mockOrderInfo = getMockOrderInfo(
|
||||||
|
mockReferralNumber,
|
||||||
|
mockReferralCorrelationId,
|
||||||
|
mockReferralDate,
|
||||||
|
mockAccountNumber,
|
||||||
|
mockSavedSessionId,
|
||||||
|
mockCrmCustomerId
|
||||||
|
);
|
||||||
|
|
||||||
|
const mockData = {
|
||||||
|
actionList: [
|
||||||
|
{
|
||||||
|
actionName: storeActions.SAVE_SESSION,
|
||||||
|
data: mockOrderInfo,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
router: router,
|
||||||
|
};
|
||||||
|
|
||||||
|
setupMocksForJsFiles(mockData);
|
||||||
|
|
||||||
|
const testCookieValue = {
|
||||||
|
ReferralNumber: mockReferralNumber,
|
||||||
|
ReferralDate: mockReferralDate,
|
||||||
|
ReferralCorrelationId: mockReferralCorrelationId,
|
||||||
|
ShouldResetState: false,
|
||||||
|
DidHeritageFunnelUpdateLast: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
setupCookies({ funnelCookieValue: JSON.stringify(testCookieValue) });
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await saveSession();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(cookieHelper.getFunnelCookie().DidHeritageFunnelUpdateLast).toEqual(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
47
src/helpers/heritage-integration/session-helper.js
Normal file
47
src/helpers/heritage-integration/session-helper.js
Normal file
|
|
@ -0,0 +1,47 @@
|
||||||
|
import { applicationConfig } from "@/constants/application-config";
|
||||||
|
import { getFunnelCookie } from "@/helpers/heritage-integration/cookie-helper.js";
|
||||||
|
|
||||||
|
/*
|
||||||
|
Method to determine if our analytics session has timed out or not.
|
||||||
|
Amount used for timeout is configurable in application-config.js
|
||||||
|
*/
|
||||||
|
export function isAnalyticsSessionStillActive() {
|
||||||
|
if (getFunnelCookie() !== null) {
|
||||||
|
const lastTouchedValue = getFunnelCookie().LastTouched;
|
||||||
|
const timeoutAmount = applicationConfig.ANALYTICS_SESSION_TIMEOUT_MINUTES;
|
||||||
|
const isMoreThanHalfHourAgo =
|
||||||
|
(new Date() - new Date(lastTouchedValue)) / 60000 > timeoutAmount;
|
||||||
|
|
||||||
|
if (isMoreThanHalfHourAgo) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Method to determine if the users 'saved' session is still active.
|
||||||
|
When user state is created, there is a date that is saved into state
|
||||||
|
this method checks against that date.
|
||||||
|
|
||||||
|
Note: That time for saved session timeout is configurable in application-config.js
|
||||||
|
*/
|
||||||
|
export function isSavedSessionStillActive() {
|
||||||
|
if (getFunnelCookie() !== null) {
|
||||||
|
const savedSessionTimeStamp = new Date(getFunnelCookie().SavedSessionTimeoutDate);
|
||||||
|
const isSavedSessionTimedOut = new Date(new Date().toUTCString()) > savedSessionTimeStamp;
|
||||||
|
|
||||||
|
return !isSavedSessionTimedOut;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Function to calculate the date for the saved session timeout.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export function getDateForSavedSessionTimeout() {
|
||||||
|
const currentDate = new Date(new Date().toUTCString());
|
||||||
|
currentDate.setDate(currentDate.getDate() + applicationConfig.SAVED_SESSION_TIMEOUT_DAYS);
|
||||||
|
return currentDate.toUTCString();
|
||||||
|
}
|
||||||
89
src/helpers/heritage-integration/session-helper.spec.js
Normal file
89
src/helpers/heritage-integration/session-helper.spec.js
Normal file
|
|
@ -0,0 +1,89 @@
|
||||||
|
import * as cookieHelper from "@/helpers/heritage-integration/cookie-helper";
|
||||||
|
import {
|
||||||
|
isAnalyticsSessionStillActive,
|
||||||
|
isSavedSessionStillActive,
|
||||||
|
getDateForSavedSessionTimeout,
|
||||||
|
} from "@/helpers/heritage-integration/session-helper";
|
||||||
|
import { applicationConfig } from "@/constants/application-config";
|
||||||
|
|
||||||
|
describe("isAnalyticsSessionStillActive", () => {
|
||||||
|
test("isAnalyticsSessionStillActive, should return true", () => {
|
||||||
|
// Arrange
|
||||||
|
const mockDate = new Date(new Date().toUTCString());
|
||||||
|
mockDate.setDate(mockDate.getDate() + 1);
|
||||||
|
|
||||||
|
cookieHelper.getFunnelCookie = jest
|
||||||
|
.spyOn(cookieHelper, "getFunnelCookie")
|
||||||
|
.mockReturnValue({ LastTouched: mockDate });
|
||||||
|
|
||||||
|
// Act
|
||||||
|
const result = isAnalyticsSessionStillActive();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(result).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("isAnalyticsSessionStillActive, should return false", () => {
|
||||||
|
// Arrange
|
||||||
|
const mockDate = new Date(new Date().toUTCString());
|
||||||
|
mockDate.setDate(mockDate.getDate() - 1);
|
||||||
|
|
||||||
|
cookieHelper.getFunnelCookie = jest
|
||||||
|
.spyOn(cookieHelper, "getFunnelCookie")
|
||||||
|
.mockReturnValue({ LastTouched: mockDate });
|
||||||
|
|
||||||
|
// Act
|
||||||
|
const result = isAnalyticsSessionStillActive();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(result).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("isSavedSessionStillActive", () => {
|
||||||
|
test("isSavedSessionStillActive, should return true", () => {
|
||||||
|
// Arrange
|
||||||
|
const mockDate = new Date(new Date().toUTCString());
|
||||||
|
mockDate.setDate(mockDate.getDate() + 1);
|
||||||
|
|
||||||
|
cookieHelper.getFunnelCookie = jest
|
||||||
|
.spyOn(cookieHelper, "getFunnelCookie")
|
||||||
|
.mockReturnValue({ SavedSessionTimeoutDate: mockDate });
|
||||||
|
|
||||||
|
// Act
|
||||||
|
const result = isSavedSessionStillActive();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(result).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("isSavedSessionStillActive, should return false", () => {
|
||||||
|
// Arrange
|
||||||
|
const mockDate = new Date(new Date().toUTCString());
|
||||||
|
mockDate.setDate(mockDate.getDate() - 1);
|
||||||
|
|
||||||
|
cookieHelper.getFunnelCookie = jest
|
||||||
|
.spyOn(cookieHelper, "getFunnelCookie")
|
||||||
|
.mockReturnValue({ SavedSessionTimeoutDate: mockDate });
|
||||||
|
|
||||||
|
// Act
|
||||||
|
const result = isSavedSessionStillActive();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(result).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("getDateForSavedSessionTimeout", () => {
|
||||||
|
test("getDateForSavedSessionTimeout, should equal application config setting", () => {
|
||||||
|
// Arrange
|
||||||
|
const currentDate = new Date(new Date().toUTCString());
|
||||||
|
currentDate.setDate(currentDate.getDate() + applicationConfig.SAVED_SESSION_TIMEOUT_DAYS);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
const result = getDateForSavedSessionTimeout();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(result).toEqual(currentDate.toUTCString());
|
||||||
|
});
|
||||||
|
});
|
||||||
144
src/helpers/unit-test-helper.js
Normal file
144
src/helpers/unit-test-helper.js
Normal file
|
|
@ -0,0 +1,144 @@
|
||||||
|
import { storeActions } from "@/constants/store-actions";
|
||||||
|
import { storeMutations } from "@/constants/store-mutations.js";
|
||||||
|
import { navigationScenarios } from "@/router/router-constants/navigation-scenarios.js";
|
||||||
|
import { vehicleCategories } from "@/constants/vehicle-categories.js";
|
||||||
|
import { fmgPageValues } from "@/router/router-constants/fmgPage-values";
|
||||||
|
import { cookieNames } from "@/constants/cookie-names";
|
||||||
|
import { Form } from "vee-validate";
|
||||||
|
import baseMixin from "@/mixins/base-mixin";
|
||||||
|
import {
|
||||||
|
getCookieDomainValue,
|
||||||
|
setCookieProperties,
|
||||||
|
} from "@/helpers/heritage-integration/cookie-helper";
|
||||||
|
import {
|
||||||
|
analyticsPageEvents,
|
||||||
|
GaCategories,
|
||||||
|
GaActions,
|
||||||
|
GaLabels,
|
||||||
|
GaEvents,
|
||||||
|
ValueToLogTypes,
|
||||||
|
} from "@/constants/analytics";
|
||||||
|
import { queryStrings } from "@/constants/query-strings";
|
||||||
|
import { routerParams } from "@/router/router-constants/router-params";
|
||||||
|
|
||||||
|
// Common methods
|
||||||
|
export function getMountOptions(mockData) {
|
||||||
|
// Define our mocks to attached to the 'global' object for Vue/Jest.
|
||||||
|
const mocks = {};
|
||||||
|
|
||||||
|
//this is mocking if you use the mixin directly(baseMixin.methods.dispatchStoreAction) vs this.dispatchStoreAction
|
||||||
|
setupBaseMixinDispatchStoreAction(mockData);
|
||||||
|
|
||||||
|
mocks.pushEventToGA = jest.fn();
|
||||||
|
mocks.pushPageViewToGA = jest.fn();
|
||||||
|
mocks.logEvent = jest.fn();
|
||||||
|
mocks.pushExperimentsToDataLayer = jest.fn();
|
||||||
|
mocks.prependActionToMethod = jest.fn();
|
||||||
|
mocks.dispatchStoreAction = jest.fn();
|
||||||
|
mocks.dispatchStoreAction.mockImplementation((actionName) => {
|
||||||
|
let actionFilterResult = mockData.actionList?.filter((x) => x.actionName == actionName);
|
||||||
|
|
||||||
|
if (actionFilterResult?.length === 1) {
|
||||||
|
return Promise.resolve({
|
||||||
|
data: actionFilterResult[0].data,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Mock const files
|
||||||
|
mocks.storeActions = storeActions;
|
||||||
|
mocks.storeMutations = storeMutations;
|
||||||
|
mocks.navigationScenarios = navigationScenarios;
|
||||||
|
mocks.vehicleCategories = vehicleCategories;
|
||||||
|
mocks.fmgPageValues = fmgPageValues;
|
||||||
|
mocks.analyticsPageEvents = analyticsPageEvents;
|
||||||
|
mocks.GaCategories = GaCategories;
|
||||||
|
mocks.GaActions = GaActions;
|
||||||
|
mocks.GaLabels = GaLabels;
|
||||||
|
mocks.GaEvents = GaEvents;
|
||||||
|
mocks.ValueToLogTypes = ValueToLogTypes;
|
||||||
|
mocks.queryStrings = queryStrings;
|
||||||
|
mocks.routerParams = routerParams;
|
||||||
|
|
||||||
|
// Mock $store and $router when accessing this.$store/$router
|
||||||
|
mocks.$store = mockData.store;
|
||||||
|
mocks.$router = mockData.router;
|
||||||
|
mocks.$route = mockData.route;
|
||||||
|
mocks.$loadScript = mockData.loadScript;
|
||||||
|
|
||||||
|
const global = {
|
||||||
|
mocks: mocks,
|
||||||
|
mixins: mockData.mixins,
|
||||||
|
stubs: { Form },
|
||||||
|
};
|
||||||
|
|
||||||
|
return { global };
|
||||||
|
}
|
||||||
|
|
||||||
|
export function setupMocksForJsFiles(mockData = {}) {
|
||||||
|
setupBaseMixinDispatchStoreAction(mockData);
|
||||||
|
|
||||||
|
return { baseMixin };
|
||||||
|
}
|
||||||
|
|
||||||
|
// Heritage integration common methods
|
||||||
|
export const cookies = {
|
||||||
|
[cookieNames.FUNNEL_SESSION_INFO]: `{"ReferralNumber":"1566818","ReferralDate":"2022-03-15T10:56:24.597","ReferralCorrelationId":"404d2b04-f86e-45c3-b373-127b6217b060","ShouldResetState":false,"DidHeritageFunnelUpdateLast":true}`,
|
||||||
|
UNIQUE_SESSION_ID: "33756020-b58e-4ec7-b8b8-3f1576719c40",
|
||||||
|
anotherCookie: "{}",
|
||||||
|
someOtherCookie: "{}",
|
||||||
|
dxdev: "did=21b9b94a-ec23-42c1-aaac-e2ae4e4dbffe",
|
||||||
|
sid: "cba0c3d1-3c1b-4305-bb56-31aa50f58e27",
|
||||||
|
skey: "12345",
|
||||||
|
};
|
||||||
|
|
||||||
|
// Removes test cookies for testing cookie-helper and order-helper
|
||||||
|
export function removeAllTestCookies() {
|
||||||
|
Object.keys(cookies).forEach((key) => {
|
||||||
|
document.cookie = `${key}=;Max-Age=0;`;
|
||||||
|
document.cookie = `${key}=;Max-Age=0;path=/;${getCookieDomainValue()}`;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getMockOrderInfo(
|
||||||
|
mockReferralNumber,
|
||||||
|
mockCorrelationId,
|
||||||
|
mockReferralDate,
|
||||||
|
accountNumber = "0",
|
||||||
|
savedSessionId,
|
||||||
|
crmCustomerId
|
||||||
|
) {
|
||||||
|
return {
|
||||||
|
referralNumber: mockReferralNumber,
|
||||||
|
referralCorrelationId: mockCorrelationId,
|
||||||
|
referralDate: mockReferralDate,
|
||||||
|
accountNumber: accountNumber,
|
||||||
|
savedSessionId: savedSessionId,
|
||||||
|
crmCustomerId: crmCustomerId,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function setupCookies({ funnelCookieValue = "", includeHeritageCookie = true }) {
|
||||||
|
Object.keys(cookies).forEach((key) => {
|
||||||
|
const cookieValue =
|
||||||
|
key == cookieNames.FUNNEL_SESSION_INFO ? funnelCookieValue : cookies[key];
|
||||||
|
if (includeHeritageCookie || key != cookieNames.FUNNEL_SESSION_INFO)
|
||||||
|
setCookieProperties({ [key]: cookieValue }, { isSecure: false });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Private methods
|
||||||
|
function setupBaseMixinDispatchStoreAction(mockData) {
|
||||||
|
if (mockData.actionList !== undefined) {
|
||||||
|
baseMixin.methods.dispatchStoreAction = jest.fn();
|
||||||
|
baseMixin.methods.dispatchStoreAction.mockImplementation((actionName) => {
|
||||||
|
let actionFilterResult = mockData.actionList.filter((x) => x.actionName == actionName);
|
||||||
|
|
||||||
|
if (actionFilterResult.length > 0 && actionFilterResult.length === 1) {
|
||||||
|
return Promise.resolve({
|
||||||
|
data: actionFilterResult[0].data,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
212
src/mixins/analytics-mixin.js
Normal file
212
src/mixins/analytics-mixin.js
Normal file
|
|
@ -0,0 +1,212 @@
|
||||||
|
import { storeActions } from "@/constants/store-actions";
|
||||||
|
import {
|
||||||
|
setCookieProperties,
|
||||||
|
getDeviceIdValue,
|
||||||
|
getSessionIdValue,
|
||||||
|
getSessionKeyValue,
|
||||||
|
} from "@/helpers/heritage-integration/cookie-helper";
|
||||||
|
import { queryStrings } from "@/constants/query-strings";
|
||||||
|
import { experimentSettings } from "@/constants/experiments";
|
||||||
|
import {
|
||||||
|
analyticsPageEvents,
|
||||||
|
GaCategories,
|
||||||
|
GaActions,
|
||||||
|
GaLabels,
|
||||||
|
GaEvents,
|
||||||
|
ValueToLogTypes,
|
||||||
|
} from "@/constants/analytics";
|
||||||
|
import { cookieNames } from "@/constants/cookie-names";
|
||||||
|
import store from "@/store";
|
||||||
|
|
||||||
|
import baseMixin from "@/mixins/base-mixin";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
methods: {
|
||||||
|
logPageView(pageEvent) {
|
||||||
|
const currentPageName = getPageNameByQueryString();
|
||||||
|
var payload = {
|
||||||
|
userId: getDeviceIdValue(),
|
||||||
|
sessionKey: getSessionKeyValue(),
|
||||||
|
pageName: currentPageName,
|
||||||
|
sessionId: getSessionIdValue(),
|
||||||
|
action: "",
|
||||||
|
event: pageEvent,
|
||||||
|
shouldUseSessionId: false,
|
||||||
|
experimentsForUser: store.getters.applicationUser.experiments,
|
||||||
|
};
|
||||||
|
|
||||||
|
baseMixin.methods.dispatchStoreAction(storeActions.LOG_PAGE_VIEW, payload, false);
|
||||||
|
},
|
||||||
|
|
||||||
|
logCustomEvent(category, action, label, value) {
|
||||||
|
const currentPageName = getPageNameByQueryString();
|
||||||
|
|
||||||
|
var payload = {
|
||||||
|
userId: getDeviceIdValue(),
|
||||||
|
sessionKey: getSessionKeyValue(),
|
||||||
|
pageName: currentPageName,
|
||||||
|
sessionId: getSessionIdValue(),
|
||||||
|
category: category,
|
||||||
|
action: action,
|
||||||
|
label: label,
|
||||||
|
value: value,
|
||||||
|
shouldUseSessionId: false,
|
||||||
|
experimentsForUser: store.getters.applicationUser.experiments,
|
||||||
|
};
|
||||||
|
|
||||||
|
baseMixin.methods.dispatchStoreAction(storeActions.LOG_CUSTOM_EVENT, payload, false);
|
||||||
|
},
|
||||||
|
|
||||||
|
pushEventToGA(category, action, label, pushToLogApp = false, valueToLogType = null) {
|
||||||
|
const currentPageName = getPageNameByQueryString();
|
||||||
|
const labelToLog = getValueToLog(label, valueToLogType);
|
||||||
|
|
||||||
|
const eventToBePushed = {
|
||||||
|
event: GaEvents.GENERIC_EVENT,
|
||||||
|
category: category,
|
||||||
|
action: action,
|
||||||
|
label: labelToLog,
|
||||||
|
value: undefined,
|
||||||
|
path: `/fmg/?${queryStrings.FMG_PAGE}=${currentPageName}`,
|
||||||
|
};
|
||||||
|
|
||||||
|
pushToDataLayerIfDefined(eventToBePushed);
|
||||||
|
|
||||||
|
if (pushToLogApp) {
|
||||||
|
this.logCustomEvent(category, action, labelToLog, undefined);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
pushPageViewToGA() {
|
||||||
|
const currentPageName = getPageNameByQueryString();
|
||||||
|
const pageViewEvent = {
|
||||||
|
event: GaEvents.PAGE_VIEW_EVENT,
|
||||||
|
pagePath: `/fmg/?${queryStrings.FMG_PAGE}=${currentPageName}`,
|
||||||
|
pageTitle: currentPageName,
|
||||||
|
};
|
||||||
|
|
||||||
|
pushToDataLayerIfDefined(pageViewEvent);
|
||||||
|
|
||||||
|
this.logPageView(analyticsPageEvents.ENTRY);
|
||||||
|
},
|
||||||
|
|
||||||
|
pushExperimentsToDataLayer() {
|
||||||
|
const experiments = store.getters.applicationUser.experiments;
|
||||||
|
experiments?.forEach((exp) => {
|
||||||
|
// Set Google Dimension Index based on experiment settings.
|
||||||
|
let googleDimensionIndex = 99;
|
||||||
|
|
||||||
|
if (exp.settings[experimentSettings.GOOGLE_CUSTOM_DIMENSION_INDEX] !== undefined) {
|
||||||
|
googleDimensionIndex =
|
||||||
|
exp.settings[experimentSettings.GOOGLE_CUSTOM_DIMENSION_INDEX];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create object with dimension index and value.
|
||||||
|
const experimentWithDimension = {
|
||||||
|
[`experimentId_${googleDimensionIndex}`]: exp.universeId,
|
||||||
|
[`variationId_${googleDimensionIndex}`]: exp.variationId,
|
||||||
|
[`experimentName_${googleDimensionIndex}`]: exp.universeName,
|
||||||
|
[`variationName_${googleDimensionIndex}`]: exp.variationName,
|
||||||
|
[`customDimension_${googleDimensionIndex}`]: `${exp.universeId}_${exp.variationId}_${exp.universeName}_${exp.variationName}`,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Push to the data layer with the Google Custom Dimension Index.
|
||||||
|
pushToDataLayerIfDefined(experimentWithDimension);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
prependActionToMethod(object, method, actionToPrepend) {
|
||||||
|
const baseMethodName = method.name.startsWith("bound ")
|
||||||
|
? method.name.substring(6)
|
||||||
|
: method.name;
|
||||||
|
const baseMethod = object[baseMethodName];
|
||||||
|
object[baseMethodName] = function () {
|
||||||
|
actionToPrepend.apply(this, arguments);
|
||||||
|
return baseMethod.apply(object, arguments);
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
async initSession() {
|
||||||
|
const sid = getSessionIdValue();
|
||||||
|
const skey = getSessionKeyValue();
|
||||||
|
var payload = {
|
||||||
|
userId: getDeviceIdValue(),
|
||||||
|
sessionId: sid,
|
||||||
|
userAgent: navigator.userAgent,
|
||||||
|
referrer: document.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
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
noSession() {
|
||||||
|
return (
|
||||||
|
getSessionKeyValue() === 0 ||
|
||||||
|
getSessionIdValue() === "00000000-0000-0000-0000-000000000000"
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
analyticsPageEvents() {
|
||||||
|
return analyticsPageEvents;
|
||||||
|
},
|
||||||
|
GaCategories() {
|
||||||
|
return GaCategories;
|
||||||
|
},
|
||||||
|
GaActions() {
|
||||||
|
return GaActions;
|
||||||
|
},
|
||||||
|
GaLabels() {
|
||||||
|
return GaLabels;
|
||||||
|
},
|
||||||
|
ValueToLogTypes() {
|
||||||
|
return ValueToLogTypes;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
function pushToDataLayerIfDefined(data) {
|
||||||
|
if (window.dataLayer !== undefined) {
|
||||||
|
window.dataLayer.push(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getPageNameByQueryString() {
|
||||||
|
const params = new URLSearchParams(location.search);
|
||||||
|
|
||||||
|
if (params.has(queryStrings.FMG_PAGE)) {
|
||||||
|
return params.get(queryStrings.FMG_PAGE);
|
||||||
|
} else {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getValueToLog(value, valueToLogType) {
|
||||||
|
if (valueToLogType != null && valueToLogType === ValueToLogTypes.LAST_5) {
|
||||||
|
return value.slice(-5);
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
299
src/mixins/analytics-mixin.spec.js
Normal file
299
src/mixins/analytics-mixin.spec.js
Normal file
|
|
@ -0,0 +1,299 @@
|
||||||
|
import analyticsMixin from "@/mixins/analytics-mixin";
|
||||||
|
import { setupMocksForJsFiles, setupCookies } from "@/helpers/unit-test-helper.js";
|
||||||
|
import { storeActions } from "@/constants/store-actions";
|
||||||
|
import {
|
||||||
|
analyticsPageEvents,
|
||||||
|
GaCategories,
|
||||||
|
GaActions,
|
||||||
|
GaLabels,
|
||||||
|
GaEvents,
|
||||||
|
ValueToLogTypes,
|
||||||
|
} from "@/constants/analytics";
|
||||||
|
import store from "@/store";
|
||||||
|
|
||||||
|
describe("analyticsMixin.js", () => {
|
||||||
|
test("logPageView: calls dispatch with type and payload", () => {
|
||||||
|
const type = "";
|
||||||
|
const payload = {};
|
||||||
|
|
||||||
|
const mockData = {
|
||||||
|
actionList: [
|
||||||
|
{
|
||||||
|
actionName: storeActions.LOG_PAGE_VIEW,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
const mocks = setupMocksForJsFiles(mockData);
|
||||||
|
|
||||||
|
const testCookieValue = {
|
||||||
|
sid: "10000000-0000-0000-0000-000000000001",
|
||||||
|
};
|
||||||
|
|
||||||
|
setupCookies({ funnelCookieValue: JSON.stringify(testCookieValue) });
|
||||||
|
|
||||||
|
analyticsMixin.methods.logPageView(type, payload);
|
||||||
|
|
||||||
|
expect(mocks.baseMixin.methods.dispatchStoreAction).toBeCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("logCustomEvent: calls dispatch with type and payload", () => {
|
||||||
|
const mockData = {
|
||||||
|
actionList: [
|
||||||
|
{
|
||||||
|
actionName: storeActions.LOG_CUSTOM_EVENT,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
const mocks = setupMocksForJsFiles(mockData);
|
||||||
|
|
||||||
|
analyticsMixin.methods.logCustomEvent("someCat", "someAction", "someLabel", "someVal");
|
||||||
|
|
||||||
|
expect(mocks.baseMixin.methods.dispatchStoreAction).toBeCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("pushEventToGA, should call dataLayer push and logCustomEvent too", () => {
|
||||||
|
// Arrange
|
||||||
|
window.dataLayer = [];
|
||||||
|
const mockData = {
|
||||||
|
actionList: [
|
||||||
|
{
|
||||||
|
actionName: storeActions.LOG_CUSTOM_EVENT,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
const mocks = setupMocksForJsFiles(mockData);
|
||||||
|
var mockDataLayer = [];
|
||||||
|
mockDataLayer.push({
|
||||||
|
event: "event",
|
||||||
|
category: "category",
|
||||||
|
action: "action",
|
||||||
|
label: "label",
|
||||||
|
value: undefined,
|
||||||
|
path: "/fmg/?fmgPage=",
|
||||||
|
});
|
||||||
|
|
||||||
|
// Act
|
||||||
|
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", () => {
|
||||||
|
// Arrange
|
||||||
|
window.dataLayer = [];
|
||||||
|
var expectedDataLayer = [];
|
||||||
|
expectedDataLayer.push({
|
||||||
|
event: "event",
|
||||||
|
category: "category",
|
||||||
|
action: "action",
|
||||||
|
label: "33333",
|
||||||
|
value: undefined,
|
||||||
|
path: "/fmg/?fmgPage=",
|
||||||
|
});
|
||||||
|
|
||||||
|
// Act
|
||||||
|
analyticsMixin.methods.pushEventToGA(
|
||||||
|
"category",
|
||||||
|
"action",
|
||||||
|
"1111122222333333",
|
||||||
|
false,
|
||||||
|
ValueToLogTypes.LAST_5
|
||||||
|
);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
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", () => {
|
||||||
|
// Arrange
|
||||||
|
window.dataLayer = [];
|
||||||
|
var expectedDataLayer = [];
|
||||||
|
expectedDataLayer.push({
|
||||||
|
event: "event",
|
||||||
|
category: "category",
|
||||||
|
action: "action",
|
||||||
|
label: "111",
|
||||||
|
value: undefined,
|
||||||
|
path: "/fmg/?fmgPage=",
|
||||||
|
});
|
||||||
|
|
||||||
|
// Act
|
||||||
|
analyticsMixin.methods.pushEventToGA(
|
||||||
|
"category",
|
||||||
|
"action",
|
||||||
|
"111",
|
||||||
|
false,
|
||||||
|
ValueToLogTypes.LAST_5
|
||||||
|
);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(expectedDataLayer).toEqual(expect.arrayContaining(window.dataLayer));
|
||||||
|
});
|
||||||
|
|
||||||
|
test("Experiments, should push to dataLayer with default Google Custom Dimension Index", () => {
|
||||||
|
// Arrange
|
||||||
|
window.dataLayer = [];
|
||||||
|
|
||||||
|
const mockExperimentData = [
|
||||||
|
{
|
||||||
|
settings: {},
|
||||||
|
variationName: "test",
|
||||||
|
universeName: "testUniverse",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
// Mock store
|
||||||
|
jest.mock(
|
||||||
|
"@/store",
|
||||||
|
() => {
|
||||||
|
return {};
|
||||||
|
},
|
||||||
|
{ virtual: true }
|
||||||
|
);
|
||||||
|
|
||||||
|
store.getters = {
|
||||||
|
applicationUser: {
|
||||||
|
experiments: [
|
||||||
|
{
|
||||||
|
settings: {},
|
||||||
|
variationName: "test",
|
||||||
|
universeName: "testUniverse",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
analyticsMixin.methods.pushExperimentsToDataLayer(mockExperimentData);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(window.dataLayer).toEqual([
|
||||||
|
{
|
||||||
|
experimentId_99: undefined,
|
||||||
|
variationId_99: undefined,
|
||||||
|
experimentName_99: "testUniverse",
|
||||||
|
variationName_99: "test",
|
||||||
|
customDimension_99: "undefined_undefined_testUniverse_test",
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("Experiments, should push to dataLayer with custom Google Custom Dimension Index", () => {
|
||||||
|
// Arrange
|
||||||
|
window.dataLayer = [];
|
||||||
|
|
||||||
|
const mockExperimentData = [
|
||||||
|
{
|
||||||
|
settings: { "Google Custom Dimension Index": "5" },
|
||||||
|
variationName: "test",
|
||||||
|
universeName: "testUniverse",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
// Mock store
|
||||||
|
jest.mock(
|
||||||
|
"@/store",
|
||||||
|
() => {
|
||||||
|
return {};
|
||||||
|
},
|
||||||
|
{ virtual: true }
|
||||||
|
);
|
||||||
|
|
||||||
|
store.getters = {
|
||||||
|
applicationUser: {
|
||||||
|
experiments: [
|
||||||
|
{
|
||||||
|
settings: { "Google Custom Dimension Index": "5" },
|
||||||
|
variationName: "test",
|
||||||
|
universeName: "testUniverse",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
analyticsMixin.methods.pushExperimentsToDataLayer(mockExperimentData);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(window.dataLayer).toEqual([
|
||||||
|
{
|
||||||
|
experimentId_5: undefined,
|
||||||
|
variationId_5: undefined,
|
||||||
|
experimentName_5: "testUniverse",
|
||||||
|
variationName_5: "test",
|
||||||
|
customDimension_5: "undefined_undefined_testUniverse_test",
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("Obj is not null after action prepended", () => {
|
||||||
|
//Arrange
|
||||||
|
const obj = { baseMethodName: "testMethodName", data: "testData" };
|
||||||
|
const method = { name: "testMethodName", data: "testData" };
|
||||||
|
const action = "testAction";
|
||||||
|
|
||||||
|
//Act
|
||||||
|
analyticsMixin.methods.prependActionToMethod(obj, method, action);
|
||||||
|
|
||||||
|
//Assert
|
||||||
|
expect(obj != null);
|
||||||
|
});
|
||||||
|
test("Obj method name does not include bound", () => {
|
||||||
|
//Arrange
|
||||||
|
const obj = { baseMethodName: "testMethodName", data: "testData" };
|
||||||
|
const method = { name: "testMethodName", data: "testData" };
|
||||||
|
const action = "testAction";
|
||||||
|
|
||||||
|
//Act
|
||||||
|
analyticsMixin.methods.prependActionToMethod(obj, method, action);
|
||||||
|
|
||||||
|
//Assert
|
||||||
|
expect(method.name.startsWith("bound ")).toBe(false);
|
||||||
|
});
|
||||||
|
test("Prepended action does not include bound", () => {
|
||||||
|
//Arrange
|
||||||
|
const obj = { baseMethodName: "testMethodName", data: "testData" };
|
||||||
|
const method = { name: "testMethodName", data: "testData" };
|
||||||
|
const action = "testAction";
|
||||||
|
|
||||||
|
//Act
|
||||||
|
analyticsMixin.methods.prependActionToMethod(obj, method, action);
|
||||||
|
|
||||||
|
//Assert
|
||||||
|
expect(action.startsWith("bound ")).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("analyticsPageEvents returns constants analyticsPageEvents", () => {
|
||||||
|
//Act
|
||||||
|
const analyticsPE = analyticsMixin.computed.analyticsPageEvents();
|
||||||
|
|
||||||
|
//Assert
|
||||||
|
expect(analyticsPE).toEqual(analyticsPageEvents);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("GaActions returns constants GaActions", () => {
|
||||||
|
//Act
|
||||||
|
const gaActions = analyticsMixin.computed.GaActions();
|
||||||
|
|
||||||
|
//Assert
|
||||||
|
expect(gaActions).toEqual(GaActions);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("GaCategories returns constants GaCategories", () => {
|
||||||
|
//Act
|
||||||
|
const gaCategories = analyticsMixin.computed.GaCategories();
|
||||||
|
|
||||||
|
//Assert
|
||||||
|
expect(gaCategories).toEqual(GaCategories);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("GaLabels returns constants GaLabels", () => {
|
||||||
|
//Act
|
||||||
|
const gaLabels = analyticsMixin.computed.GaLabels();
|
||||||
|
|
||||||
|
//Assert
|
||||||
|
expect(gaLabels).toEqual(GaLabels);
|
||||||
|
});
|
||||||
|
});
|
||||||
Loading…
Reference in a new issue