diff --git a/src/helpers/heritage-integration/cookie-helper.spec.js b/src/helpers/heritage-integration/cookie-helper.spec.js index 5df2ae925..0929e0ed6 100644 --- a/src/helpers/heritage-integration/cookie-helper.spec.js +++ b/src/helpers/heritage-integration/cookie-helper.spec.js @@ -3,10 +3,25 @@ import { getDeviceIdValue, getSessionKeyValue, getSessionIdValue, + setCookieProperties, + regenerateDeviceId, + getUserIdValue, + regenerateUserId, + setSessionKeyIfUnset, + setSessionIdIfUnset, + isCookieSet, + refreshCookieExpiration, } 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,40 +121,284 @@ 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(); + }); }); }); - describe("getSessionIdValue", () => { - test("getSessionIdValue, should return GUID", () => { + 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(); + }); + }); + }); + + describe("Session Key", () => { + describe("getSessionKeyValue", () => { + test("Should return session key int", () => { + // Arrange + setupCookies({}); + + // Act + const result = getSessionKeyValue(); + + //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("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("isCookieSet", () => { + test("Returns true if cookie is set and unexpired", () => { // Arrange setupCookies({}); // Act - const result = getSessionIdValue(); + const result = isCookieSet(cookieNames.SESSION_ID); - //Assert - expect(result).toBe("cba0c3d1-3c1b-4305-bb56-31aa50f58e27"); + // 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); + }); + }); + + 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); }); }); }); diff --git a/src/helpers/unit-test-helper.js b/src/helpers/unit-test-helper.js index 123dc9d40..2cd580df0 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) { diff --git a/src/mixins/analytics-mixin.spec.js b/src/mixins/analytics-mixin.spec.js index 8f7cfceaa..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 } 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,20 +15,19 @@ import { ValueToLogTypes, } 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(), - }; -}); +import { + getDeviceIdValue, + getSessionIdValue, + getSessionKeyValue, + getUserIdValue, +} from "@/helpers/heritage-integration/cookie-helper"; describe("analyticsMixin.js", () => { + beforeEach(() => { + removeAllTestCookies(); + setupCrypto("7e4727f3-9a3d-4c59-9cb3-6f4121b5ea94"); + }); + test("logPageView: calls dispatch with type and payload", async () => { const type = ""; const payload = {}; @@ -348,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(); + }); + }); });