From 69338deced978b664555bbf837dd8b6de2e141f0 Mon Sep 17 00:00:00 2001 From: Alex Yau Date: Mon, 11 Sep 2023 14:54:20 +1000 Subject: [PATCH 01/21] Local storage option for v3 js sdk - Migrate legacy cookie to new cookie - Add useCookie option - use localStorage by default --- src/Uid2Options.ts | 2 +- src/uid2CookieManager.ts | 10 +++++++++- src/uid2LocalStorageManager.ts | 23 +++++++++++++++++++++++ src/uid2Sdk.ts | 25 ++++++++++++++++++++----- 4 files changed, 53 insertions(+), 7 deletions(-) create mode 100644 src/uid2LocalStorageManager.ts diff --git a/src/Uid2Options.ts b/src/Uid2Options.ts index 4a36455..8c787c3 100644 --- a/src/Uid2Options.ts +++ b/src/Uid2Options.ts @@ -6,7 +6,7 @@ import { InitCallbackOptions } from "./Uid2InitCallbacks"; export type Uid2Options = BaseUid2Options & InitCallbackOptions & UID2CookieOptions & - Uid2ApiClientOptions; + Uid2ApiClientOptions & { useCookie?: boolean; }; type BaseUid2Options = { refreshRetryPeriod?: number; identity?: Uid2Identity; diff --git a/src/uid2CookieManager.ts b/src/uid2CookieManager.ts index 3c8d23b..31a2416 100644 --- a/src/uid2CookieManager.ts +++ b/src/uid2CookieManager.ts @@ -71,12 +71,20 @@ export class UID2CookieManager { } } + private migrateLegacyCookie(identity: LegacyUid2SDKCookie, now: number): Uid2Identity { + const newCookie = enrichIdentity(identity, now); + this.setCookie(newCookie); + return newCookie; + } + public loadIdentityFromCookie(): Uid2Identity | null { const payload = this.getCookie(); if (payload) { const result = JSON.parse(payload) as unknown; if (isValidIdentity(result)) return result; - if (isLegacyCookie(result)) return enrichIdentity(result, Date.now()); + if (isLegacyCookie(result)) { + return this.migrateLegacyCookie(result, Date.now()); + } } return null; } diff --git a/src/uid2LocalStorageManager.ts b/src/uid2LocalStorageManager.ts new file mode 100644 index 0000000..2d7a99f --- /dev/null +++ b/src/uid2LocalStorageManager.ts @@ -0,0 +1,23 @@ +import { isValidIdentity, Uid2Identity } from "./Uid2Identity"; + +export class UID2LocalStorageManager { + public setValue(identity: Uid2Identity) { + const value = JSON.stringify(identity); + localStorage.setItem("identity", value); + } + public removeValue() { + localStorage.removeItem("identity"); + } + private getValue() { + return localStorage.getItem("identity"); + } + + public loadIdentityFromLocalStorage(): Uid2Identity | null { + const payload = this.getValue(); + if (payload) { + const result = JSON.parse(payload) as unknown; + if (isValidIdentity(result)) return result; + } + return null; + } +} diff --git a/src/uid2Sdk.ts b/src/uid2Sdk.ts index cdaba0f..227eb83 100644 --- a/src/uid2Sdk.ts +++ b/src/uid2Sdk.ts @@ -17,6 +17,7 @@ import { isClientSideIdentityOptionsOrThrow, } from "./uid2ClientSideIdentityOptions"; import { bytesToBase64 } from "./uid2Base64"; +import { UID2LocalStorageManager } from "./uid2LocalStorageManager"; function hasExpired(expiry: number, now = Date.now()) { return expiry <= now; @@ -55,6 +56,7 @@ export class UID2 { // Dependencies initialised on call to init due to requirement for options private _cookieManager: UID2CookieManager | undefined; + private _localStorageManager: UID2LocalStorageManager | undefined; private _apiClient: Uid2ApiClient | undefined; // State @@ -219,11 +221,18 @@ export class UID2 { this._opts = opts; this._cookieManager = new UID2CookieManager({ ...opts }); + this._localStorageManager = new UID2LocalStorageManager(); this._apiClient = new Uid2ApiClient(opts); this._tokenPromiseHandler.registerApiClient(this._apiClient); - const identity = this._opts.identity - ? this._opts.identity - : this._cookieManager.loadIdentityFromCookie(); + + let identity; + if (this._opts.identity) { + identity = this._opts.identity; + } else if (opts.useCookie) { + identity = this._cookieManager.loadIdentityFromCookie(); + } else { + identity = this._localStorageManager.loadIdentityFromLocalStorage(); + } const validatedIdentity = this.validateAndSetIdentity(identity); if (validatedIdentity) this.triggerRefreshOrSetTimer(validatedIdentity); this._initComplete = true; @@ -318,7 +327,7 @@ export class UID2 { status?: IdentityStatus, statusText?: string ): Uid2Identity | null { - if (!this._cookieManager) + if (!this._cookieManager || !this._localStorageManager) throw new Error("Cannot set identity before calling init."); const validity = this.getIdentityStatus(identity); if ( @@ -329,10 +338,16 @@ export class UID2 { this._identity = validity.identity; if (validity.identity) { - this._cookieManager.setCookie(validity.identity); + if (this._opts.useCookie) { + this._cookieManager.setCookie(validity.identity); + } + else { + this._localStorageManager.setValue(validity.identity); + } } else { this.abort(); this._cookieManager.removeCookie(); + this._localStorageManager.removeValue(); } notifyInitCallback( this._opts, From 7b25accef9b6c6765b31f9210534d506d18be6fa Mon Sep 17 00:00:00 2001 From: Alex Yau Date: Mon, 11 Sep 2023 14:54:38 +1000 Subject: [PATCH 02/21] Prettier changes --- src/uid2Sdk.ts | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/uid2Sdk.ts b/src/uid2Sdk.ts index 227eb83..08562a3 100644 --- a/src/uid2Sdk.ts +++ b/src/uid2Sdk.ts @@ -256,17 +256,17 @@ export class UID2 { private getIdentityStatus(identity: Uid2Identity | null): | { - valid: true; - identity: Uid2Identity; - errorMessage: string; - status: IdentityStatus; - } + valid: true; + identity: Uid2Identity; + errorMessage: string; + status: IdentityStatus; + } | { - valid: false; - errorMessage: string; - status: IdentityStatus; - identity: null; - } { + valid: false; + errorMessage: string; + status: IdentityStatus; + identity: null; + } { if (!identity) { return { valid: false, @@ -438,7 +438,7 @@ export class UID2 { } private async callCstgAndSetIdentity( - request: { emailHash: string } | { phoneHash: string }, + request: { emailHash: string; } | { phoneHash: string; }, opts: ClientSideIdentityOptions ) { const cstgResult = await this._apiClient!.callCstgApi(request, opts); From 0e045aef17fdd66f5cffffa8a8f0e4195e525e42 Mon Sep 17 00:00:00 2001 From: Alex Yau Date: Mon, 11 Sep 2023 15:04:36 +1000 Subject: [PATCH 03/21] Migrate from cookie to localStorage --- src/uid2Sdk.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/uid2Sdk.ts b/src/uid2Sdk.ts index 08562a3..16dcff0 100644 --- a/src/uid2Sdk.ts +++ b/src/uid2Sdk.ts @@ -228,10 +228,9 @@ export class UID2 { let identity; if (this._opts.identity) { identity = this._opts.identity; - } else if (opts.useCookie) { - identity = this._cookieManager.loadIdentityFromCookie(); } else { - identity = this._localStorageManager.loadIdentityFromLocalStorage(); + const localStorageIdentity = this._localStorageManager.loadIdentityFromLocalStorage(); + identity = localStorageIdentity !== null ? localStorageIdentity : this._cookieManager.loadIdentityFromCookie(); } const validatedIdentity = this.validateAndSetIdentity(identity); if (validatedIdentity) this.triggerRefreshOrSetTimer(validatedIdentity); @@ -342,6 +341,7 @@ export class UID2 { this._cookieManager.setCookie(validity.identity); } else { + this._cookieManager.removeCookie(); this._localStorageManager.setValue(validity.identity); } } else { From 3428da608467fea74afeb76f4b117a6d40d24ae5 Mon Sep 17 00:00:00 2001 From: Alex Yau Date: Wed, 13 Sep 2023 10:50:26 +1000 Subject: [PATCH 04/21] Use cookie identity if later expipry --- src/uid2Sdk.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/uid2Sdk.ts b/src/uid2Sdk.ts index 16dcff0..b05c9d4 100644 --- a/src/uid2Sdk.ts +++ b/src/uid2Sdk.ts @@ -230,7 +230,9 @@ export class UID2 { identity = this._opts.identity; } else { const localStorageIdentity = this._localStorageManager.loadIdentityFromLocalStorage(); - identity = localStorageIdentity !== null ? localStorageIdentity : this._cookieManager.loadIdentityFromCookie(); + const cookieIdentity = this._cookieManager.loadIdentityFromCookie(); + const shouldUseCookie = cookieIdentity && (!localStorageIdentity || cookieIdentity.identity_expires > localStorageIdentity.identity_expires); + identity = shouldUseCookie ? cookieIdentity : localStorageIdentity; } const validatedIdentity = this.validateAndSetIdentity(identity); if (validatedIdentity) this.triggerRefreshOrSetTimer(validatedIdentity); @@ -340,8 +342,10 @@ export class UID2 { if (this._opts.useCookie) { this._cookieManager.setCookie(validity.identity); } - else { + else if (this._opts.useCookie === false) { + this._localStorageManager.setValue(validity.identity); this._cookieManager.removeCookie(); + } else if (this._opts.useCookie === undefined) { this._localStorageManager.setValue(validity.identity); } } else { From 4754e1fca65a919abbecf917114ec82a89857392 Mon Sep 17 00:00:00 2001 From: Alex Yau Date: Thu, 14 Sep 2023 13:38:36 +1000 Subject: [PATCH 05/21] change localStorage key --- src/uid2LocalStorageManager.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/uid2LocalStorageManager.ts b/src/uid2LocalStorageManager.ts index 2d7a99f..cfd4773 100644 --- a/src/uid2LocalStorageManager.ts +++ b/src/uid2LocalStorageManager.ts @@ -3,13 +3,13 @@ import { isValidIdentity, Uid2Identity } from "./Uid2Identity"; export class UID2LocalStorageManager { public setValue(identity: Uid2Identity) { const value = JSON.stringify(identity); - localStorage.setItem("identity", value); + localStorage.setItem("UID2-identity", value); } public removeValue() { - localStorage.removeItem("identity"); + localStorage.removeItem("UID2-identity"); } private getValue() { - return localStorage.getItem("identity"); + return localStorage.getItem("UID2-identity"); } public loadIdentityFromLocalStorage(): Uid2Identity | null { From 1fbd9432588fd8f25eb85ba27729bcf61f0f6c29 Mon Sep 17 00:00:00 2001 From: Alex Yau Date: Mon, 25 Sep 2023 13:18:45 +1000 Subject: [PATCH 06/21] Addressing feedback - Use const for localStorageKeyName - Move useCookie to base options - Check if value is in localStorage before removing cookie --- src/Uid2Options.ts | 3 ++- src/uid2LocalStorageManager.ts | 10 ++++++---- src/uid2Sdk.ts | 4 ++-- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/Uid2Options.ts b/src/Uid2Options.ts index 8c787c3..9b8cb48 100644 --- a/src/Uid2Options.ts +++ b/src/Uid2Options.ts @@ -6,10 +6,11 @@ import { InitCallbackOptions } from "./Uid2InitCallbacks"; export type Uid2Options = BaseUid2Options & InitCallbackOptions & UID2CookieOptions & - Uid2ApiClientOptions & { useCookie?: boolean; }; + Uid2ApiClientOptions; type BaseUid2Options = { refreshRetryPeriod?: number; identity?: Uid2Identity; + useCookie?: boolean; }; export function isUID2OptionsOrThrow( diff --git a/src/uid2LocalStorageManager.ts b/src/uid2LocalStorageManager.ts index cfd4773..f1bcd4c 100644 --- a/src/uid2LocalStorageManager.ts +++ b/src/uid2LocalStorageManager.ts @@ -1,15 +1,17 @@ import { isValidIdentity, Uid2Identity } from "./Uid2Identity"; +export const localStorageKeyName = 'UID2-sdk-identity' + export class UID2LocalStorageManager { public setValue(identity: Uid2Identity) { const value = JSON.stringify(identity); - localStorage.setItem("UID2-identity", value); + localStorage.setItem(localStorageKeyName, value); } public removeValue() { - localStorage.removeItem("UID2-identity"); + localStorage.removeItem(localStorageKeyName); } - private getValue() { - return localStorage.getItem("UID2-identity"); + public getValue() { + return localStorage.getItem(localStorageKeyName); } public loadIdentityFromLocalStorage(): Uid2Identity | null { diff --git a/src/uid2Sdk.ts b/src/uid2Sdk.ts index b05c9d4..f39eac0 100644 --- a/src/uid2Sdk.ts +++ b/src/uid2Sdk.ts @@ -344,8 +344,8 @@ export class UID2 { } else if (this._opts.useCookie === false) { this._localStorageManager.setValue(validity.identity); - this._cookieManager.removeCookie(); - } else if (this._opts.useCookie === undefined) { + if (this._localStorageManager.getValue()) this._cookieManager.removeCookie(); + } else { this._localStorageManager.setValue(validity.identity); } } else { From 410b8b17d1d7d277a31a717252cba4f4572aea17 Mon Sep 17 00:00:00 2001 From: Alex Yau Date: Mon, 25 Sep 2023 13:19:59 +1000 Subject: [PATCH 07/21] WIP Tests - There are still 8 tests failing in 4 suites --- src/integrationTests/async.spec.ts | 348 ++-- src/integrationTests/autoRefresh.test.ts | 948 ++++++----- src/integrationTests/basic.test.ts | 1769 +++++++++++--------- src/integrationTests/callbacks.test.ts | 184 +- src/integrationTests/compatibility.test.ts | 204 ++- src/integrationTests/options.test.ts | 46 +- src/integrationTests/secureSignal.test.ts | 2 +- src/mocks.ts | 20 + 8 files changed, 1944 insertions(+), 1577 deletions(-) diff --git a/src/integrationTests/async.spec.ts b/src/integrationTests/async.spec.ts index a2bd786..a8f25af 100644 --- a/src/integrationTests/async.spec.ts +++ b/src/integrationTests/async.spec.ts @@ -29,195 +29,237 @@ afterEach(() => { mocks.resetFakeTime(); }); +const removeUid2Cookie = mocks.removeUid2Cookie; +const removeUid2LocalStorage = mocks.removeUid2LocalStorage; + const makeIdentity = mocks.makeIdentityV2; -describe("when getAdvertisingTokenAsync is called before init", () => { - describe("when initialising with a valid identity", () => { - const identity = makeIdentity(); - test("it should resolve promise after invoking the callback", () => { - const p = uid2.getAdvertisingTokenAsync().then((token: any) => { - expect(callback).toHaveBeenCalled(); - return token; - }); - uid2.init({ callback: callback, identity: identity }); - jest.runAllTimers(); - return expect(p).resolves.toBe(identity.advertising_token); +let useCookie: boolean | undefined = undefined; + +const testCookieAndLocalStorage = (test: () => void, only = false) => { + const describeFn = only ? describe.only : describe; + describeFn('Using default: ', () => { + beforeEach(() => { + removeUid2Cookie(); + removeUid2LocalStorage(); + useCookie = undefined; }); + test(); }); - - describe("when initialising with an invalid identity", () => { - test("it should reject promise after invoking the callback", () => { - const p = uid2.getAdvertisingTokenAsync().catch((e: any) => { - expect(callback).toHaveBeenCalled(); - throw e; - }); - uid2.init({ callback: callback }); - return expect(p).rejects.toBeInstanceOf(Error); + describeFn('Using cookies ', () => { + beforeEach(() => { + removeUid2Cookie(); + removeUid2LocalStorage(); + useCookie = true; }); + test(); }); + describeFn('Using local storage ', () => { + beforeEach(() => { + removeUid2Cookie(); + removeUid2LocalStorage(); + useCookie = false; + }); + test(); + }); +}; - describe("when initalising with a non-expired identity which requires a refresh", () => { - test("it should resolve updated advertising", () => { - const originalIdentity = makeIdentity({ - refresh_from: Date.now() - 100000, - }); - const updatedIdentity = makeIdentity({ - advertising_token: "updated_advertising_token", +testCookieAndLocalStorage(() => { + describe("when getAdvertisingTokenAsync is called before init", () => { + describe("when initialising with a valid identity", () => { + const identity = makeIdentity(); + test("it should resolve promise after invoking the callback", () => { + const p = uid2.getAdvertisingTokenAsync().then((token: any) => { + expect(callback).toHaveBeenCalled(); + return token; + }); + uid2.init({ callback: callback, identity: identity, useCookie: useCookie }); + jest.runAllTimers(); + return expect(p).resolves.toBe(identity.advertising_token); }); - const p = uid2.getAdvertisingTokenAsync(); - uid2.init({ identity: originalIdentity }); - xhrMock.responseText = btoa( - JSON.stringify({ status: "success", body: updatedIdentity }) - ); - xhrMock.onreadystatechange(new Event("")); - return expect(p).resolves.toBe(updatedIdentity.advertising_token); }); - }); - describe("when auto refresh fails, but identity still valid", () => { - test("it should resolve original advertising token", () => { - const originalIdentity = makeIdentity({ - refresh_from: Date.now() - 100000, + describe("when initialising with an invalid identity", () => { + test("it should reject promise after invoking the callback", () => { + const p = uid2.getAdvertisingTokenAsync().catch((e: any) => { + expect(callback).toHaveBeenCalled(); + throw e; + }); + uid2.init({ callback: callback, useCookie: useCookie }); + return expect(p).rejects.toBeInstanceOf(Error); }); - const p = uid2.getAdvertisingTokenAsync().then((token: any) => { - expect(callback).toHaveBeenCalled(); - return token; + }); + + describe("when initialising with a non-expired identity which requires a refresh", () => { + test("it should resolve updated advertising", () => { + const originalIdentity = makeIdentity({ + refresh_from: Date.now() - 100000, + }); + const updatedIdentity = makeIdentity({ + advertising_token: "updated_advertising_token", + }); + const p = uid2.getAdvertisingTokenAsync(); + uid2.init({ identity: originalIdentity, useCookie: useCookie }); + xhrMock.responseText = btoa( + JSON.stringify({ status: "success", body: updatedIdentity }) + ); + xhrMock.onreadystatechange(new Event("")); + return expect(p).resolves.toBe(updatedIdentity.advertising_token); }); - uid2.init({ callback: callback, identity: originalIdentity }); - xhrMock.responseText = JSON.stringify({ status: "error" }); - xhrMock.onreadystatechange(new Event("")); - return expect(p).resolves.toBe(originalIdentity.advertising_token); }); - }); - describe("when auto refresh fails, but identity already expired", () => { - test("it should reject promise after invoking the callback", () => { - const originalIdentity = makeIdentity({ - refresh_from: Date.now() - 100000, - identity_expires: Date.now() - 1, + describe("when auto refresh fails, but identity still valid", () => { + test("it should resolve original advertising token", () => { + const originalIdentity = makeIdentity({ + refresh_from: Date.now() - 100000, + }); + const p = uid2.getAdvertisingTokenAsync().then((token: any) => { + expect(callback).toHaveBeenCalled(); + return token; + }); + uid2.init({ callback: callback, identity: originalIdentity, useCookie: useCookie }); + xhrMock.responseText = JSON.stringify({ status: "error" }); + xhrMock.onreadystatechange(new Event("")); + return expect(p).resolves.toBe(originalIdentity.advertising_token); }); - const p = uid2.getAdvertisingTokenAsync().catch((e: any) => { - expect(callback).toHaveBeenCalled(); - throw e; + }); + + describe("when auto refresh fails, but identity already expired", () => { + test("it should reject promise after invoking the callback", () => { + const originalIdentity = makeIdentity({ + refresh_from: Date.now() - 100000, + identity_expires: Date.now() - 1, + }); + const p = uid2.getAdvertisingTokenAsync().catch((e: any) => { + expect(callback).toHaveBeenCalled(); + throw e; + }); + uid2.init({ callback: callback, identity: originalIdentity, useCookie: useCookie }); + xhrMock.responseText = JSON.stringify({ status: "error" }); + xhrMock.onreadystatechange(new Event("")); + return expect(p).rejects.toBeInstanceOf(Error); }); - uid2.init({ callback: callback, identity: originalIdentity }); - xhrMock.responseText = JSON.stringify({ status: "error" }); - xhrMock.onreadystatechange(new Event("")); - return expect(p).rejects.toBeInstanceOf(Error); }); - }); - describe("when giving multiple promises", () => { - const identity = makeIdentity(); - test("it should resolve all promises", () => { - const p1 = uid2.getAdvertisingTokenAsync(); - const p2 = uid2.getAdvertisingTokenAsync(); - const p3 = uid2.getAdvertisingTokenAsync(); - uid2.init({ identity: identity }); - return expect(Promise.all([p1, p2, p3])).resolves.toStrictEqual( - Array(3).fill(identity.advertising_token) - ); + describe("when giving multiple promises", () => { + const identity = makeIdentity(); + test("it should resolve all promises", () => { + const p1 = uid2.getAdvertisingTokenAsync(); + const p2 = uid2.getAdvertisingTokenAsync(); + const p3 = uid2.getAdvertisingTokenAsync(); + uid2.init({ identity: identity, useCookie: useCookie }); + return expect(Promise.all([p1, p2, p3])).resolves.toStrictEqual( + Array(3).fill(identity.advertising_token) + ); + }); }); }); -}); -describe("when getAdvertisingTokenAsync is called after init completed", () => { - describe("when initialised with a valid identity", () => { - const identity = makeIdentity(); - test("it should resolve promise", () => { - uid2.init({ identity: identity }); - return expect(uid2.getAdvertisingTokenAsync()).resolves.toBe( - identity.advertising_token - ); + describe("when getAdvertisingTokenAsync is called after init completed", () => { + describe("when initialised with a valid identity", () => { + const identity = makeIdentity(); + test("it should resolve promise", () => { + uid2.init({ identity: identity, useCookie: useCookie }); + return expect(uid2.getAdvertisingTokenAsync()).resolves.toBe( + identity.advertising_token + ); + }); }); - }); - describe("when initialisation failed", () => { - test("it should reject promise", () => { - uid2.init({}); - return expect(uid2.getAdvertisingTokenAsync()).rejects.toBeInstanceOf( - Error - ); + describe("when initialisation failed", () => { + + // beforeEach(() => { + // removeUid2Cookie(); + // removeUid2LocalStorage(); + // }); + test("it should reject promise", () => { + uid2.init({}); + return expect(uid2.getAdvertisingTokenAsync()).rejects.toBeInstanceOf( + Error + ); + }); }); - }); - describe("when identity is temporarily not available", () => { - test("it should reject promise", () => { - const originalIdentity = makeIdentity({ - refresh_from: Date.now() - 100000, - identity_expires: Date.now() - 1, + describe("when identity is temporarily not available", () => { + test("it should reject promise", () => { + const originalIdentity = makeIdentity({ + refresh_from: Date.now() - 100000, + identity_expires: Date.now() - 1, + }); + uid2.init({ identity: originalIdentity, useCookie: useCookie }); + xhrMock.responseText = JSON.stringify({ status: "error" }); + xhrMock.onreadystatechange(new Event("")); + return expect(uid2.getAdvertisingTokenAsync()).rejects.toBeInstanceOf( + Error + ); }); - uid2.init({ identity: originalIdentity }); - xhrMock.responseText = JSON.stringify({ status: "error" }); - xhrMock.onreadystatechange(new Event("")); - return expect(uid2.getAdvertisingTokenAsync()).rejects.toBeInstanceOf( - Error - ); }); - }); - describe("when disconnect() has been called", () => { - test("it should reject promise", () => { - uid2.init({ identity: makeIdentity() }); - uid2.disconnect(); - return expect(uid2.getAdvertisingTokenAsync()).rejects.toBeInstanceOf( - Error - ); + describe("when disconnect() has been called", () => { + test("it should reject promise", () => { + uid2.init({ identity: makeIdentity(), useCookie: useCookie }); + uid2.disconnect(); + return expect(uid2.getAdvertisingTokenAsync()).rejects.toBeInstanceOf( + Error + ); + }); }); }); -}); -describe("when getAdvertisingTokenAsync is called before refresh on init completes", () => { - const originalIdentity = makeIdentity({ - refresh_from: Date.now() - 100000, - }); - beforeEach(() => { - uid2.init({ identity: originalIdentity }); - }); + describe("when getAdvertisingTokenAsync is called before refresh on init completes", () => { + const originalIdentity = makeIdentity({ + refresh_from: Date.now() - 100000, + }); + beforeEach(() => { + uid2.init({ identity: originalIdentity, useCookie: useCookie }); + }); - describe("when promise obtained after disconnect", () => { - test("it should reject promise", () => { - uid2.disconnect(); - return expect(uid2.getAdvertisingTokenAsync()).rejects.toBeInstanceOf( - Error - ); + describe("when promise obtained after disconnect", () => { + test("it should reject promise", () => { + uid2.disconnect(); + return expect(uid2.getAdvertisingTokenAsync()).rejects.toBeInstanceOf( + Error + ); + }); }); }); -}); -describe("when window.__uid2.init is called on SdkLoaded from a callback", () => { - const identity = makeIdentity(); - // Reset window UID2 instance - const callback = jest.fn((eventType: EventType) => { - if (eventType === UID2.EventType.SdkLoaded) { - console.log("Trying"); - try { - (sdkWindow.__uid2 as UID2).init({ identity }); - } catch (ex) { - console.log(ex); - throw ex; + describe("when window.__uid2.init is called on SdkLoaded from a callback", () => { + const identity = makeIdentity(); + // Reset window UID2 instance + const callback = jest.fn((eventType: EventType) => { + if (eventType === UID2.EventType.SdkLoaded) { + console.log("Trying"); + try { + (sdkWindow.__uid2 as UID2).init({ identity, useCookie: useCookie }); + } catch (ex) { + console.log(ex); + throw ex; + } + console.log("Succeeded"); } - console.log("Succeeded"); - } - }); - test("the SDK should be initialized correctly", () => { - sdkWindow.__uid2 = { callbacks: [] }; - sdkWindow.__uid2.callbacks!.push(callback); - expect(callback).toHaveBeenCalledTimes(0); - __uid2InternalHandleScriptLoad(); - jest.runOnlyPendingTimers(); - if (!(sdkWindow.__uid2 instanceof UID2)) - throw Error( - "UID2 should be ready to use by the time SdkLoaded is triggered." + }); + // only passes for cookies + test("the SDK should be initialized correctly", () => { + sdkWindow.__uid2 = { callbacks: [] }; + sdkWindow.__uid2.callbacks!.push(callback); + expect(callback).toHaveBeenCalledTimes(0); + __uid2InternalHandleScriptLoad(); + jest.runOnlyPendingTimers(); + if (!(sdkWindow.__uid2 instanceof UID2)) + throw Error( + "UID2 should be ready to use by the time SdkLoaded is triggered." + ); + expect(callback).toHaveBeenNthCalledWith( + 1, + UID2.EventType.SdkLoaded, + expect.anything() ); - expect(callback).toHaveBeenNthCalledWith( - 1, - UID2.EventType.SdkLoaded, - expect.anything() - ); - console.log(identity.advertising_token); - expect(sdkWindow.__uid2.getAdvertisingToken()).toBe( - identity.advertising_token - ); + console.log(sdkWindow.__uid2.getAdvertisingToken()); + console.log(identity.advertising_token); + expect(sdkWindow.__uid2.getAdvertisingToken()).toBe( + identity.advertising_token + ); + }); }); }); diff --git a/src/integrationTests/autoRefresh.test.ts b/src/integrationTests/autoRefresh.test.ts index bd6734f..e54958d 100644 --- a/src/integrationTests/autoRefresh.test.ts +++ b/src/integrationTests/autoRefresh.test.ts @@ -33,529 +33,555 @@ afterEach(() => { const getUid2Cookie = mocks.getUid2Cookie; const makeIdentity = mocks.makeIdentityV2; -describe("when auto refreshing a non-expired identity which does not require a refresh", () => { - const originalIdentity = makeIdentity({ - advertising_token: "original_advertising_token", - }); - beforeEach(() => { - getAdvertisingTokenPromise = uid2.getAdvertisingTokenAsync(); - jest.clearAllMocks(); - jest.runOnlyPendingTimers(); - uid2.init({ callback: callback, identity: originalIdentity }); - }); - - test("should invoke the callback", () => { - expect(sdkWindow.crypto).toBeDefined(); - expect(callback).toHaveBeenCalledTimes(1); - }); - test("should not initiate token refresh", () => { - expect(xhrMock.send).not.toHaveBeenCalled(); - }); - test("should set refresh timer", () => { - expect(setTimeout).toHaveBeenCalledTimes(1); - expect(clearTimeout).not.toBeCalled(); - }); - test("should be in available state", () => { - (expect(uid2) as any).toBeInAvailableState(); - }); +let useCookie: boolean | undefined = undefined; - test("getAdvertisingTokenAsync should return current adverstising token", async () => { - expect(await getAdvertisingTokenPromise).toEqual( - originalIdentity.advertising_token - ); - }); -}); - -describe("when auto refreshing a non-expired identity which requires a refresh", () => { - const refreshFrom = Date.now() + 100; - const originalIdentity = makeIdentity({ - advertising_token: "original_advertising_token", - refresh_from: refreshFrom, - }); - const updatedIdentity = makeIdentity({ - advertising_token: "updated_advertising_token", - }); - - beforeEach(() => { - uid2.init({ callback: callback, identity: originalIdentity }); - jest.clearAllMocks(); - jest.setSystemTime(refreshFrom); - jest.runOnlyPendingTimers(); - }); - - test("should not invoke the callback", () => { - expect(callback).not.toHaveBeenCalled(); - }); - test("should initiate token refresh", () => { - expect(xhrMock.send).toHaveBeenCalledTimes(1); +const testCookieAndLocalStorage = (test: () => void, only = false) => { + const describeFn = only ? describe.only : describe; + describeFn('Using default: ', () => { + beforeEach(() => { + useCookie = undefined; + }); + test(); }); - test("should not set refresh timer", () => { - expect(setTimeout).not.toHaveBeenCalled(); - expect(clearTimeout).not.toHaveBeenCalled(); + describeFn('Using cookies ', () => { + beforeEach(() => { + useCookie = true; + }); + test(); }); - test("should be in available state", () => { - (expect(uid2) as any).toBeInAvailableState(); + describeFn('Using local storage ', () => { + beforeEach(() => { + useCookie = false; + }); + test(); }); +}; - describe("when token refresh succeeds", () => { +testCookieAndLocalStorage(() => { + describe("when auto refreshing a non-expired identity which does not require a refresh", () => { + const originalIdentity = makeIdentity({ + advertising_token: "original_advertising_token", + }); beforeEach(() => { getAdvertisingTokenPromise = uid2.getAdvertisingTokenAsync(); - xhrMock.responseText = btoa( - JSON.stringify({ status: "success", body: updatedIdentity }) - ); - xhrMock.onreadystatechange(new Event("")); + jest.clearAllMocks(); + jest.runOnlyPendingTimers(); + uid2.init({ callback: callback, identity: originalIdentity }); }); test("should invoke the callback", () => { - expect(callback).toHaveBeenNthCalledWith( - 1, - expect.objectContaining({ - advertisingToken: updatedIdentity.advertising_token, - advertising_token: updatedIdentity.advertising_token, - status: UID2.IdentityStatus.REFRESHED, - }) - ); + expect(sdkWindow.crypto).toBeDefined(); + expect(callback).toHaveBeenCalledTimes(1); }); - test("should set cookie", () => { - expect(getUid2Cookie().advertising_token).toBe( - updatedIdentity.advertising_token - ); + test("should not initiate token refresh", () => { + expect(xhrMock.send).not.toHaveBeenCalled(); }); test("should set refresh timer", () => { expect(setTimeout).toHaveBeenCalledTimes(1); - expect(clearTimeout).not.toHaveBeenCalled(); + expect(clearTimeout).not.toBeCalled(); }); test("should be in available state", () => { - (expect(uid2) as any).toBeInAvailableState( - updatedIdentity.advertising_token - ); + (expect(uid2) as any).toBeInAvailableState(); }); - test("getAdvertisingTokenAsync should return new advertising token", async () => { + test("getAdvertisingTokenAsync should return current advertising token", async () => { expect(await getAdvertisingTokenPromise).toEqual( - updatedIdentity.advertising_token + originalIdentity.advertising_token ); }); }); - describe("when token refresh returns optout", () => { - let expection: any; - beforeEach(async () => { - try { - getAdvertisingTokenPromise = uid2.getAdvertisingTokenAsync(); - xhrMock.responseText = btoa(JSON.stringify({ status: "optout" })); - xhrMock.onreadystatechange(new Event("")); - await getAdvertisingTokenPromise; - } catch (err) { - expection = err; - } - }); - test("getAdvertisingTokenPromise should reject", () => { - expect(expection).toEqual(new Error("UID2 SDK aborted.")); - }); - test("should invoke the callback", () => { - expect(callback).toHaveBeenNthCalledWith( - 1, - expect.objectContaining({ - advertisingToken: undefined, - advertising_token: undefined, - status: UID2.IdentityStatus.OPTOUT, - }) - ); - }); - test("should clear cookie", () => { - expect(getUid2Cookie()).toBeUndefined(); - }); - test("should not set refresh timer", () => { - expect(setTimeout).not.toHaveBeenCalled(); - expect(clearTimeout).not.toHaveBeenCalled(); + describe("when auto refreshing a non-expired identity which requires a refresh", () => { + const refreshFrom = Date.now() + 100; + const originalIdentity = makeIdentity({ + advertising_token: "original_advertising_token", + refresh_from: refreshFrom, }); - test("should be in unavailable state", () => { - (expect(uid2) as any).toBeInUnavailableState(); + const updatedIdentity = makeIdentity({ + advertising_token: "updated_advertising_token", }); - }); - describe("when token refresh returns refresh token expired", () => { - let expection: any; - beforeEach(async () => { - try { - getAdvertisingTokenPromise = uid2.getAdvertisingTokenAsync(); - xhrMock.responseText = btoa( - JSON.stringify({ status: "expired_token" }) - ); - xhrMock.onreadystatechange(new Event("")); - await getAdvertisingTokenPromise; - } catch (err) { - expection = err; - } - }); - test("getAdvertisingTokenPromise should reject", () => { - expect(expection).toEqual(new Error("UID2 SDK aborted.")); + beforeEach(() => { + uid2.init({ callback: callback, identity: originalIdentity }); + jest.clearAllMocks(); + jest.setSystemTime(refreshFrom); + jest.runOnlyPendingTimers(); }); - test("should invoke the callback", () => { - expect(callback).toHaveBeenNthCalledWith( - 1, - expect.objectContaining({ - advertisingToken: undefined, - advertising_token: undefined, - status: UID2.IdentityStatus.REFRESH_EXPIRED, - }) - ); + + test("should not invoke the callback", () => { + expect(callback).not.toHaveBeenCalled(); }); - test("should clear cookie", () => { - expect(getUid2Cookie()).toBeUndefined(); + test("should initiate token refresh", () => { + expect(xhrMock.send).toHaveBeenCalledTimes(1); }); test("should not set refresh timer", () => { expect(setTimeout).not.toHaveBeenCalled(); expect(clearTimeout).not.toHaveBeenCalled(); }); - test("should be in unavailable state", () => { - (expect(uid2) as any).toBeInUnavailableState(); + test("should be in available state", () => { + (expect(uid2) as any).toBeInAvailableState(); }); - }); - describe("when token refresh returns an error status", () => { - let expection: any; - beforeEach(async () => { - try { + describe("when token refresh succeeds", () => { + beforeEach(() => { getAdvertisingTokenPromise = uid2.getAdvertisingTokenAsync(); - xhrMock.responseText = JSON.stringify({ - status: "error", - body: updatedIdentity, - }); + xhrMock.responseText = btoa( + JSON.stringify({ status: "success", body: updatedIdentity }) + ); xhrMock.onreadystatechange(new Event("")); - await getAdvertisingTokenPromise; - } catch (err) { - expection = err; - } - }); - test("getAdvertisingTokenPromise should return current advertising token", async () => { - expect(await getAdvertisingTokenPromise).toEqual( - originalIdentity.advertising_token - ); - }); + }); + + test("should invoke the callback", () => { + expect(callback).toHaveBeenNthCalledWith( + 1, + expect.objectContaining({ + advertisingToken: updatedIdentity.advertising_token, + advertising_token: updatedIdentity.advertising_token, + status: UID2.IdentityStatus.REFRESHED, + }) + ); + }); + test("should set cookie", () => { + expect(getUid2Cookie().advertising_token).toBe( + updatedIdentity.advertising_token + ); + }); + test("should set refresh timer", () => { + expect(setTimeout).toHaveBeenCalledTimes(1); + expect(clearTimeout).not.toHaveBeenCalled(); + }); + test("should be in available state", () => { + (expect(uid2) as any).toBeInAvailableState( + updatedIdentity.advertising_token + ); + }); - test("should not update cookie", () => { - expect(getUid2Cookie().advertising_token).toBe( - originalIdentity.advertising_token - ); - }); - test("should set refresh timer", () => { - expect(setTimeout).toHaveBeenCalledTimes(1); - expect(clearTimeout).not.toHaveBeenCalled(); - }); - test("should be in available state", () => { - (expect(uid2) as any).toBeInAvailableState( - originalIdentity.advertising_token - ); - }); - }); + test("getAdvertisingTokenAsync should return new advertising token", async () => { + expect(await getAdvertisingTokenPromise).toEqual( + updatedIdentity.advertising_token + ); + }); + }); + + describe("when token refresh returns optout", () => { + let expection: any; + beforeEach(async () => { + try { + getAdvertisingTokenPromise = uid2.getAdvertisingTokenAsync(); + xhrMock.responseText = btoa(JSON.stringify({ status: "optout" })); + xhrMock.onreadystatechange(new Event("")); + await getAdvertisingTokenPromise; + } catch (err) { + expection = err; + } + }); + test("getAdvertisingTokenPromise should reject", () => { + expect(expection).toEqual(new Error("UID2 SDK aborted.")); + }); + test("should invoke the callback", () => { + expect(callback).toHaveBeenNthCalledWith( + 1, + expect.objectContaining({ + advertisingToken: undefined, + advertising_token: undefined, + status: UID2.IdentityStatus.OPTOUT, + }) + ); + }); + test("should clear cookie", () => { + expect(getUid2Cookie()).toBeUndefined(); + }); + test("should not set refresh timer", () => { + expect(setTimeout).not.toHaveBeenCalled(); + expect(clearTimeout).not.toHaveBeenCalled(); + }); + test("should be in unavailable state", () => { + (expect(uid2) as any).toBeInUnavailableState(); + }); + }); + + describe("when token refresh returns refresh token expired", () => { + let expection: any; + beforeEach(async () => { + try { + getAdvertisingTokenPromise = uid2.getAdvertisingTokenAsync(); + xhrMock.responseText = btoa( + JSON.stringify({ status: "expired_token" }) + ); + xhrMock.onreadystatechange(new Event("")); + await getAdvertisingTokenPromise; + } catch (err) { + expection = err; + } + }); + test("getAdvertisingTokenPromise should reject", () => { + expect(expection).toEqual(new Error("UID2 SDK aborted.")); + }); + test("should invoke the callback", () => { + expect(callback).toHaveBeenNthCalledWith( + 1, + expect.objectContaining({ + advertisingToken: undefined, + advertising_token: undefined, + status: UID2.IdentityStatus.REFRESH_EXPIRED, + }) + ); + }); + test("should clear cookie", () => { + expect(getUid2Cookie()).toBeUndefined(); + }); + test("should not set refresh timer", () => { + expect(setTimeout).not.toHaveBeenCalled(); + expect(clearTimeout).not.toHaveBeenCalled(); + }); + test("should be in unavailable state", () => { + (expect(uid2) as any).toBeInUnavailableState(); + }); + }); + + describe("when token refresh returns an error status", () => { + let expection: any; + beforeEach(async () => { + try { + getAdvertisingTokenPromise = uid2.getAdvertisingTokenAsync(); + xhrMock.responseText = JSON.stringify({ + status: "error", + body: updatedIdentity, + }); + xhrMock.onreadystatechange(new Event("")); + await getAdvertisingTokenPromise; + } catch (err) { + expection = err; + } + }); + test("getAdvertisingTokenPromise should return current advertising token", async () => { + expect(await getAdvertisingTokenPromise).toEqual( + originalIdentity.advertising_token + ); + }); - describe("when token refresh fails and current identity expires", () => { - let expection: any; - beforeEach(async () => { - try { + test("should not update cookie", () => { + expect(getUid2Cookie().advertising_token).toBe( + originalIdentity.advertising_token + ); + }); + test("should set refresh timer", () => { + expect(setTimeout).toHaveBeenCalledTimes(1); + expect(clearTimeout).not.toHaveBeenCalled(); + }); + test("should be in available state", () => { + (expect(uid2) as any).toBeInAvailableState( + originalIdentity.advertising_token + ); + }); + }); + + describe("when token refresh fails and current identity expires", () => { + let expection: any; + beforeEach(async () => { + try { + getAdvertisingTokenPromise = uid2.getAdvertisingTokenAsync(); + jest.setSystemTime(originalIdentity.refresh_expires * 1000 + 1); + xhrMock.responseText = JSON.stringify({ status: "error" }); + xhrMock.onreadystatechange(new Event("")); + await getAdvertisingTokenPromise; + } catch (err) { + expection = err; + } + }); + + test("getAdvertisingTokenPromise should reject", () => { + expect(expection).toEqual(new Error("UID2 SDK aborted.")); + }); + + test("should invoke the callback", () => { + expect(callback).toHaveBeenNthCalledWith( + 1, + expect.objectContaining({ + advertisingToken: undefined, + advertising_token: undefined, + status: UID2.IdentityStatus.REFRESH_EXPIRED, + }) + ); + }); + test("should clear cookie", () => { + expect(getUid2Cookie()).toBeUndefined(); + }); + test("should not set refresh timer", () => { + expect(setTimeout).not.toHaveBeenCalled(); + expect(clearTimeout).not.toHaveBeenCalled(); + }); + test("should be in unavailable state", () => { + (expect(uid2) as any).toBeInUnavailableState(); + }); + }); + + describe("when a new token is set using setIdentity", () => { + const manualSetIdentity = makeIdentity({ + advertising_token: "manual_set_advertising_token", + }); + beforeEach(() => { + uid2.setIdentity(manualSetIdentity); getAdvertisingTokenPromise = uid2.getAdvertisingTokenAsync(); - jest.setSystemTime(originalIdentity.refresh_expires * 1000 + 1); - xhrMock.responseText = JSON.stringify({ status: "error" }); - xhrMock.onreadystatechange(new Event("")); - await getAdvertisingTokenPromise; - } catch (err) { - expection = err; - } - }); - - test("getAdvertisingTokenPromise should reject", () => { - expect(expection).toEqual(new Error("UID2 SDK aborted.")); - }); + }); + + test("should abort the refreshing request", () => { + expect(xhrMock.abort).toHaveBeenCalledTimes(1); + }); + + test("should invoke the callback", () => { + expect(callback).toHaveBeenNthCalledWith( + 1, + expect.objectContaining({ + advertisingToken: manualSetIdentity.advertising_token, + advertising_token: manualSetIdentity.advertising_token, + status: UID2.IdentityStatus.REFRESHED, + }) + ); + }); + test("should set cookie", () => { + expect(getUid2Cookie().advertising_token).toBe( + manualSetIdentity.advertising_token + ); + }); + test("should set refresh timer", () => { + expect(setTimeout).toHaveBeenCalledTimes(1); + expect(clearTimeout).not.toHaveBeenCalled(); + }); + test("should be in available state", () => { + (expect(uid2) as any).toBeInAvailableState( + manualSetIdentity.advertising_token + ); + }); - test("should invoke the callback", () => { - expect(callback).toHaveBeenNthCalledWith( - 1, - expect.objectContaining({ - advertisingToken: undefined, - advertising_token: undefined, - status: UID2.IdentityStatus.REFRESH_EXPIRED, - }) - ); - }); - test("should clear cookie", () => { - expect(getUid2Cookie()).toBeUndefined(); - }); - test("should not set refresh timer", () => { - expect(setTimeout).not.toHaveBeenCalled(); - expect(clearTimeout).not.toHaveBeenCalled(); - }); - test("should be in unavailable state", () => { - (expect(uid2) as any).toBeInUnavailableState(); + test("getAdvertisingTokenAsync should return manual set token", async () => { + expect(await getAdvertisingTokenPromise).toEqual( + manualSetIdentity.advertising_token + ); + }); }); }); - describe("when a new token is set using setIdentity", () => { - const manualSetIdentity = makeIdentity({ - advertising_token: "manual_set_advertising_token", + describe("when auto refreshing an expired identity", () => { + const refreshFrom = Date.now() + 100; + const originalIdentity = makeIdentity({ + advertising_token: "original_advertising_token", + identity_expires: refreshFrom, + refresh_from: refreshFrom, }); - beforeEach(() => { - uid2.setIdentity(manualSetIdentity); - getAdvertisingTokenPromise = uid2.getAdvertisingTokenAsync(); + const updatedIdentity = makeIdentity({ + advertising_token: "updated_advertising_token", }); - test("should abort the refreshing request", () => { - expect(xhrMock.abort).toHaveBeenCalledTimes(1); - }); - - test("should invoke the callback", () => { - expect(callback).toHaveBeenNthCalledWith( - 1, - expect.objectContaining({ - advertisingToken: manualSetIdentity.advertising_token, - advertising_token: manualSetIdentity.advertising_token, - status: UID2.IdentityStatus.REFRESHED, - }) - ); - }); - test("should set cookie", () => { - expect(getUid2Cookie().advertising_token).toBe( - manualSetIdentity.advertising_token - ); - }); - test("should set refresh timer", () => { - expect(setTimeout).toHaveBeenCalledTimes(1); - expect(clearTimeout).not.toHaveBeenCalled(); - }); - test("should be in available state", () => { - (expect(uid2) as any).toBeInAvailableState( - manualSetIdentity.advertising_token - ); - }); - - test("getAdvertisingTokenAsync should return manual set token", async () => { - expect(await getAdvertisingTokenPromise).toEqual( - manualSetIdentity.advertising_token - ); - }); - }); -}); - -describe("when auto refreshing an expired identity", () => { - const refreshFrom = Date.now() + 100; - const originalIdentity = makeIdentity({ - advertising_token: "original_advertising_token", - identity_expires: refreshFrom, - refresh_from: refreshFrom, - }); - const updatedIdentity = makeIdentity({ - advertising_token: "updated_advertising_token", - }); - - beforeEach(() => { - uid2.init({ callback: callback, identity: originalIdentity }); - jest.clearAllMocks(); - jest.setSystemTime(refreshFrom); - jest.runOnlyPendingTimers(); - }); - - test("should not invoke the callback", () => { - expect(callback).not.toHaveBeenCalled(); - }); - test("should initiate token refresh", () => { - expect(xhrMock.send).toHaveBeenCalledTimes(1); - }); - test("should not set refresh timer", () => { - expect(setTimeout).not.toHaveBeenCalled(); - expect(clearTimeout).not.toHaveBeenCalled(); - }); - test("should be in available state", () => { - (expect(uid2) as any).toBeInTemporarilyUnavailableState(); - }); - - describe("when token refresh succeeds", () => { beforeEach(() => { - getAdvertisingTokenPromise = uid2.getAdvertisingTokenAsync(); - xhrMock.responseText = btoa( - JSON.stringify({ status: "success", body: updatedIdentity }) - ); - xhrMock.onreadystatechange(new Event("")); - }); - - test("should invoke the callback", () => { - expect(callback).toHaveBeenNthCalledWith( - 1, - expect.objectContaining({ - advertisingToken: updatedIdentity.advertising_token, - advertising_token: updatedIdentity.advertising_token, - status: UID2.IdentityStatus.REFRESHED, - }) - ); - }); - test("should set cookie", () => { - expect(getUid2Cookie().advertising_token).toBe( - updatedIdentity.advertising_token - ); - }); - test("should set refresh timer", () => { - expect(setTimeout).toHaveBeenCalledTimes(1); - expect(clearTimeout).not.toHaveBeenCalled(); - }); - test("should be in available state", () => { - (expect(uid2) as any).toBeInAvailableState( - updatedIdentity.advertising_token - ); - }); - test("getAdvertisingTokenPromise should return new advertising token", async () => { - expect(await getAdvertisingTokenPromise).toEqual( - updatedIdentity.advertising_token - ); + uid2.init({ callback: callback, identity: originalIdentity }); + jest.clearAllMocks(); + jest.setSystemTime(refreshFrom); + jest.runOnlyPendingTimers(); }); - }); - describe("when token refresh returns optout", () => { - let expection: any; - beforeEach(async () => { - try { - getAdvertisingTokenPromise = uid2.getAdvertisingTokenAsync(); - xhrMock.responseText = btoa(JSON.stringify({ status: "optout" })); - xhrMock.onreadystatechange(new Event("")); - await getAdvertisingTokenPromise; - } catch (err) { - expection = err; - } + test("should not invoke the callback", () => { + expect(callback).not.toHaveBeenCalled(); }); - test("getAdvertisingTokenPromise should reject", () => { - expect(expection).toEqual(new Error("UID2 SDK aborted.")); - }); - test("should invoke the callback", () => { - expect(callback).toHaveBeenNthCalledWith( - 1, - expect.objectContaining({ - advertisingToken: undefined, - advertising_token: undefined, - status: UID2.IdentityStatus.OPTOUT, - }) - ); - }); - test("should clear cookie", () => { - expect(getUid2Cookie()).toBeUndefined(); + test("should initiate token refresh", () => { + expect(xhrMock.send).toHaveBeenCalledTimes(1); }); test("should not set refresh timer", () => { expect(setTimeout).not.toHaveBeenCalled(); expect(clearTimeout).not.toHaveBeenCalled(); }); - test("should be in unavailable state", () => { - (expect(uid2) as any).toBeInUnavailableState(); + test("should be in available state", () => { + (expect(uid2) as any).toBeInTemporarilyUnavailableState(); }); - }); - describe("when token refresh returns refresh token expired", () => { - let expection: any; - beforeEach(async () => { - try { + describe("when token refresh succeeds", () => { + beforeEach(() => { getAdvertisingTokenPromise = uid2.getAdvertisingTokenAsync(); xhrMock.responseText = btoa( - JSON.stringify({ status: "expired_token" }) + JSON.stringify({ status: "success", body: updatedIdentity }) ); xhrMock.onreadystatechange(new Event("")); - await getAdvertisingTokenPromise; - } catch (err) { - expection = err; - } - }); - test("getAdvertisingTokenPromise should reject", () => { - expect(expection).toEqual(new Error("UID2 SDK aborted.")); - }); - test("should invoke the callback", () => { - expect(callback).toHaveBeenNthCalledWith( - 1, - expect.objectContaining({ - advertisingToken: undefined, - advertising_token: undefined, - status: UID2.IdentityStatus.REFRESH_EXPIRED, - }) - ); - }); - test("should clear cookie", () => { - expect(getUid2Cookie()).toBeUndefined(); - }); - test("should not set refresh timer", () => { - expect(setTimeout).not.toHaveBeenCalled(); - expect(clearTimeout).not.toHaveBeenCalled(); - }); - test("should be in unavailable state", () => { - (expect(uid2) as any).toBeInUnavailableState(); - }); - }); - - describe("when token refresh returns an error status", () => { - let expection: any; - beforeEach(async () => { - try { - getAdvertisingTokenPromise = uid2.getAdvertisingTokenAsync(); - xhrMock.responseText = JSON.stringify({ - status: "error", - body: updatedIdentity, - }); - xhrMock.onreadystatechange(new Event("")); - await getAdvertisingTokenPromise; - } catch (err) { - expection = err; - } - }); - test("getAdvertisingTokenPromise should reject", () => { - expect(expection).toEqual(new Error("No identity available.")); - }); - test("should not update cookie", () => { - expect(getUid2Cookie().advertising_token).toBe( - originalIdentity.advertising_token - ); - }); - test("should set refresh timer", () => { - expect(setTimeout).toHaveBeenCalledTimes(1); - expect(clearTimeout).not.toHaveBeenCalled(); - }); - test("should be in temporarily unavailable state", () => { - (expect(uid2) as any).toBeInTemporarilyUnavailableState( - originalIdentity.advertising_token - ); - }); - }); - - describe("when token refresh fails and current identity expires", () => { - let expection: any; - beforeEach(async () => { - try { - getAdvertisingTokenPromise = uid2.getAdvertisingTokenAsync(); - jest.setSystemTime(originalIdentity.refresh_expires * 1000 + 1); - xhrMock.responseText = JSON.stringify({ status: "error" }); - xhrMock.onreadystatechange(new Event("")); - await getAdvertisingTokenPromise; - } catch (err) { - expection = err; - } - }); - - test("getAdvertisingTokenPromise should reject", () => { - expect(expection).toEqual(new Error("UID2 SDK aborted.")); - }); - - test("should invoke the callback", () => { - expect(callback).toHaveBeenNthCalledWith( - 1, - expect.objectContaining({ - advertisingToken: undefined, - advertising_token: undefined, - status: UID2.IdentityStatus.REFRESH_EXPIRED, - }) - ); - }); - test("should clear cookie", () => { - expect(getUid2Cookie()).toBeUndefined(); - }); - test("should not set refresh timer", () => { - expect(setTimeout).not.toHaveBeenCalled(); - expect(clearTimeout).not.toHaveBeenCalled(); - }); - test("should be in unavailable state", () => { - (expect(uid2) as any).toBeInUnavailableState(); + }); + + test("should invoke the callback", () => { + expect(callback).toHaveBeenNthCalledWith( + 1, + expect.objectContaining({ + advertisingToken: updatedIdentity.advertising_token, + advertising_token: updatedIdentity.advertising_token, + status: UID2.IdentityStatus.REFRESHED, + }) + ); + }); + test("should set cookie", () => { + expect(getUid2Cookie().advertising_token).toBe( + updatedIdentity.advertising_token + ); + }); + test("should set refresh timer", () => { + expect(setTimeout).toHaveBeenCalledTimes(1); + expect(clearTimeout).not.toHaveBeenCalled(); + }); + test("should be in available state", () => { + (expect(uid2) as any).toBeInAvailableState( + updatedIdentity.advertising_token + ); + }); + test("getAdvertisingTokenPromise should return new advertising token", async () => { + expect(await getAdvertisingTokenPromise).toEqual( + updatedIdentity.advertising_token + ); + }); + }); + + describe("when token refresh returns optout", () => { + let expection: any; + beforeEach(async () => { + try { + getAdvertisingTokenPromise = uid2.getAdvertisingTokenAsync(); + xhrMock.responseText = btoa(JSON.stringify({ status: "optout" })); + xhrMock.onreadystatechange(new Event("")); + await getAdvertisingTokenPromise; + } catch (err) { + expection = err; + } + }); + test("getAdvertisingTokenPromise should reject", () => { + expect(expection).toEqual(new Error("UID2 SDK aborted.")); + }); + test("should invoke the callback", () => { + expect(callback).toHaveBeenNthCalledWith( + 1, + expect.objectContaining({ + advertisingToken: undefined, + advertising_token: undefined, + status: UID2.IdentityStatus.OPTOUT, + }) + ); + }); + test("should clear cookie", () => { + expect(getUid2Cookie()).toBeUndefined(); + }); + test("should not set refresh timer", () => { + expect(setTimeout).not.toHaveBeenCalled(); + expect(clearTimeout).not.toHaveBeenCalled(); + }); + test("should be in unavailable state", () => { + (expect(uid2) as any).toBeInUnavailableState(); + }); + }); + + describe("when token refresh returns refresh token expired", () => { + let expection: any; + beforeEach(async () => { + try { + getAdvertisingTokenPromise = uid2.getAdvertisingTokenAsync(); + xhrMock.responseText = btoa( + JSON.stringify({ status: "expired_token" }) + ); + xhrMock.onreadystatechange(new Event("")); + await getAdvertisingTokenPromise; + } catch (err) { + expection = err; + } + }); + test("getAdvertisingTokenPromise should reject", () => { + expect(expection).toEqual(new Error("UID2 SDK aborted.")); + }); + test("should invoke the callback", () => { + expect(callback).toHaveBeenNthCalledWith( + 1, + expect.objectContaining({ + advertisingToken: undefined, + advertising_token: undefined, + status: UID2.IdentityStatus.REFRESH_EXPIRED, + }) + ); + }); + test("should clear cookie", () => { + expect(getUid2Cookie()).toBeUndefined(); + }); + test("should not set refresh timer", () => { + expect(setTimeout).not.toHaveBeenCalled(); + expect(clearTimeout).not.toHaveBeenCalled(); + }); + test("should be in unavailable state", () => { + (expect(uid2) as any).toBeInUnavailableState(); + }); + }); + + describe("when token refresh returns an error status", () => { + let expection: any; + beforeEach(async () => { + try { + getAdvertisingTokenPromise = uid2.getAdvertisingTokenAsync(); + xhrMock.responseText = JSON.stringify({ + status: "error", + body: updatedIdentity, + }); + xhrMock.onreadystatechange(new Event("")); + await getAdvertisingTokenPromise; + } catch (err) { + expection = err; + } + }); + test("getAdvertisingTokenPromise should reject", () => { + expect(expection).toEqual(new Error("No identity available.")); + }); + test("should not update cookie", () => { + expect(getUid2Cookie().advertising_token).toBe( + originalIdentity.advertising_token + ); + }); + test("should set refresh timer", () => { + expect(setTimeout).toHaveBeenCalledTimes(1); + expect(clearTimeout).not.toHaveBeenCalled(); + }); + test("should be in temporarily unavailable state", () => { + (expect(uid2) as any).toBeInTemporarilyUnavailableState( + originalIdentity.advertising_token + ); + }); + }); + + describe("when token refresh fails and current identity expires", () => { + let expection: any; + beforeEach(async () => { + try { + getAdvertisingTokenPromise = uid2.getAdvertisingTokenAsync(); + jest.setSystemTime(originalIdentity.refresh_expires * 1000 + 1); + xhrMock.responseText = JSON.stringify({ status: "error" }); + xhrMock.onreadystatechange(new Event("")); + await getAdvertisingTokenPromise; + } catch (err) { + expection = err; + } + }); + + test("getAdvertisingTokenPromise should reject", () => { + expect(expection).toEqual(new Error("UID2 SDK aborted.")); + }); + + test("should invoke the callback", () => { + expect(callback).toHaveBeenNthCalledWith( + 1, + expect.objectContaining({ + advertisingToken: undefined, + advertising_token: undefined, + status: UID2.IdentityStatus.REFRESH_EXPIRED, + }) + ); + }); + test("should clear cookie", () => { + expect(getUid2Cookie()).toBeUndefined(); + }); + test("should not set refresh timer", () => { + expect(setTimeout).not.toHaveBeenCalled(); + expect(clearTimeout).not.toHaveBeenCalled(); + }); + test("should be in unavailable state", () => { + (expect(uid2) as any).toBeInUnavailableState(); + }); }); }); }); diff --git a/src/integrationTests/basic.test.ts b/src/integrationTests/basic.test.ts index 6e69fe2..41800c1 100644 --- a/src/integrationTests/basic.test.ts +++ b/src/integrationTests/basic.test.ts @@ -13,6 +13,8 @@ import { sdkWindow, UID2 } from "../uid2Sdk"; let callback: any; let uid2: UID2; let xhrMock: any; +// let _cryptoMock: any; +// let cryptoMock: any; mocks.setupFakeTime(); @@ -21,6 +23,8 @@ beforeEach(() => { uid2 = new UID2(); xhrMock = new mocks.XhrMock(sdkWindow); mocks.setCookieMock(sdkWindow.document); + // _cryptoMock = new mocks.CryptoMock(sdkWindow); + // cryptoMock = new mocks.CryptoMock(sdkWindow); }); afterEach(() => { @@ -29,925 +33,1088 @@ afterEach(() => { const setUid2Cookie = mocks.setUid2Cookie; const getUid2Cookie = mocks.getUid2Cookie; +const removeUid2Cookie = mocks.removeUid2Cookie; +const removeUid2LocalStorage = mocks.removeUid2LocalStorage; +const setUid2LocalStorage = mocks.setUid2LocalStorage; +const getUid2LocalStorage = mocks.getUid2LocalStorage; const makeIdentityV1 = mocks.makeIdentityV1; const makeIdentityV2 = mocks.makeIdentityV2; -describe("When google tag setup is called", () => { - test("should not fail when there is no googletag", () => { - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - sdkWindow.googletag = null; - expect(() => UID2.setupGoogleTag()).not.toThrow(TypeError); - }); - test("should not fail when there is no googletag secureSignalProviders and no uid2SecureSignalProvider", () => { - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - sdkWindow.googletag = { secureSignalProviders: null }; - expect(() => UID2.setupGoogleTag()).not.toThrow(TypeError); - }); +let useCookie: boolean | undefined = undefined; - test("should not fail when there is no uid2SecureSignalProvider", () => { - const mockPush = jest.fn(); - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - sdkWindow.googletag = { secureSignalProviders: { push: mockPush } }; - expect(() => UID2.setupGoogleTag()).not.toThrow(TypeError); - expect(mockPush.mock.calls.length).toBe(0); +const testCookieAndLocalStorage = (test: () => void, only = false) => { + const describeFn = only ? describe.only : describe; + describeFn('Using default: ', () => { + beforeEach(() => { + removeUid2Cookie(); + removeUid2LocalStorage(); + useCookie = undefined; + }); + test(); }); - - test("should push if googletag has secureSignalProviders", () => { - const mockRegister = jest.fn(); - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - sdkWindow.__uid2SecureSignalProvider = { - registerSecureSignalProvider: mockRegister, - }; - UID2.setupGoogleTag(); - expect(mockRegister.mock.calls.length).toBe(1); + describeFn('Using cookies ', () => { + beforeEach(() => { + removeUid2Cookie(); + removeUid2LocalStorage(); + useCookie = true; + }); + test(); }); -}); - -describe("initial state before init() is called", () => { - test("should be in initialising state", () => { - (expect(uid2) as any).toBeInInitialisingState(); + describeFn('Using local storage ', () => { + beforeEach(() => { + removeUid2Cookie(); + removeUid2LocalStorage(); + useCookie = false; + }); + test(); }); +}; - test("getAdvertisingToken should return undefined", () => { - expect(uid2.getAdvertisingToken()).toBeUndefined(); - }); -}); - -describe("when initialising with invalid options", () => { - test("should fail on no opts", () => { - expect(() => (uid2 as any).init()).toThrow(TypeError); - }); - test("should fail on opts not being an object", () => { - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - expect(() => uid2.init(12345)).toThrow(TypeError); - }); - test("should fail on opts being null", () => { - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - expect(() => uid2.init(null)).toThrow(TypeError); - }); - test("should work on no callback provided", () => { - expect(() => uid2.init({})).not.toThrow(TypeError); - }); - test("should fail on callback not being a function", () => { - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - expect(() => uid2.init({ callback: 12345 })).toThrow(TypeError); - }); - test("should fail on refreshRetryPeriod not being a number", () => { - expect(() => +testCookieAndLocalStorage(() => { + describe("When google tag setup is called", () => { + test("should not fail when there is no googletag", () => { // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore - uid2.init({ callback: () => {}, refreshRetryPeriod: "abc" }) - ).toThrow(TypeError); - }); - test("should fail on refreshRetryPeriod being less than 1 second", () => { - expect(() => - uid2.init({ callback: () => {}, refreshRetryPeriod: 1 }) - ).toThrow(RangeError); - }); -}); - -test("init() should fail if called multiple times", () => { - uid2.init({ callback: () => {} }); - expect(() => uid2.init({ callback: () => {} })).toThrow(); -}); - -describe("when initialised without identity", () => { - describe("when uid2 cookie is not available", () => { - beforeEach(() => { - uid2.init({ callback: callback }); - }); - - test("should invoke the callback", () => { - expect(callback).toHaveBeenNthCalledWith( - 1, - expect.objectContaining({ - advertisingToken: undefined, - advertising_token: undefined, - status: UID2.IdentityStatus.NO_IDENTITY, - }) - ); + sdkWindow.googletag = null; + expect(() => UID2.setupGoogleTag()).not.toThrow(TypeError); }); - test("should not set cookie", () => { - expect(getUid2Cookie()).toBeUndefined(); - }); - test("should not set refresh timer", () => { - expect(setTimeout).not.toHaveBeenCalled(); - expect(clearTimeout).not.toHaveBeenCalled(); - }); - test("should be in unavailable state", () => { - (expect(uid2) as any).toBeInUnavailableState(); + test("should not fail when there is no googletag secureSignalProviders and no uid2SecureSignalProvider", () => { + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + sdkWindow.googletag = { secureSignalProviders: null }; + expect(() => UID2.setupGoogleTag()).not.toThrow(TypeError); }); - }); - describe("when uid2 cookie with invalid JSON is available", () => { - beforeEach(() => { - setUid2Cookie({}); - uid2.init({ callback: callback }); + test("should not fail when there is no uid2SecureSignalProvider", () => { + const mockPush = jest.fn(); + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + sdkWindow.googletag = { secureSignalProviders: { push: mockPush } }; + expect(() => UID2.setupGoogleTag()).not.toThrow(TypeError); + expect(mockPush.mock.calls.length).toBe(0); }); - test("should invoke the callback", () => { - expect(callback).toHaveBeenNthCalledWith( - 1, - expect.objectContaining({ - advertisingToken: undefined, - advertising_token: undefined, - status: UID2.IdentityStatus.NO_IDENTITY, - }) - ); - }); - test("should clear cookie", () => { - expect(getUid2Cookie()).toBeUndefined(); - }); - test("should not set refresh timer", () => { - expect(setTimeout).not.toHaveBeenCalled(); - expect(clearTimeout).not.toHaveBeenCalled(); - }); - test("should be in unavailable state", () => { - (expect(uid2) as any).toBeInUnavailableState(); + test("should push if googletag has secureSignalProviders", () => { + const mockRegister = jest.fn(); + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + sdkWindow.__uid2SecureSignalProvider = { + registerSecureSignalProvider: mockRegister, + }; + UID2.setupGoogleTag(); + expect(mockRegister.mock.calls.length).toBe(1); }); }); - describe("when uid2 cookie with up-to-date identity is available v2", () => { - const identity = makeIdentityV2(); - - beforeEach(() => { - setUid2Cookie(identity); - uid2.init({ callback: callback }); + describe("initial state before init() is called", () => { + test("should be in initialising state", () => { + (expect(uid2) as any).toBeInInitialisingState(); }); - test("should invoke the callback", () => { - expect(callback).toHaveBeenNthCalledWith( - 1, - expect.objectContaining({ - advertisingToken: identity.advertising_token, - advertising_token: identity.advertising_token, - status: UID2.IdentityStatus.ESTABLISHED, - }) - ); - }); - test("should set cookie", () => { - expect(getUid2Cookie().advertising_token).toBe( - identity.advertising_token - ); - }); - test("should set refresh timer", () => { - expect(setTimeout).toHaveBeenCalledTimes(1); - expect(clearTimeout).not.toHaveBeenCalled(); - }); - test("should be in available state", () => { - (expect(uid2) as any).toBeInAvailableState(identity.advertising_token); + test("getAdvertisingToken should return undefined", () => { + expect(uid2.getAdvertisingToken()).toBeUndefined(); }); }); - describe("when uid2 cookie with expired refresh is available", () => { - const identity = makeIdentityV2({ - refresh_expires: Date.now() - 100000, + describe("when initialising with invalid options", () => { + test("should fail on no opts", () => { + expect(() => (uid2 as any).init()).toThrow(TypeError); }); - - beforeEach(() => { - setUid2Cookie(identity); - uid2.init({ callback: callback }); + test("should fail on opts not being an object", () => { + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + expect(() => uid2.init(12345)).toThrow(TypeError); }); - - test("should invoke the callback", () => { - expect(callback).toHaveBeenNthCalledWith( - 1, - expect.objectContaining({ - advertisingToken: undefined, - advertising_token: undefined, - status: UID2.IdentityStatus.REFRESH_EXPIRED, - }) - ); + test("should fail on opts being null", () => { + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + expect(() => uid2.init(null)).toThrow(TypeError); }); - test("should clear cookie", () => { - expect(getUid2Cookie()).toBeUndefined(); + test("should work on no callback provided", () => { + expect(() => uid2.init({})).not.toThrow(TypeError); }); - test("should not set refresh timer", () => { - expect(setTimeout).not.toHaveBeenCalled(); - expect(clearTimeout).not.toHaveBeenCalled(); + test("should fail on callback not being a function", () => { + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + expect(() => uid2.init({ callback: 12345 })).toThrow(TypeError); }); - test("should be in unavailable state", () => { - (expect(uid2) as any).toBeInUnavailableState(); + test("should fail on refreshRetryPeriod not being a number", () => { + expect(() => + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + uid2.init({ callback: () => { }, refreshRetryPeriod: "abc" }) + ).toThrow(TypeError); + }); + test("should fail on refreshRetryPeriod being less than 1 second", () => { + expect(() => + uid2.init({ callback: () => { }, refreshRetryPeriod: 1 }) + ).toThrow(RangeError); }); }); - describe("when uid2 cookie with valid but refreshable identity is available", () => { - const identity = makeIdentityV2({ - refresh_from: Date.now() - 100000, - }); + test("init() should fail if called multiple times", () => { + uid2.init({ callback: () => { } }); + expect(() => uid2.init({ callback: () => { } })).toThrow(); + }); - beforeEach(() => { - setUid2Cookie(identity); - uid2.init({ callback: callback }); - }); + describe("when initialised without identity", () => { + describe("when uid2 cookie is not available", () => { + beforeEach(() => { + removeUid2Cookie(); + removeUid2LocalStorage(); + uid2.init({ callback: callback, useCookie: useCookie }); + }); - test("should initiate token refresh", () => { - expect(xhrMock.send).toHaveBeenCalledTimes(1); - }); - test("should not set refresh timer", () => { - expect(setTimeout).not.toHaveBeenCalled(); - expect(clearTimeout).not.toHaveBeenCalled(); - }); - test("should be in available state", () => { - (expect(uid2) as any).toBeInAvailableState(); + // afterEach(() => { + // removeUid2Cookie(); + // removeUid2LocalStorage(); + // }) + + test("should invoke the callback", () => { + expect(callback).toHaveBeenNthCalledWith( + 1, + expect.objectContaining({ + advertisingToken: undefined, + advertising_token: undefined, + status: UID2.IdentityStatus.NO_IDENTITY, + }) + ); + }); + test("should not set cookie", () => { + expect(getUid2Cookie()).toBeUndefined(); + }); + test("should not set refresh timer", () => { + expect(setTimeout).not.toHaveBeenCalled(); + expect(clearTimeout).not.toHaveBeenCalled(); + }); + test("should be in unavailable state", () => { + (expect(uid2) as any).toBeInUnavailableState(); + }); }); - }); - describe("when uid2 v2 cookie with expired but refreshable identity is available", () => { - const identity = makeIdentityV2({ - identity_expires: Date.now() - 100000, - refresh_from: Date.now() - 100000, - }); + describe("when uid2 cookie with invalid JSON is available", () => { + beforeEach(() => { + setUid2Cookie({}); + uid2.init({ callback: callback, useCookie: useCookie }); + }); - beforeEach(() => { - setUid2Cookie(identity); - uid2.init({ callback: callback }); + test("should invoke the callback", () => { + expect(callback).toHaveBeenNthCalledWith( + 1, + expect.objectContaining({ + advertisingToken: undefined, + advertising_token: undefined, + status: UID2.IdentityStatus.NO_IDENTITY, + }) + ); + }); + test("should clear cookie", () => { + expect(getUid2Cookie()).toBeUndefined(); + }); + test("should not set refresh timer", () => { + expect(setTimeout).not.toHaveBeenCalled(); + expect(clearTimeout).not.toHaveBeenCalled(); + }); + test("should be in unavailable state", () => { + (expect(uid2) as any).toBeInUnavailableState(); + }); }); - test("should initiate token refresh", () => { - const cryptoMock = new mocks.CryptoMock(sdkWindow); - expect(xhrMock.send).toHaveBeenCalledTimes(1); - const url = "https://prod.uidapi.com/v2/token/refresh"; - expect(xhrMock.open).toHaveBeenLastCalledWith("POST", url, true); - expect(xhrMock.send).toHaveBeenLastCalledWith(identity.refresh_token); - xhrMock.onreadystatechange(); - expect(cryptoMock.subtle.importKey).toHaveBeenCalled(); - }); + describe("when uid2 cookie with up-to-date identity is available v2", () => { + const identity = makeIdentityV2(); - test("should not set refresh timer", () => { - expect(setTimeout).not.toHaveBeenCalled(); - expect(clearTimeout).not.toHaveBeenCalled(); - }); - test("should be in initialising state", () => { - (expect(uid2) as any).toBeInTemporarilyUnavailableState(); - }); - }); - describe("when uid2 v1 cookie with expired but refreshable identity is available", () => { - const identity = makeIdentityV1({ - identity_expires: Date.now() - 100000, - refresh_from: Date.now() - 100000, - }); + beforeEach(() => { + setUid2Cookie(identity); + uid2.init({ callback: callback, useCookie: useCookie }); + }); - beforeEach(() => { - setUid2Cookie(identity); - uid2.init({ callback: callback }); + test("should invoke the callback", () => { + expect(callback).toHaveBeenNthCalledWith( + 1, + expect.objectContaining({ + advertisingToken: identity.advertising_token, + advertising_token: identity.advertising_token, + status: UID2.IdentityStatus.ESTABLISHED, + }) + ); + }); + test("should set value", () => { + if (useCookie) { + expect(getUid2Cookie().advertising_token).toBe(identity.advertising_token); + } else { + expect(getUid2LocalStorage().advertising_token).toBe(identity.advertising_token); + } + }); + test("should set refresh timer", () => { + expect(setTimeout).toHaveBeenCalledTimes(1); + expect(clearTimeout).not.toHaveBeenCalled(); + }); + test("should be in available state", () => { + (expect(uid2) as any).toBeInAvailableState(identity.advertising_token); + }); }); - test("should initiate token refresh", () => { - const cryptoMock = new mocks.CryptoMock(sdkWindow); - expect(xhrMock.send).toHaveBeenCalledTimes(1); - const url = "https://prod.uidapi.com/v2/token/refresh"; - expect(xhrMock.open).toHaveBeenLastCalledWith("POST", url, true); - expect(xhrMock.send).toHaveBeenLastCalledWith(identity.refresh_token); - xhrMock.onreadystatechange(); - expect(cryptoMock.subtle.importKey).toHaveBeenCalledTimes(0); - }); - }); -}); + describe("when uid2 cookie with expired refresh is available", () => { + const identity = makeIdentityV2({ + refresh_expires: Date.now() - 100000, + }); -describe("when initialised with specific identity", () => { - describe("when invalid identity is supplied", () => { - beforeEach(() => { - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - uid2.init({ callback: callback, identity: {} }); - }); + beforeEach(() => { + removeUid2Cookie(); + removeUid2LocalStorage(); + setUid2Cookie(identity); + uid2.init({ callback: callback, useCookie: useCookie }); + }); - test("should invoke the callback", () => { - expect(callback).toHaveBeenNthCalledWith( - 1, - expect.objectContaining({ - advertisingToken: undefined, - advertising_token: undefined, - status: UID2.IdentityStatus.INVALID, - }) - ); - }); - test("should clear cookie", () => { - expect(getUid2Cookie()).toBeUndefined(); - }); - test("should not set refresh timer", () => { - expect(setTimeout).not.toHaveBeenCalled(); - expect(clearTimeout).not.toHaveBeenCalled(); - }); - test("should be in unavailable state", () => { - (expect(uid2) as any).toBeInUnavailableState(); + // afterEach(() => { + // removeUid2Cookie(); + // removeUid2LocalStorage(); + // }) + + test("should invoke the callback", () => { + expect(callback).toHaveBeenNthCalledWith( + 1, + expect.objectContaining({ + advertisingToken: undefined, + advertising_token: undefined, + status: UID2.IdentityStatus.REFRESH_EXPIRED, + }) + ); + }); + test("should clear cookie", () => { + expect(getUid2Cookie()).toBeUndefined(); + }); + test("should not set refresh timer", () => { + expect(setTimeout).not.toHaveBeenCalled(); + expect(clearTimeout).not.toHaveBeenCalled(); + }); + test("should be in unavailable state", () => { + (expect(uid2) as any).toBeInUnavailableState(); + }); }); - }); - describe("when valid v2 identity is supplied", () => { - const identity = makeIdentityV2(); + describe("when uid2 cookie with valid but refreshable identity is available", () => { + const identity = makeIdentityV2({ + refresh_from: Date.now() - 100000, + }); - beforeEach(() => { - uid2.init({ callback: callback, identity: identity }); - }); + beforeEach(() => { + setUid2Cookie(identity); + uid2.init({ callback: callback, useCookie: useCookie }); + }); - test("should invoke the callback", () => { - expect(callback).toHaveBeenNthCalledWith( - 1, - expect.objectContaining({ - advertisingToken: identity.advertising_token, - advertising_token: identity.advertising_token, - status: UID2.IdentityStatus.ESTABLISHED, - }) - ); - }); - test("should set cookie", () => { - expect(getUid2Cookie().advertising_token).toBe( - identity.advertising_token - ); + test("should initiate token refresh", () => { + expect(xhrMock.send).toHaveBeenCalledTimes(1); + }); + test("should not set refresh timer", () => { + expect(setTimeout).not.toHaveBeenCalled(); + expect(clearTimeout).not.toHaveBeenCalled(); + }); + test("should be in available state", () => { + (expect(uid2) as any).toBeInAvailableState(); + }); }); - test("should set refresh timer", () => { - expect(setTimeout).toHaveBeenCalledTimes(1); - expect(clearTimeout).not.toHaveBeenCalled(); + + describe("when uid2 v2 cookie with expired but refreshable identity is available", () => { + const identity = makeIdentityV2({ + identity_expires: Date.now() - 100000, + refresh_from: Date.now() - 100000, + }); + // let _cryptoMock: any; + let cryptoMock: any; + + // const cryptoMock = new mocks.CryptoMock(sdkWindow); + + beforeEach(() => { + xhrMock.open.mockClear(); + xhrMock.send.mockClear(); + cryptoMock = new mocks.CryptoMock(sdkWindow); + // _cryptoMock.subtle.importKey.mockClear(); + removeUid2Cookie(); + removeUid2LocalStorage(); + setUid2Cookie(identity); + uid2.init({ callback: callback, useCookie: useCookie }); + }); + + afterEach(() => { + removeUid2Cookie(); + removeUid2LocalStorage(); + xhrMock.open.mockClear(); + xhrMock.send.mockClear(); + // _cryptoMock.subtle.importKey.mockClear(); + cryptoMock.subtle.importKey.mockClear(); + // xhrMock.onreadystatechange = null; + }); + + // this test is only passing on first go + test("should initiate token refresh", () => { + // const cryptoMock = new mocks.CryptoMock(sdkWindow); + expect(xhrMock.send).toHaveBeenCalledTimes(1); + const url = "https://prod.uidapi.com/v2/token/refresh"; + expect(xhrMock.open).toHaveBeenLastCalledWith("POST", url, true); + expect(xhrMock.send).toHaveBeenLastCalledWith(identity.refresh_token); + xhrMock.onreadystatechange(); + expect(cryptoMock.subtle.importKey).toHaveBeenCalled(); + }); + + test("should not set refresh timer", () => { + expect(setTimeout).not.toHaveBeenCalled(); + expect(clearTimeout).not.toHaveBeenCalled(); + }); + test("should be in initialising state", () => { + (expect(uid2) as any).toBeInTemporarilyUnavailableState(); + }); }); - test("should be in available state", () => { - (expect(uid2) as any).toBeInAvailableState(identity.advertising_token); + describe("when uid2 v1 cookie with expired but refreshable identity is available", () => { + const identity = makeIdentityV1({ + identity_expires: Date.now() - 100000, + refresh_from: Date.now() - 100000, + }); + + beforeEach(() => { + removeUid2Cookie(); + removeUid2LocalStorage(); + setUid2Cookie(identity); + uid2.init({ callback: callback, useCookie: useCookie }); + }); + + test("should initiate token refresh", () => { + const cryptoMock = new mocks.CryptoMock(sdkWindow); + expect(xhrMock.send).toHaveBeenCalledTimes(1); + const url = "https://prod.uidapi.com/v2/token/refresh"; + expect(xhrMock.open).toHaveBeenLastCalledWith("POST", url, true); + expect(xhrMock.send).toHaveBeenLastCalledWith(identity.refresh_token); + xhrMock.onreadystatechange(); + expect(cryptoMock.subtle.importKey).toHaveBeenCalledTimes(0); + }); }); }); - describe("when valid identity is supplied and cookie is available", () => { - const initIdentity = makeIdentityV2({ - advertising_token: "init_advertising_token", - }); - const cookieIdentity = makeIdentityV2({ - advertising_token: "cookie_advertising_token", - }); + describe("when initialised with specific identity", () => { + describe("when invalid identity is supplied", () => { + beforeEach(() => { + removeUid2Cookie(); + removeUid2LocalStorage(); + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + uid2.init({ callback: callback, identity: {}, useCookie: useCookie }); + }); - beforeEach(() => { - setUid2Cookie(cookieIdentity); - uid2.init({ callback: callback, identity: initIdentity }); - }); - - test("should invoke the callback", () => { - expect(callback).toHaveBeenNthCalledWith( - 1, - expect.objectContaining({ - advertisingToken: initIdentity.advertising_token, - advertising_token: initIdentity.advertising_token, - status: UID2.IdentityStatus.ESTABLISHED, - }) - ); - }); - test("should set cookie", () => { - expect(getUid2Cookie().advertising_token).toBe( - initIdentity.advertising_token - ); - }); - test("should set refresh timer", () => { - expect(setTimeout).toHaveBeenCalledTimes(1); - expect(clearTimeout).not.toHaveBeenCalled(); - }); - test("should be in available state", () => { - (expect(uid2) as any).toBeInAvailableState( - initIdentity.advertising_token - ); + test("should invoke the callback", () => { + expect(callback).toHaveBeenNthCalledWith( + 1, + expect.objectContaining({ + advertisingToken: undefined, + advertising_token: undefined, + status: UID2.IdentityStatus.INVALID, + }) + ); + }); + test("should clear cookie", () => { + expect(getUid2Cookie()).toBeUndefined(); + }); + test("should not set refresh timer", () => { + expect(setTimeout).not.toHaveBeenCalled(); + expect(clearTimeout).not.toHaveBeenCalled(); + }); + test("should be in unavailable state", () => { + (expect(uid2) as any).toBeInUnavailableState(); + }); }); - }); -}); -describe("when still valid identity is refreshed on init", () => { - const originalIdentity = makeIdentityV2({ - advertising_token: "original_advertising_token", - refresh_from: Date.now() - 100000, - }); - const updatedIdentity = makeIdentityV2({ - advertising_token: "updated_advertising_token", - }); + describe("when valid v2 identity is supplied and using cookie", () => { + const identity = makeIdentityV2(); - beforeEach(() => { - uid2.init({ callback: callback, identity: originalIdentity }); - }); + beforeEach(() => { + removeUid2Cookie(); + removeUid2LocalStorage(); + uid2.init({ callback: callback, identity: identity, useCookie: useCookie }); + }); - describe("when token refresh succeeds", () => { - beforeEach(() => { - xhrMock.responseText = btoa( - JSON.stringify({ status: "success", body: updatedIdentity }) - ); - xhrMock.onreadystatechange(new Event("")); - }); - - test("should invoke the callback", () => { - expect(callback).toHaveBeenLastCalledWith( - expect.objectContaining({ - advertisingToken: updatedIdentity.advertising_token, - advertising_token: updatedIdentity.advertising_token, - status: UID2.IdentityStatus.REFRESHED, - }) - ); - }); - test("should set cookie", () => { - expect(getUid2Cookie().advertising_token).toBe( - updatedIdentity.advertising_token - ); - }); - test("should set refresh timer", () => { - expect(setTimeout).toHaveBeenCalledTimes(1); - expect(clearTimeout).not.toHaveBeenCalled(); + test("should invoke the callback", () => { + expect(callback).toHaveBeenNthCalledWith( + 1, + expect.objectContaining({ + advertisingToken: identity.advertising_token, + advertising_token: identity.advertising_token, + status: UID2.IdentityStatus.ESTABLISHED, + }) + ); + }); + test("should set value", () => { + if (useCookie) { + expect(getUid2Cookie().advertising_token).toBe( + identity.advertising_token + ); + } + else { + expect(getUid2LocalStorage().advertising_token).toBe( + identity.advertising_token + ); + } + }); + test("should set refresh timer", () => { + expect(setTimeout).toHaveBeenCalledTimes(1); + expect(clearTimeout).not.toHaveBeenCalled(); + }); + test("should be in available state", () => { + (expect(uid2) as any).toBeInAvailableState(identity.advertising_token); + }); }); - test("should be in available state", () => { - (expect(uid2) as any).toBeInAvailableState( - updatedIdentity.advertising_token - ); + + describe("when valid identity is supplied and cookie is available", () => { + const initIdentity = makeIdentityV2({ + advertising_token: "init_advertising_token", + }); + const cookieIdentity = makeIdentityV2({ + advertising_token: "cookie_advertising_token", + }); + + beforeEach(() => { + removeUid2Cookie(); + removeUid2LocalStorage(); + setUid2Cookie(cookieIdentity); + uid2.init({ callback: callback, identity: initIdentity, useCookie: useCookie }); + }); + + test("should invoke the callback", () => { + expect(callback).toHaveBeenNthCalledWith( + 1, + expect.objectContaining({ + advertisingToken: initIdentity.advertising_token, + advertising_token: initIdentity.advertising_token, + status: UID2.IdentityStatus.ESTABLISHED, + }) + ); + }); + test("should set value", () => { + if (useCookie) { + expect(getUid2Cookie().advertising_token).toBe( + initIdentity.advertising_token + ); + } + else { + expect(getUid2LocalStorage().advertising_token).toBe( + initIdentity.advertising_token + ); + } + }); + test("should set refresh timer", () => { + expect(setTimeout).toHaveBeenCalledTimes(1); + expect(clearTimeout).not.toHaveBeenCalled(); + }); + test("should be in available state", () => { + (expect(uid2) as any).toBeInAvailableState( + initIdentity.advertising_token + ); + }); }); }); - describe("when token refresh returns invalid response", () => { - beforeEach(() => { - xhrMock.responseText = "abc"; - xhrMock.onreadystatechange(new Event("")); - }); - - test("should invoke the callback", () => { - expect(callback).toHaveBeenNthCalledWith( - 1, - expect.objectContaining({ - advertisingToken: originalIdentity.advertising_token, - advertising_token: originalIdentity.advertising_token, - status: UID2.IdentityStatus.ESTABLISHED, - }) - ); - }); - test("should set cookie", () => { - expect(getUid2Cookie().advertising_token).toBe( - originalIdentity.advertising_token - ); - }); - test("should set refresh timer", () => { - expect(setTimeout).toHaveBeenCalledTimes(1); - expect(clearTimeout).not.toHaveBeenCalled(); + describe("when still valid identity is refreshed on init", () => { + const originalIdentity = makeIdentityV2({ + advertising_token: "original_advertising_token", + refresh_from: Date.now() - 100000, }); - test("should be in available state", () => { - (expect(uid2) as any).toBeInAvailableState( - originalIdentity.advertising_token - ); + const updatedIdentity = makeIdentityV2({ + advertising_token: "updated_advertising_token", }); - }); - describe("when token refresh returns optout", () => { beforeEach(() => { - xhrMock.responseText = btoa(JSON.stringify({ status: "optout" })); - xhrMock.onreadystatechange(new Event("")); + removeUid2Cookie(); + removeUid2LocalStorage(); + uid2.init({ callback: callback, identity: originalIdentity, useCookie: useCookie }); }); - test("should invoke the callback", () => { - expect(callback).toHaveBeenLastCalledWith( - expect.objectContaining({ - advertisingToken: undefined, - advertising_token: undefined, - status: UID2.IdentityStatus.OPTOUT, - }) - ); - }); - test("should not set cookie", () => { - expect(getUid2Cookie()).toBeUndefined(); - }); - test("should not set refresh timer", () => { - expect(setTimeout).not.toHaveBeenCalled(); - expect(clearTimeout).not.toHaveBeenCalled(); - }); - test("should be in unavailable state", () => { - (expect(uid2) as any).toBeInUnavailableState(); - }); - }); + describe("when token refresh succeeds", () => { + beforeEach(() => { + xhrMock.responseText = btoa( + JSON.stringify({ status: "success", body: updatedIdentity }) + ); + xhrMock.onreadystatechange(new Event("")); + }); - describe("when token refresh returns expired token", () => { - beforeEach(() => { - xhrMock.responseText = JSON.stringify({ status: "expired_token" }); - xhrMock.status = 400; - xhrMock.onreadystatechange(new Event("")); + // afterEach(() => { + // removeUid2Cookie(); + // removeUid2LocalStorage(); + // }); + + test("should invoke the callback", () => { + expect(callback).toHaveBeenLastCalledWith( + expect.objectContaining({ + advertisingToken: updatedIdentity.advertising_token, + advertising_token: updatedIdentity.advertising_token, + status: UID2.IdentityStatus.REFRESHED, + }) + ); + }); + test("should set value", () => { + if (useCookie) { + expect(getUid2Cookie().advertising_token).toBe( + updatedIdentity.advertising_token + ); + } + else { + expect(getUid2LocalStorage().advertising_token).toBe( + updatedIdentity.advertising_token + ); + } + }); + test("should set refresh timer", () => { + expect(setTimeout).toHaveBeenCalledTimes(1); + expect(clearTimeout).not.toHaveBeenCalled(); + }); + test("should be in available state", () => { + (expect(uid2) as any).toBeInAvailableState( + updatedIdentity.advertising_token + ); + }); }); - test("should invoke the callback", () => { - expect(callback).toHaveBeenLastCalledWith( - expect.objectContaining({ - advertisingToken: undefined, - advertising_token: undefined, - status: UID2.IdentityStatus.REFRESH_EXPIRED, - }) - ); - }); - test("should not set cookie", () => { - expect(getUid2Cookie()).toBeUndefined(); - }); - test("should not set refresh timer", () => { - expect(setTimeout).not.toHaveBeenCalled(); - expect(clearTimeout).not.toHaveBeenCalled(); - }); - test("should be in unavailable state", () => { - (expect(uid2) as any).toBeInUnavailableState(); - }); - }); + describe("when token refresh returns invalid response", () => { + beforeEach(() => { + // removeUid2Cookie(); + // removeUid2LocalStorage(); + xhrMock.responseText = "abc"; + xhrMock.onreadystatechange(new Event("")); + }); - describe("when token refresh returns an error status", () => { - beforeEach(() => { - xhrMock.responseText = JSON.stringify({ - status: "error", - body: updatedIdentity, + test("should invoke the callback", () => { + expect(callback).toHaveBeenNthCalledWith( + 1, + expect.objectContaining({ + advertisingToken: originalIdentity.advertising_token, + advertising_token: originalIdentity.advertising_token, + status: UID2.IdentityStatus.ESTABLISHED, + }) + ); + }); + test("should set value", () => { + if (useCookie) { + expect(getUid2Cookie().advertising_token).toBe( + originalIdentity.advertising_token + ); + } + else { + expect(getUid2LocalStorage().advertising_token).toBe( + originalIdentity.advertising_token + ); + } + }); + test("should set refresh timer", () => { + expect(setTimeout).toHaveBeenCalledTimes(1); + expect(clearTimeout).not.toHaveBeenCalled(); + }); + test("should be in available state", () => { + (expect(uid2) as any).toBeInAvailableState( + originalIdentity.advertising_token + ); }); - xhrMock.onreadystatechange(new Event("")); }); - test("should invoke the callback", () => { - expect(callback).toHaveBeenNthCalledWith( - 1, - expect.objectContaining({ - advertisingToken: originalIdentity.advertising_token, - advertising_token: originalIdentity.advertising_token, - status: UID2.IdentityStatus.ESTABLISHED, - }) - ); - }); - test("should set cookie", () => { - expect(getUid2Cookie().advertising_token).toBe( - originalIdentity.advertising_token - ); + describe("when token refresh returns optout", () => { + beforeEach(() => { + xhrMock.responseText = btoa(JSON.stringify({ status: "optout" })); + xhrMock.onreadystatechange(new Event("")); + }); + + test("should invoke the callback", () => { + expect(callback).toHaveBeenLastCalledWith( + expect.objectContaining({ + advertisingToken: undefined, + advertising_token: undefined, + status: UID2.IdentityStatus.OPTOUT, + }) + ); + }); + test("should not set cookie", () => { + expect(getUid2Cookie()).toBeUndefined(); + }); + test("should not set refresh timer", () => { + expect(setTimeout).not.toHaveBeenCalled(); + expect(clearTimeout).not.toHaveBeenCalled(); + }); + test("should be in unavailable state", () => { + (expect(uid2) as any).toBeInUnavailableState(); + }); }); - test("should set refresh timer", () => { - expect(setTimeout).toHaveBeenCalledTimes(1); - expect(clearTimeout).not.toHaveBeenCalled(); + + describe("when token refresh returns expired token", () => { + beforeEach(() => { + xhrMock.responseText = JSON.stringify({ status: "expired_token" }); + xhrMock.status = 400; + xhrMock.onreadystatechange(new Event("")); + }); + + test("should invoke the callback", () => { + expect(callback).toHaveBeenLastCalledWith( + expect.objectContaining({ + advertisingToken: undefined, + advertising_token: undefined, + status: UID2.IdentityStatus.REFRESH_EXPIRED, + }) + ); + }); + test("should not set cookie", () => { + expect(getUid2Cookie()).toBeUndefined(); + }); + test("should not set refresh timer", () => { + expect(setTimeout).not.toHaveBeenCalled(); + expect(clearTimeout).not.toHaveBeenCalled(); + }); + test("should be in unavailable state", () => { + (expect(uid2) as any).toBeInUnavailableState(); + }); }); - test("should be in available state", () => { - (expect(uid2) as any).toBeInAvailableState( - originalIdentity.advertising_token - ); + + describe("when token refresh returns an error status", () => { + beforeEach(() => { + xhrMock.responseText = JSON.stringify({ + status: "error", + body: updatedIdentity, + }); + xhrMock.onreadystatechange(new Event("")); + }); + + test("should invoke the callback", () => { + expect(callback).toHaveBeenNthCalledWith( + 1, + expect.objectContaining({ + advertisingToken: originalIdentity.advertising_token, + advertising_token: originalIdentity.advertising_token, + status: UID2.IdentityStatus.ESTABLISHED, + }) + ); + }); + test("should set value", () => { + if (useCookie) { + expect(getUid2Cookie().advertising_token).toBe( + originalIdentity.advertising_token + ); + } + else { + expect(getUid2LocalStorage().advertising_token).toBe( + originalIdentity.advertising_token + ); + } + }); + test("should set refresh timer", () => { + expect(setTimeout).toHaveBeenCalledTimes(1); + expect(clearTimeout).not.toHaveBeenCalled(); + }); + test("should be in available state", () => { + (expect(uid2) as any).toBeInAvailableState( + originalIdentity.advertising_token + ); + }); }); - }); - describe("when token refresh returns no body", () => { - beforeEach(() => { - xhrMock.responseText = JSON.stringify({ status: "success" }); - xhrMock.onreadystatechange(new Event("")); - }); - - test("should invoke the callback", () => { - expect(callback).toHaveBeenNthCalledWith( - 1, - expect.objectContaining({ - advertisingToken: originalIdentity.advertising_token, - advertising_token: originalIdentity.advertising_token, - status: UID2.IdentityStatus.ESTABLISHED, - }) - ); - }); - test("should set cookie", () => { - expect(getUid2Cookie().advertising_token).toBe( - originalIdentity.advertising_token - ); - }); - test("should set refresh timer", () => { - expect(setTimeout).toHaveBeenCalledTimes(1); - expect(clearTimeout).not.toHaveBeenCalled(); + describe("when token refresh returns no body", () => { + beforeEach(() => { + xhrMock.responseText = JSON.stringify({ status: "success" }); + xhrMock.onreadystatechange(new Event("")); + }); + + test("should invoke the callback", () => { + expect(callback).toHaveBeenNthCalledWith( + 1, + expect.objectContaining({ + advertisingToken: originalIdentity.advertising_token, + advertising_token: originalIdentity.advertising_token, + status: UID2.IdentityStatus.ESTABLISHED, + }) + ); + }); + test("should set value", () => { + if (useCookie) { + expect(getUid2Cookie().advertising_token).toBe( + originalIdentity.advertising_token + ); + } + else { + expect(getUid2LocalStorage().advertising_token).toBe( + originalIdentity.advertising_token + ); + } + }); + test("should set refresh timer", () => { + expect(setTimeout).toHaveBeenCalledTimes(1); + expect(clearTimeout).not.toHaveBeenCalled(); + }); + test("should be in available state", () => { + (expect(uid2) as any).toBeInAvailableState( + originalIdentity.advertising_token + ); + }); }); - test("should be in available state", () => { - (expect(uid2) as any).toBeInAvailableState( - originalIdentity.advertising_token - ); + + describe("when token refresh returns incorrect body type", () => { + beforeEach(() => { + xhrMock.responseText = JSON.stringify({ status: "success", body: 5 }); + xhrMock.onreadystatechange(new Event("")); + }); + + test("should invoke the callback", () => { + expect(callback).toHaveBeenNthCalledWith( + 1, + expect.objectContaining({ + advertisingToken: originalIdentity.advertising_token, + advertising_token: originalIdentity.advertising_token, + status: UID2.IdentityStatus.ESTABLISHED, + }) + ); + }); + test("should set value", () => { + if (useCookie) { + expect(getUid2Cookie().advertising_token).toBe( + originalIdentity.advertising_token + ); + } + else { + expect(getUid2LocalStorage().advertising_token).toBe( + originalIdentity.advertising_token + ); + } + }); + test("should set refresh timer", () => { + expect(setTimeout).toHaveBeenCalledTimes(1); + expect(clearTimeout).not.toHaveBeenCalled(); + }); + test("should be in available state", () => { + (expect(uid2) as any).toBeInAvailableState( + originalIdentity.advertising_token + ); + }); }); - }); - describe("when token refresh returns incorrect body type", () => { - beforeEach(() => { - xhrMock.responseText = JSON.stringify({ status: "success", body: 5 }); - xhrMock.onreadystatechange(new Event("")); - }); - - test("should invoke the callback", () => { - expect(callback).toHaveBeenNthCalledWith( - 1, - expect.objectContaining({ - advertisingToken: originalIdentity.advertising_token, - advertising_token: originalIdentity.advertising_token, - status: UID2.IdentityStatus.ESTABLISHED, - }) - ); - }); - test("should set cookie", () => { - expect(getUid2Cookie().advertising_token).toBe( - originalIdentity.advertising_token - ); - }); - test("should set refresh timer", () => { - expect(setTimeout).toHaveBeenCalledTimes(1); - expect(clearTimeout).not.toHaveBeenCalled(); + describe("when token refresh returns invalid body", () => { + beforeEach(() => { + xhrMock.responseText = JSON.stringify({ status: "success", body: {} }); + xhrMock.onreadystatechange(new Event("")); + }); + + test("should invoke the callback", () => { + expect(callback).toHaveBeenNthCalledWith( + 1, + expect.objectContaining({ + advertisingToken: originalIdentity.advertising_token, + advertising_token: originalIdentity.advertising_token, + status: UID2.IdentityStatus.ESTABLISHED, + }) + ); + }); + test("should set value", () => { + if (useCookie) { + expect(getUid2Cookie().advertising_token).toBe( + originalIdentity.advertising_token + ); + } + else { + expect(getUid2LocalStorage().advertising_token).toBe( + originalIdentity.advertising_token + ); + } + }); + test("should set refresh timer", () => { + expect(setTimeout).toHaveBeenCalledTimes(1); + expect(clearTimeout).not.toHaveBeenCalled(); + }); + test("should be in available state", () => { + (expect(uid2) as any).toBeInAvailableState( + originalIdentity.advertising_token + ); + }); }); - test("should be in available state", () => { - (expect(uid2) as any).toBeInAvailableState( - originalIdentity.advertising_token - ); + + describe("when token refresh fails and current identity expires", () => { + beforeEach(() => { + jest.setSystemTime(originalIdentity.refresh_expires * 1000 + 1); + xhrMock.responseText = JSON.stringify({ status: "error" }); + xhrMock.onreadystatechange(new Event("")); + }); + + test("should invoke the callback", () => { + expect(callback).toHaveBeenLastCalledWith( + expect.objectContaining({ + advertisingToken: undefined, + advertising_token: undefined, + status: UID2.IdentityStatus.REFRESH_EXPIRED, + }) + ); + }); + test("should not set cookie", () => { + expect(getUid2Cookie()).toBeUndefined(); + }); + test("should not set refresh timer", () => { + expect(setTimeout).not.toHaveBeenCalled(); + expect(clearTimeout).not.toHaveBeenCalled(); + }); + test("should be in unavailable state", () => { + (expect(uid2) as any).toBeInUnavailableState(); + }); }); }); - describe("when token refresh returns invalid body", () => { - beforeEach(() => { - xhrMock.responseText = JSON.stringify({ status: "success", body: {} }); - xhrMock.onreadystatechange(new Event("")); - }); - - test("should invoke the callback", () => { - expect(callback).toHaveBeenNthCalledWith( - 1, - expect.objectContaining({ - advertisingToken: originalIdentity.advertising_token, - advertising_token: originalIdentity.advertising_token, - status: UID2.IdentityStatus.ESTABLISHED, - }) - ); - }); - test("should set cookie", () => { - expect(getUid2Cookie().advertising_token).toBe( - originalIdentity.advertising_token - ); - }); - test("should set refresh timer", () => { - expect(setTimeout).toHaveBeenCalledTimes(1); - expect(clearTimeout).not.toHaveBeenCalled(); + describe("when expired identity is refreshed on init", () => { + const originalIdentity = makeIdentityV2({ + advertising_token: "original_advertising_token", + refresh_from: Date.now() - 100000, + identity_expires: Date.now() - 1, }); - test("should be in available state", () => { - (expect(uid2) as any).toBeInAvailableState( - originalIdentity.advertising_token - ); + const updatedIdentity = makeIdentityV2({ + advertising_token: "updated_advertising_token", }); - }); - describe("when token refresh fails and current identity expires", () => { beforeEach(() => { - jest.setSystemTime(originalIdentity.refresh_expires * 1000 + 1); - xhrMock.responseText = JSON.stringify({ status: "error" }); - xhrMock.onreadystatechange(new Event("")); + uid2.init({ callback: callback, identity: originalIdentity, useCookie: useCookie }); }); - test("should invoke the callback", () => { - expect(callback).toHaveBeenLastCalledWith( - expect.objectContaining({ - advertisingToken: undefined, - advertising_token: undefined, - status: UID2.IdentityStatus.REFRESH_EXPIRED, - }) - ); - }); - test("should not set cookie", () => { - expect(getUid2Cookie()).toBeUndefined(); - }); - test("should not set refresh timer", () => { - expect(setTimeout).not.toHaveBeenCalled(); - expect(clearTimeout).not.toHaveBeenCalled(); - }); - test("should be in unavailable state", () => { - (expect(uid2) as any).toBeInUnavailableState(); + describe("when token refresh succeeds", () => { + beforeEach(() => { + xhrMock.responseText = btoa( + JSON.stringify({ status: "success", body: updatedIdentity }) + ); + xhrMock.onreadystatechange(new Event("")); + }); + + test("should invoke the callback", () => { + expect(callback).toHaveBeenNthCalledWith( + 2, + expect.objectContaining({ + advertisingToken: updatedIdentity.advertising_token, + advertising_token: updatedIdentity.advertising_token, + status: UID2.IdentityStatus.REFRESHED, + }) + ); + }); + test("should set value", () => { + if (useCookie) { + expect(getUid2Cookie().advertising_token).toBe( + updatedIdentity.advertising_token + ); + } + else { + expect(getUid2LocalStorage().advertising_token).toBe( + updatedIdentity.advertising_token + ); + } + }); + test("should set refresh timer", () => { + expect(setTimeout).toHaveBeenCalledTimes(1); + expect(clearTimeout).not.toHaveBeenCalled(); + }); + test("should be in available state", () => { + (expect(uid2) as any).toBeInAvailableState( + updatedIdentity.advertising_token + ); + }); }); - }); -}); -describe("when expired identity is refreshed on init", () => { - const originalIdentity = makeIdentityV2({ - advertising_token: "original_advertising_token", - refresh_from: Date.now() - 100000, - identity_expires: Date.now() - 1, - }); - const updatedIdentity = makeIdentityV2({ - advertising_token: "updated_advertising_token", - }); + describe("when token refresh returns optout", () => { + beforeEach(() => { + xhrMock.responseText = btoa(JSON.stringify({ status: "optout" })); + xhrMock.onreadystatechange(new Event("")); + }); - beforeEach(() => { - uid2.init({ callback: callback, identity: originalIdentity }); - }); + test("should invoke the callback", () => { + expect(callback).toHaveBeenLastCalledWith( + expect.objectContaining({ + advertisingToken: undefined, + advertising_token: undefined, + status: UID2.IdentityStatus.OPTOUT, + }) + ); + }); + test("should not set cookie", () => { + expect(getUid2Cookie()).toBeUndefined(); + }); + test("should not set refresh timer", () => { + expect(setTimeout).not.toHaveBeenCalled(); + expect(clearTimeout).not.toHaveBeenCalled(); + }); + test("should be in unavailable state", () => { + (expect(uid2) as any).toBeInUnavailableState(); + }); + }); - describe("when token refresh succeeds", () => { - beforeEach(() => { - xhrMock.responseText = btoa( - JSON.stringify({ status: "success", body: updatedIdentity }) - ); - xhrMock.onreadystatechange(new Event("")); - }); - - test("should invoke the callback", () => { - expect(callback).toHaveBeenNthCalledWith( - 2, - expect.objectContaining({ - advertisingToken: updatedIdentity.advertising_token, - advertising_token: updatedIdentity.advertising_token, - status: UID2.IdentityStatus.REFRESHED, - }) - ); - }); - test("should set cookie", () => { - expect(getUid2Cookie().advertising_token).toBe( - updatedIdentity.advertising_token - ); - }); - test("should set refresh timer", () => { - expect(setTimeout).toHaveBeenCalledTimes(1); - expect(clearTimeout).not.toHaveBeenCalled(); + describe("when token refresh returns expired token", () => { + beforeEach(() => { + xhrMock.responseText = JSON.stringify({ status: "expired_token" }); + xhrMock.status = 400; + xhrMock.onreadystatechange(new Event("")); + }); + + test("should invoke the callback", () => { + expect(callback).toHaveBeenNthCalledWith( + 2, + expect.objectContaining({ + advertisingToken: undefined, + advertising_token: undefined, + status: UID2.IdentityStatus.REFRESH_EXPIRED, + }) + ); + }); + test("should not set cookie", () => { + expect(getUid2Cookie()).toBeUndefined(); + }); + test("should not set refresh timer", () => { + expect(setTimeout).not.toHaveBeenCalled(); + expect(clearTimeout).not.toHaveBeenCalled(); + }); + test("should be in unavailable state", () => { + (expect(uid2) as any).toBeInUnavailableState(); + }); }); - test("should be in available state", () => { - (expect(uid2) as any).toBeInAvailableState( - updatedIdentity.advertising_token - ); + + describe("when token refresh returns an error status", () => { + beforeEach(() => { + xhrMock.responseText = JSON.stringify({ + status: "error", + body: updatedIdentity, + }); + xhrMock.onreadystatechange(new Event("")); + }); + + test("should invoke the callback", () => { + expect(callback).toHaveBeenNthCalledWith( + 1, + expect.objectContaining({ + advertisingToken: undefined, + advertising_token: undefined, + status: UID2.IdentityStatus.EXPIRED, + }) + ); + }); + test("should set value", () => { + if (useCookie) { + expect(getUid2Cookie().advertising_token).toBe( + originalIdentity.advertising_token + ); + } + else { + expect(getUid2LocalStorage().advertising_token).toBe( + originalIdentity.advertising_token + ); + } + }); + test("should set refresh timer", () => { + expect(setTimeout).toHaveBeenCalledTimes(1); + expect(clearTimeout).not.toHaveBeenCalled(); + }); + test("should be in temporarily unavailable state", () => { + (expect(uid2) as any).toBeInTemporarilyUnavailableState(); + }); }); - }); - describe("when token refresh returns optout", () => { - beforeEach(() => { - xhrMock.responseText = btoa(JSON.stringify({ status: "optout" })); - xhrMock.onreadystatechange(new Event("")); + describe("when token refresh fails and current identity expires", () => { + beforeEach(() => { + jest.setSystemTime(originalIdentity.refresh_expires * 1000 + 1); + xhrMock.responseText = JSON.stringify({ status: "error" }); + xhrMock.onreadystatechange(new Event("")); + }); + + test("should invoke the callback", () => { + expect(callback).toHaveBeenNthCalledWith( + 2, + expect.objectContaining({ + advertisingToken: undefined, + advertising_token: undefined, + status: UID2.IdentityStatus.REFRESH_EXPIRED, + }) + ); + }); + test("should not set cookie", () => { + expect(getUid2Cookie()).toBeUndefined(); + }); + test("should not set refresh timer", () => { + expect(setTimeout).not.toHaveBeenCalled(); + expect(clearTimeout).not.toHaveBeenCalled(); + }); + test("should be in unavailable state", () => { + (expect(uid2) as any).toBeInUnavailableState(); + }); }); + }); - test("should invoke the callback", () => { - expect(callback).toHaveBeenLastCalledWith( - expect.objectContaining({ - advertisingToken: undefined, - advertising_token: undefined, - status: UID2.IdentityStatus.OPTOUT, - }) - ); + describe("abort()", () => { + test("should not clear cookie", () => { + const identity = makeIdentityV2(); + setUid2Cookie(identity); + uid2.abort(); + expect(getUid2Cookie().advertising_token).toBe(identity.advertising_token); }); - test("should not set cookie", () => { - expect(getUid2Cookie()).toBeUndefined(); + test("should abort refresh timer", () => { + uid2.init({ callback: callback, identity: makeIdentityV2(), useCookie: useCookie }); + expect(setTimeout).toHaveBeenCalledTimes(1); + expect(clearTimeout).not.toHaveBeenCalled(); + uid2.abort(); + expect(setTimeout).toHaveBeenCalledTimes(1); + expect(clearTimeout).toHaveBeenCalledTimes(1); }); - test("should not set refresh timer", () => { + test("should not abort refresh timer if not timer is set", () => { + uid2.init({ + callback: callback, + identity: makeIdentityV2({ refresh_from: Date.now() - 100000 }), + useCookie: useCookie + }); expect(setTimeout).not.toHaveBeenCalled(); expect(clearTimeout).not.toHaveBeenCalled(); - }); - test("should be in unavailable state", () => { - (expect(uid2) as any).toBeInUnavailableState(); - }); - }); - - describe("when token refresh returns expired token", () => { - beforeEach(() => { - xhrMock.responseText = JSON.stringify({ status: "expired_token" }); - xhrMock.status = 400; - xhrMock.onreadystatechange(new Event("")); - }); - - test("should invoke the callback", () => { - expect(callback).toHaveBeenNthCalledWith( - 2, - expect.objectContaining({ - advertisingToken: undefined, - advertising_token: undefined, - status: UID2.IdentityStatus.REFRESH_EXPIRED, - }) - ); - }); - test("should not set cookie", () => { - expect(getUid2Cookie()).toBeUndefined(); - }); - test("should not set refresh timer", () => { + uid2.abort(); expect(setTimeout).not.toHaveBeenCalled(); expect(clearTimeout).not.toHaveBeenCalled(); }); - test("should be in unavailable state", () => { - (expect(uid2) as any).toBeInUnavailableState(); - }); - }); - - describe("when token refresh returns an error status", () => { - beforeEach(() => { - xhrMock.responseText = JSON.stringify({ - status: "error", - body: updatedIdentity, + test("should abort refresh token request", () => { + uid2.init({ + callback: callback, + identity: makeIdentityV2({ refresh_from: Date.now() - 100000 }), + useCookie: useCookie }); - xhrMock.onreadystatechange(new Event("")); - }); - - test("should invoke the callback", () => { - expect(callback).toHaveBeenNthCalledWith( - 1, - expect.objectContaining({ - advertisingToken: undefined, - advertising_token: undefined, - status: UID2.IdentityStatus.EXPIRED, - }) - ); - }); - test("should set cookie", () => { - expect(getUid2Cookie().advertising_token).toBe( - originalIdentity.advertising_token - ); - }); - test("should set refresh timer", () => { - expect(setTimeout).toHaveBeenCalledTimes(1); - expect(clearTimeout).not.toHaveBeenCalled(); + expect(xhrMock.send).toHaveBeenCalledTimes(1); + expect(xhrMock.abort).not.toHaveBeenCalled(); + uid2.abort(); + expect(xhrMock.send).toHaveBeenCalledTimes(1); + expect(xhrMock.abort).toHaveBeenCalledTimes(1); }); - test("should be in temporarily unavailable state", () => { - (expect(uid2) as any).toBeInTemporarilyUnavailableState(); + test("should prevent subsequent calls to init()", () => { + uid2.abort(); + expect(() => uid2.init({ callback: () => { } })).toThrow(); }); }); - describe("when token refresh fails and current identity expires", () => { - beforeEach(() => { - jest.setSystemTime(originalIdentity.refresh_expires * 1000 + 1); - xhrMock.responseText = JSON.stringify({ status: "error" }); - xhrMock.onreadystatechange(new Event("")); - }); - - test("should invoke the callback", () => { - expect(callback).toHaveBeenNthCalledWith( - 2, - expect.objectContaining({ - advertisingToken: undefined, - advertising_token: undefined, - status: UID2.IdentityStatus.REFRESH_EXPIRED, - }) - ); - }); - test("should not set cookie", () => { + describe("disconnect()", () => { + test("should clear cookie", () => { + setUid2Cookie(makeIdentityV2()); + uid2.disconnect(); expect(getUid2Cookie()).toBeUndefined(); }); - test("should not set refresh timer", () => { - expect(setTimeout).not.toHaveBeenCalled(); + test("should abort refresh timer", () => { + uid2.init({ callback: callback, identity: makeIdentityV2(), useCookie: useCookie }); + expect(setTimeout).toHaveBeenCalledTimes(1); expect(clearTimeout).not.toHaveBeenCalled(); + uid2.disconnect(); + expect(setTimeout).toHaveBeenCalledTimes(1); + expect(clearTimeout).toHaveBeenCalledTimes(1); + }); + test("should abort refresh token request", () => { + uid2.init({ + callback: callback, + identity: makeIdentityV2({ refresh_from: Date.now() - 100000 }), + useCookie: useCookie + }); + expect(xhrMock.send).toHaveBeenCalledTimes(1); + expect(xhrMock.abort).not.toHaveBeenCalled(); + uid2.disconnect(); + expect(xhrMock.send).toHaveBeenCalledTimes(1); + expect(xhrMock.abort).toHaveBeenCalledTimes(1); }); - test("should be in unavailable state", () => { + test("should prevent subsequent calls to init()", () => { + uid2.disconnect(); + expect(() => uid2.init({ callback: () => { } })).toThrow(); + }); + test("should switch to unavailable state", () => { + uid2.init({ callback: callback, identity: makeIdentityV2(), useCookie: useCookie }); + uid2.disconnect(); (expect(uid2) as any).toBeInUnavailableState(); }); }); }); - -describe("abort()", () => { - test("should not clear cookie", () => { - const identity = makeIdentityV2(); - setUid2Cookie(identity); - uid2.abort(); - expect(getUid2Cookie().advertising_token).toBe(identity.advertising_token); - }); - test("should abort refresh timer", () => { - uid2.init({ callback: callback, identity: makeIdentityV2() }); - expect(setTimeout).toHaveBeenCalledTimes(1); - expect(clearTimeout).not.toHaveBeenCalled(); - uid2.abort(); - expect(setTimeout).toHaveBeenCalledTimes(1); - expect(clearTimeout).toHaveBeenCalledTimes(1); - }); - test("should not abort refresh timer if not timer is set", () => { - uid2.init({ - callback: callback, - identity: makeIdentityV2({ refresh_from: Date.now() - 100000 }), - }); - expect(setTimeout).not.toHaveBeenCalled(); - expect(clearTimeout).not.toHaveBeenCalled(); - uid2.abort(); - expect(setTimeout).not.toHaveBeenCalled(); - expect(clearTimeout).not.toHaveBeenCalled(); - }); - test("should abort refresh token request", () => { - uid2.init({ - callback: callback, - identity: makeIdentityV2({ refresh_from: Date.now() - 100000 }), - }); - expect(xhrMock.send).toHaveBeenCalledTimes(1); - expect(xhrMock.abort).not.toHaveBeenCalled(); - uid2.abort(); - expect(xhrMock.send).toHaveBeenCalledTimes(1); - expect(xhrMock.abort).toHaveBeenCalledTimes(1); - }); - test("should prevent subsequent calls to init()", () => { - uid2.abort(); - expect(() => uid2.init({ callback: () => {} })).toThrow(); - }); -}); - -describe("disconnect()", () => { - test("should clear cookie", () => { - setUid2Cookie(makeIdentityV2()); - uid2.disconnect(); - expect(getUid2Cookie()).toBeUndefined(); - }); - test("should abort refresh timer", () => { - uid2.init({ callback: callback, identity: makeIdentityV2() }); - expect(setTimeout).toHaveBeenCalledTimes(1); - expect(clearTimeout).not.toHaveBeenCalled(); - uid2.disconnect(); - expect(setTimeout).toHaveBeenCalledTimes(1); - expect(clearTimeout).toHaveBeenCalledTimes(1); - }); - test("should abort refresh token request", () => { - uid2.init({ - callback: callback, - identity: makeIdentityV2({ refresh_from: Date.now() - 100000 }), - }); - expect(xhrMock.send).toHaveBeenCalledTimes(1); - expect(xhrMock.abort).not.toHaveBeenCalled(); - uid2.disconnect(); - expect(xhrMock.send).toHaveBeenCalledTimes(1); - expect(xhrMock.abort).toHaveBeenCalledTimes(1); - }); - test("should prevent subsequent calls to init()", () => { - uid2.disconnect(); - expect(() => uid2.init({ callback: () => {} })).toThrow(); - }); - test("should switch to unavailable state", () => { - uid2.init({ callback: callback, identity: makeIdentityV2() }); - uid2.disconnect(); - (expect(uid2) as any).toBeInUnavailableState(); - }); -}); diff --git a/src/integrationTests/callbacks.test.ts b/src/integrationTests/callbacks.test.ts index b642684..7f4b3e4 100644 --- a/src/integrationTests/callbacks.test.ts +++ b/src/integrationTests/callbacks.test.ts @@ -47,100 +47,126 @@ afterEach(() => { const makeIdentity = mocks.makeIdentityV2; -describe("when a callback is provided", () => { - const refreshFrom = Date.now() + 100; - const identity = { ...makeIdentity(), refresh_from: refreshFrom }; - const refreshedIdentity = { - ...makeIdentity(), - advertising_token: "refreshed_token", - }; - describe("before init is called", () => { - test("it should be called at the end of init", () => { - uid2.callbacks.push(asyncCallback); - const calls = asyncCallback.mock.calls.length; - uid2.init({ callback: callback, identity: identity }); - expect(asyncCallback.mock.calls.length).toBe(calls + 1); +let useCookie: boolean | undefined = undefined; + +const testCookieAndLocalStorage = (test: () => void, only = false) => { + const describeFn = only ? describe.only : describe; + describeFn('Using default: ', () => { + beforeEach(() => { + useCookie = undefined; }); - test("it should be called with a 'successful init' message", () => { - uid2.callbacks.push(asyncCallback); - uid2.init({ callback: callback, identity: identity }); - expect(asyncCallback.mock.calls.slice(-1)[0][0]).toBe( - UID2.EventType.InitCompleted - ); + test(); + }); + describeFn('Using cookies ', () => { + beforeEach(() => { + useCookie = true; }); - test("it should be provided with the loaded identity", () => { - uid2.callbacks.push(asyncCallback); - uid2.init({ callback: callback, identity: identity }); - expect(asyncCallback.mock.calls.slice(-1)[0][1]).toMatchObject({ - identity, - }); + test(); + }); + describeFn('Using local storage ', () => { + beforeEach(() => { + useCookie = false; }); + test(); }); - - describe("after init is called", () => { - test("it should be called with SdkLoaded and InitComplete immediately", () => { - uid2.init({ callback: callback, identity: identity }); - expect(asyncCallback.mock.calls.length).toBe(0); - uid2.callbacks.push(asyncCallback); - expect(asyncCallback.mock.calls.length).toBe(2); - expect(asyncCallback.mock.calls[0][0]).toBe(UID2.EventType.SdkLoaded); - expect(asyncCallback.mock.calls[1][0]).toBe(UID2.EventType.InitCompleted); +}; + +testCookieAndLocalStorage(() => { + describe("when a callback is provided", () => { + const refreshFrom = Date.now() + 100; + const identity = { ...makeIdentity(), refresh_from: refreshFrom }; + const refreshedIdentity = { + ...makeIdentity(), + advertising_token: "refreshed_token", + }; + describe("before init is called", () => { + test("it should be called at the end of init", () => { + uid2.callbacks.push(asyncCallback); + const calls = asyncCallback.mock.calls.length; + uid2.init({ callback: callback, identity: identity, useCookie: useCookie }); + expect(asyncCallback.mock.calls.length).toBe(calls + 1); + }); + test("it should be called with a 'successful init' message", () => { + uid2.callbacks.push(asyncCallback); + uid2.init({ callback: callback, identity: identity, useCookie: useCookie }); + expect(asyncCallback.mock.calls.slice(-1)[0][0]).toBe( + UID2.EventType.InitCompleted + ); + }); + test("it should be provided with the loaded identity", () => { + uid2.callbacks.push(asyncCallback); + uid2.init({ callback: callback, identity: identity, useCookie: useCookie }); + expect(asyncCallback.mock.calls.slice(-1)[0][1]).toMatchObject({ + identity, + }); + }); }); - test("it should be provided with the loaded identity", () => { - uid2.init({ callback: callback, identity: identity }); - uid2.callbacks.push(asyncCallback); - - expect(asyncCallback.mock.calls.slice(-1)[0][1]).toMatchObject({ - identity, + describe("after init is called", () => { + test("it should be called with SdkLoaded and InitComplete immediately", () => { + uid2.init({ callback: callback, identity: identity, useCookie: useCookie }); + expect(asyncCallback.mock.calls.length).toBe(0); + uid2.callbacks.push(asyncCallback); + expect(asyncCallback.mock.calls.length).toBe(2); + expect(asyncCallback.mock.calls[0][0]).toBe(UID2.EventType.SdkLoaded); + expect(asyncCallback.mock.calls[1][0]).toBe(UID2.EventType.InitCompleted); }); - }); - test("it should receive subsequent identity updates", async () => { - uid2.init({ callback: callback, identity: identity }); - uid2.callbacks.push(asyncCallback); - - const callsBeforeRefresh = asyncCallback.mock.calls.length; - jest.setSystemTime(refreshFrom); - jest.runOnlyPendingTimers(); - expect(xhrMock.send).toHaveBeenCalledTimes(1); - xhrMock.sendRefreshApiResponse(refreshedIdentity); - await mocks.flushPromises(); - - expect(asyncCallback.mock.calls.length).toBe(callsBeforeRefresh + 1); - expect(asyncCallback.mock.calls[callsBeforeRefresh][0]).toBe( - UID2.EventType.IdentityUpdated - ); - expect(asyncCallback.mock.calls[callsBeforeRefresh][1]).toMatchObject({ - identity: refreshedIdentity, + test("it should be provided with the loaded identity", () => { + uid2.init({ callback: callback, identity: identity, useCookie: useCookie }); + uid2.callbacks.push(asyncCallback); + + expect(asyncCallback.mock.calls.slice(-1)[0][1]).toMatchObject({ + identity, + }); + }); + // this test is only passing for cookies + test("it should receive subsequent identity updates", async () => { + uid2.init({ callback: callback, identity: identity, useCookie: useCookie }); + uid2.callbacks.push(asyncCallback); + + const callsBeforeRefresh = asyncCallback.mock.calls.length; + jest.setSystemTime(refreshFrom); + jest.runOnlyPendingTimers(); + expect(xhrMock.send).toHaveBeenCalledTimes(1); + xhrMock.sendRefreshApiResponse(refreshedIdentity); + await mocks.flushPromises(); + + expect(asyncCallback.mock.calls.length).toBe(callsBeforeRefresh + 1); + expect(asyncCallback.mock.calls[callsBeforeRefresh][0]).toBe( + UID2.EventType.IdentityUpdated + ); + expect(asyncCallback.mock.calls[callsBeforeRefresh][1]).toMatchObject({ + identity: refreshedIdentity, + }); }); - }); - test("it should receive a null identity update if opt-out is called", () => { - uid2.init({ callback: callback, identity: identity }); - uid2.callbacks.push(asyncCallback); - const callsBeforeRefresh = asyncCallback.mock.calls.length; + test("it should receive a null identity update if opt-out is called", () => { + uid2.init({ callback: callback, identity: identity, useCookie: useCookie }); + uid2.callbacks.push(asyncCallback); + const callsBeforeRefresh = asyncCallback.mock.calls.length; - uid2.disconnect(); + uid2.disconnect(); - expect(asyncCallback.mock.calls.length).toBe(callsBeforeRefresh + 1); - expect(asyncCallback.mock.calls[callsBeforeRefresh][0]).toBe( - UID2.EventType.IdentityUpdated - ); - expect(asyncCallback.mock.calls[callsBeforeRefresh][1]).toMatchObject({ - identity: null, + expect(asyncCallback.mock.calls.length).toBe(callsBeforeRefresh + 1); + expect(asyncCallback.mock.calls[callsBeforeRefresh][0]).toBe( + UID2.EventType.IdentityUpdated + ); + expect(asyncCallback.mock.calls[callsBeforeRefresh][1]).toMatchObject({ + identity: null, + }); }); - }); - test("it should receive identity updates when set identity is called", () => { - uid2.init({ callback: callback }); - uid2.callbacks.push(asyncCallback); - const callsBeforeSetIdentity= asyncCallback.mock.calls.length; - uid2.setIdentity(identity) + test("it should receive identity updates when set identity is called", () => { + uid2.init({ callback: callback, useCookie: useCookie }); + uid2.callbacks.push(asyncCallback); + const callsBeforeSetIdentity = asyncCallback.mock.calls.length; + uid2.setIdentity(identity); - expect(asyncCallback.mock.calls.length).toBe(callsBeforeSetIdentity+1); - expect(asyncCallback.mock.calls[callsBeforeSetIdentity][0]).toBe(UID2.EventType.IdentityUpdated); - expect(asyncCallback.mock.calls[callsBeforeSetIdentity][1]).toMatchObject({ identity: identity }); + expect(asyncCallback.mock.calls.length).toBe(callsBeforeSetIdentity + 1); + expect(asyncCallback.mock.calls[callsBeforeSetIdentity][0]).toBe(UID2.EventType.IdentityUpdated); + expect(asyncCallback.mock.calls[callsBeforeSetIdentity][1]).toMatchObject({ identity: identity }); + }); }); }); }); diff --git a/src/integrationTests/compatibility.test.ts b/src/integrationTests/compatibility.test.ts index e279c64..7afac76 100644 --- a/src/integrationTests/compatibility.test.ts +++ b/src/integrationTests/compatibility.test.ts @@ -29,104 +29,148 @@ afterEach(() => { const setUid2Cookie = mocks.setUid2Cookie; const getUid2Cookie = mocks.getUid2Cookie; +const getUid2LocalStorage = mocks.getUid2LocalStorage; const makeIdentity = mocks.makeIdentityV2; -describe("when a v0 cookie is available", () => { - const originalIdentity = { - advertising_token: "original_advertising_token", - refresh_token: "original_refresh_token", - }; - const updatedIdentity = makeIdentity({ - advertising_token: "updated_advertising_token", - }); - - beforeEach(() => { - setUid2Cookie(originalIdentity); - uid2.init({ callback: callback }); - }); +let useCookie: boolean | undefined = undefined; - test("should initiate token refresh", () => { - expect(xhrMock.send).toHaveBeenCalledTimes(1); +const testCookieAndLocalStorage = (test: () => void, only = false) => { + const describeFn = only ? describe.only : describe; + describeFn('Using default: ', () => { + beforeEach(() => { + useCookie = undefined; + }); + test(); }); - test("should not set refresh timer", () => { - expect(setTimeout).not.toHaveBeenCalled(); - expect(clearTimeout).not.toHaveBeenCalled(); + describeFn('Using cookies ', () => { + beforeEach(() => { + useCookie = true; + }); + test(); }); - test("should be in initialising state", () => { - (expect(uid2) as any).toBeInAvailableState(); + describeFn('Using local storage ', () => { + beforeEach(() => { + useCookie = false; + }); + test(); }); +}; - describe("when token refresh succeeds", () => { - beforeEach(() => { - xhrMock.responseText = JSON.stringify({ - status: "success", - body: updatedIdentity, - }); - xhrMock.onreadystatechange(new Event("")); +testCookieAndLocalStorage(() => { + describe("when a v0 cookie is available", () => { + const originalIdentity = { + advertising_token: "original_advertising_token", + refresh_token: "original_refresh_token", + }; + const updatedIdentity = makeIdentity({ + advertising_token: "updated_advertising_token", }); - test("should invoke the callback", () => { - expect(callback).toHaveBeenLastCalledWith( - expect.objectContaining({ - advertising_token: updatedIdentity.advertising_token, - status: UID2.IdentityStatus.REFRESHED, - }) - ); + beforeEach(() => { + setUid2Cookie(originalIdentity); + uid2.init({ callback: callback, useCookie: useCookie }); }); - test("should set cookie", () => { - expect(getUid2Cookie().advertising_token).toBe( - updatedIdentity.advertising_token - ); + + test("should initiate token refresh", () => { + expect(xhrMock.send).toHaveBeenCalledTimes(1); }); - test("should set refresh timer", () => { - expect(setTimeout).toHaveBeenCalledTimes(1); + test("should not set refresh timer", () => { + expect(setTimeout).not.toHaveBeenCalled(); expect(clearTimeout).not.toHaveBeenCalled(); }); - test("should be in available state", () => { - (expect(uid2) as any).toBeInAvailableState( - updatedIdentity.advertising_token - ); + test("should be in initialising state", () => { + (expect(uid2) as any).toBeInAvailableState(); }); - }); - describe("when token refresh returns an error status", () => { - beforeEach(() => { - xhrMock.responseText = JSON.stringify({ - status: "error", - body: updatedIdentity, + describe("when token refresh succeeds", () => { + beforeEach(() => { + xhrMock.responseText = JSON.stringify({ + status: "success", + body: updatedIdentity, + }); + xhrMock.onreadystatechange(new Event("")); }); - xhrMock.onreadystatechange(new Event("")); - }); - test("should invoke the callback", () => { - expect(callback).toHaveBeenNthCalledWith( - 1, - expect.objectContaining({ - advertisingToken: originalIdentity.advertising_token, - advertising_token: originalIdentity.advertising_token, - status: UID2.IdentityStatus.ESTABLISHED, - }) - ); - }); - test("should set enriched cookie", () => { - expect(getUid2Cookie().refresh_token).toBe( - originalIdentity.refresh_token - ); - expect(getUid2Cookie().refresh_from).toBe(Date.now()); - expect(getUid2Cookie().identity_expires).toBeGreaterThan(Date.now()); - expect(getUid2Cookie().refresh_expires).toBeGreaterThan(Date.now()); - expect(getUid2Cookie().identity_expires).toBeLessThan( - getUid2Cookie().refresh_expires - ); - }); - test("should set refresh timer", () => { - expect(setTimeout).toHaveBeenCalledTimes(1); - expect(clearTimeout).not.toHaveBeenCalled(); + test("should invoke the callback", () => { + expect(callback).toHaveBeenLastCalledWith( + expect.objectContaining({ + advertising_token: updatedIdentity.advertising_token, + status: UID2.IdentityStatus.REFRESHED, + }) + ); + }); + test("should set value", () => { + if (useCookie) { + expect(getUid2Cookie().advertising_token).toBe(updatedIdentity.advertising_token); + } else { + expect(getUid2LocalStorage().advertising_token).toBe(updatedIdentity.advertising_token); + } + }); + test("should set refresh timer", () => { + expect(setTimeout).toHaveBeenCalledTimes(1); + expect(clearTimeout).not.toHaveBeenCalled(); + }); + test("should be in available state", () => { + (expect(uid2) as any).toBeInAvailableState( + updatedIdentity.advertising_token + ); + }); }); - test("should be in available state", () => { - (expect(uid2) as any).toBeInAvailableState( - originalIdentity.advertising_token - ); + + describe("when token refresh returns an error status", () => { + beforeEach(() => { + xhrMock.responseText = JSON.stringify({ + status: "error", + body: updatedIdentity, + }); + xhrMock.onreadystatechange(new Event("")); + }); + + test("should invoke the callback", () => { + expect(callback).toHaveBeenNthCalledWith( + 1, + expect.objectContaining({ + advertisingToken: originalIdentity.advertising_token, + advertising_token: originalIdentity.advertising_token, + status: UID2.IdentityStatus.ESTABLISHED, + }) + ); + }); + test("should set enriched value", () => { + if (useCookie) { + const cookie = getUid2Cookie(); + expect(cookie.refresh_token).toBe( + originalIdentity.refresh_token + ); + expect(cookie.refresh_from).toBe(Date.now()); + expect(cookie.identity_expires).toBeGreaterThan(Date.now()); + expect(cookie.refresh_expires).toBeGreaterThan(Date.now()); + expect(cookie.identity_expires).toBeLessThan( + cookie.refresh_expires + ); + } + else { + const localStorageValue = getUid2LocalStorage(); + expect(localStorageValue.refresh_token).toBe( + originalIdentity.refresh_token + ); + expect(localStorageValue.refresh_from).toBe(Date.now()); + expect(localStorageValue.identity_expires).toBeGreaterThan(Date.now()); + expect(localStorageValue.refresh_expires).toBeGreaterThan(Date.now()); + expect(localStorageValue.identity_expires).toBeLessThan( + localStorageValue.refresh_expires + ); + } + }); + test("should set refresh timer", () => { + expect(setTimeout).toHaveBeenCalledTimes(1); + expect(clearTimeout).not.toHaveBeenCalled(); + }); + test("should be in available state", () => { + (expect(uid2) as any).toBeInAvailableState( + originalIdentity.advertising_token + ); + }); }); }); }); diff --git a/src/integrationTests/options.test.ts b/src/integrationTests/options.test.ts index 40e1041..73cfe6f 100644 --- a/src/integrationTests/options.test.ts +++ b/src/integrationTests/options.test.ts @@ -33,11 +33,15 @@ afterEach(() => { }); const makeIdentity = mocks.makeIdentityV2; +const getUid2Cookie = mocks.getUid2Cookie; +const getUid2LocalStorage = mocks.getUid2LocalStorage; +const removeUid2Cookie = mocks.removeUid2Cookie; +const removeUid2LocalStorage = mocks.removeUid2LocalStorage; describe("cookieDomain option", () => { describe("when using default value", () => { beforeEach(() => { - uid2.init({ callback: callback, identity: makeIdentity() }); + uid2.init({ callback: callback, identity: makeIdentity(), useCookie: true }); }); test("should not mention domain in the cookie string", () => { @@ -55,6 +59,7 @@ describe("cookieDomain option", () => { callback: callback, identity: makeIdentity(), cookieDomain: domain, + useCookie: true }); }); @@ -68,7 +73,7 @@ describe("cookieDomain option", () => { describe("cookiePath option", () => { describe("when using default value", () => { beforeEach(() => { - uid2.init({ callback: callback, identity: makeIdentity() }); + uid2.init({ callback: callback, identity: makeIdentity(), useCookie: true }); }); test("should use the default path in the cookie string", () => { @@ -85,6 +90,7 @@ describe("cookiePath option", () => { callback: callback, identity: makeIdentity(), cookiePath: path, + useCookie: true }); }); @@ -156,3 +162,39 @@ describe("refreshRetryPeriod option", () => { }); }); }); + +describe("useCookie option", () => { + const identity = makeIdentity(); + + beforeEach(() => { + removeUid2Cookie(); + removeUid2LocalStorage(); + }); + + describe("when using default value", () => { + beforeEach(() => { + uid2.init({ callback: callback, identity: identity }); + }); + test("should set identity in local storage", () => { + expect(getUid2LocalStorage().advertising_token).toBe(identity.advertising_token); + }); + }); + describe("when useCookie is false", () => { + beforeEach(() => { + uid2.init({ callback: callback, identity: identity, useCookie: false }); + }); + test("should set identity in local storage only", () => { + expect(getUid2LocalStorage().advertising_token).toBe(identity.advertising_token); + expect(getUid2Cookie()).toBeUndefined(); + }); + }); + describe("when useCookie is true", () => { + beforeEach(() => { + uid2.init({ callback: callback, identity: identity, useCookie: true }); + }); + test("should set identity in cookie only", () => { + expect(getUid2Cookie().advertising_token).toBe(identity.advertising_token); + expect(getUid2LocalStorage()).toBeNull(); + }); + }); +}); diff --git a/src/integrationTests/secureSignal.test.ts b/src/integrationTests/secureSignal.test.ts index f169a81..34a22ea 100644 --- a/src/integrationTests/secureSignal.test.ts +++ b/src/integrationTests/secureSignal.test.ts @@ -65,7 +65,7 @@ describe("Secure Signal Tests", () => { }); }); - describe("when getUid2AdvertisingToken is not definied", () => { + describe("when getUid2AdvertisingToken is not defined", () => { test("should not send signal to ESP", () => { uid2ESP = new Uid2SecureSignalProvider(); expect(secureSignalProvidersPushMock).not.toBeCalled(); diff --git a/src/mocks.ts b/src/mocks.ts index 546961c..9b37cf6 100644 --- a/src/mocks.ts +++ b/src/mocks.ts @@ -2,6 +2,7 @@ import * as jsdom from "jsdom"; import { Cookie } from "tough-cookie"; import { UID2 } from "./uid2Sdk"; import { Uid2Identity } from "./Uid2Identity"; +import { localStorageKeyName } from "./uid2LocalStorageManager"; export class CookieMock { jar: jsdom.CookieJar; @@ -146,6 +147,11 @@ export function setUid2Cookie(value: any) { UID2.COOKIE_NAME + "=" + encodeURIComponent(JSON.stringify(value)); } +export function removeUid2Cookie() { + document.cookie = + document.cookie + "=;expires=Tue, 1 Jan 1980 23:59:59 GMT"; +} + export async function flushPromises() { await Promise.resolve(); await Promise.resolve(); @@ -163,6 +169,20 @@ export function getUid2Cookie() { } } +export function removeUid2LocalStorage() { + localStorage.removeItem(localStorageKeyName); +} + +export function setUid2LocalStorage(identity: string) { + const value = JSON.stringify(identity); + localStorage.setItem(localStorageKeyName, value); +} + +export function getUid2LocalStorage() { + const value = localStorage.getItem(localStorageKeyName); + return value !== null ? JSON.parse(value) : null; +} + export function setEuidCookie(value: any) { document.cookie = "__euid" + "=" + encodeURIComponent(JSON.stringify(value)); } From 15c4cc8dda7a206cf0ac8a055d10fe40b1ccb454 Mon Sep 17 00:00:00 2001 From: Alex Yau Date: Tue, 26 Sep 2023 17:21:41 +1000 Subject: [PATCH 08/21] Add writeable: true to mockObject.defineProperty Without this, only the first pass of the test with succeed, and the following ones would file since the window.cypto would not change --- src/mocks.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mocks.ts b/src/mocks.ts index 9b37cf6..4cd1b5c 100644 --- a/src/mocks.ts +++ b/src/mocks.ts @@ -115,7 +115,7 @@ export class CryptoMock { ); this.applyTo = (window) => { - Object.defineProperty(window, "crypto", { value: this }); + Object.defineProperty(window, "crypto", { value: this, writable: true }); }; this.applyTo(window); From 764d158de50f977cee8cfa4416962301545c5c75 Mon Sep 17 00:00:00 2001 From: Alex Yau Date: Wed, 27 Sep 2023 14:14:08 +1000 Subject: [PATCH 09/21] Clean up basic.test.ts --- src/integrationTests/basic.test.ts | 54 ++---------------------------- 1 file changed, 2 insertions(+), 52 deletions(-) diff --git a/src/integrationTests/basic.test.ts b/src/integrationTests/basic.test.ts index 41800c1..3a0bb45 100644 --- a/src/integrationTests/basic.test.ts +++ b/src/integrationTests/basic.test.ts @@ -13,8 +13,6 @@ import { sdkWindow, UID2 } from "../uid2Sdk"; let callback: any; let uid2: UID2; let xhrMock: any; -// let _cryptoMock: any; -// let cryptoMock: any; mocks.setupFakeTime(); @@ -23,8 +21,8 @@ beforeEach(() => { uid2 = new UID2(); xhrMock = new mocks.XhrMock(sdkWindow); mocks.setCookieMock(sdkWindow.document); - // _cryptoMock = new mocks.CryptoMock(sdkWindow); - // cryptoMock = new mocks.CryptoMock(sdkWindow); + removeUid2Cookie(); + removeUid2LocalStorage(); }); afterEach(() => { @@ -46,24 +44,18 @@ const testCookieAndLocalStorage = (test: () => void, only = false) => { const describeFn = only ? describe.only : describe; describeFn('Using default: ', () => { beforeEach(() => { - removeUid2Cookie(); - removeUid2LocalStorage(); useCookie = undefined; }); test(); }); describeFn('Using cookies ', () => { beforeEach(() => { - removeUid2Cookie(); - removeUid2LocalStorage(); useCookie = true; }); test(); }); describeFn('Using local storage ', () => { beforeEach(() => { - removeUid2Cookie(); - removeUid2LocalStorage(); useCookie = false; }); test(); @@ -160,16 +152,9 @@ testCookieAndLocalStorage(() => { describe("when initialised without identity", () => { describe("when uid2 cookie is not available", () => { beforeEach(() => { - removeUid2Cookie(); - removeUid2LocalStorage(); uid2.init({ callback: callback, useCookie: useCookie }); }); - // afterEach(() => { - // removeUid2Cookie(); - // removeUid2LocalStorage(); - // }) - test("should invoke the callback", () => { expect(callback).toHaveBeenNthCalledWith( 1, @@ -260,17 +245,10 @@ testCookieAndLocalStorage(() => { }); beforeEach(() => { - removeUid2Cookie(); - removeUid2LocalStorage(); setUid2Cookie(identity); uid2.init({ callback: callback, useCookie: useCookie }); }); - // afterEach(() => { - // removeUid2Cookie(); - // removeUid2LocalStorage(); - // }) - test("should invoke the callback", () => { expect(callback).toHaveBeenNthCalledWith( 1, @@ -320,35 +298,24 @@ testCookieAndLocalStorage(() => { identity_expires: Date.now() - 100000, refresh_from: Date.now() - 100000, }); - // let _cryptoMock: any; let cryptoMock: any; - // const cryptoMock = new mocks.CryptoMock(sdkWindow); beforeEach(() => { xhrMock.open.mockClear(); xhrMock.send.mockClear(); cryptoMock = new mocks.CryptoMock(sdkWindow); - // _cryptoMock.subtle.importKey.mockClear(); - removeUid2Cookie(); - removeUid2LocalStorage(); setUid2Cookie(identity); uid2.init({ callback: callback, useCookie: useCookie }); }); afterEach(() => { - removeUid2Cookie(); - removeUid2LocalStorage(); xhrMock.open.mockClear(); xhrMock.send.mockClear(); - // _cryptoMock.subtle.importKey.mockClear(); cryptoMock.subtle.importKey.mockClear(); - // xhrMock.onreadystatechange = null; }); - // this test is only passing on first go test("should initiate token refresh", () => { - // const cryptoMock = new mocks.CryptoMock(sdkWindow); expect(xhrMock.send).toHaveBeenCalledTimes(1); const url = "https://prod.uidapi.com/v2/token/refresh"; expect(xhrMock.open).toHaveBeenLastCalledWith("POST", url, true); @@ -372,8 +339,6 @@ testCookieAndLocalStorage(() => { }); beforeEach(() => { - removeUid2Cookie(); - removeUid2LocalStorage(); setUid2Cookie(identity); uid2.init({ callback: callback, useCookie: useCookie }); }); @@ -393,8 +358,6 @@ testCookieAndLocalStorage(() => { describe("when initialised with specific identity", () => { describe("when invalid identity is supplied", () => { beforeEach(() => { - removeUid2Cookie(); - removeUid2LocalStorage(); // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore uid2.init({ callback: callback, identity: {}, useCookie: useCookie }); @@ -426,8 +389,6 @@ testCookieAndLocalStorage(() => { const identity = makeIdentityV2(); beforeEach(() => { - removeUid2Cookie(); - removeUid2LocalStorage(); uid2.init({ callback: callback, identity: identity, useCookie: useCookie }); }); @@ -471,8 +432,6 @@ testCookieAndLocalStorage(() => { }); beforeEach(() => { - removeUid2Cookie(); - removeUid2LocalStorage(); setUid2Cookie(cookieIdentity); uid2.init({ callback: callback, identity: initIdentity, useCookie: useCookie }); }); @@ -521,8 +480,6 @@ testCookieAndLocalStorage(() => { }); beforeEach(() => { - removeUid2Cookie(); - removeUid2LocalStorage(); uid2.init({ callback: callback, identity: originalIdentity, useCookie: useCookie }); }); @@ -534,11 +491,6 @@ testCookieAndLocalStorage(() => { xhrMock.onreadystatechange(new Event("")); }); - // afterEach(() => { - // removeUid2Cookie(); - // removeUid2LocalStorage(); - // }); - test("should invoke the callback", () => { expect(callback).toHaveBeenLastCalledWith( expect.objectContaining({ @@ -573,8 +525,6 @@ testCookieAndLocalStorage(() => { describe("when token refresh returns invalid response", () => { beforeEach(() => { - // removeUid2Cookie(); - // removeUid2LocalStorage(); xhrMock.responseText = "abc"; xhrMock.onreadystatechange(new Event("")); }); From bd64b393e515e56a5b34f7799c47ef3f77837ba6 Mon Sep 17 00:00:00 2001 From: Alex Yau Date: Wed, 27 Sep 2023 14:16:40 +1000 Subject: [PATCH 10/21] Remove cookie & localStorage in top beforeEach --- src/integrationTests/async.spec.ts | 14 ++------------ src/integrationTests/options.test.ts | 7 ++----- 2 files changed, 4 insertions(+), 17 deletions(-) diff --git a/src/integrationTests/async.spec.ts b/src/integrationTests/async.spec.ts index a8f25af..810af33 100644 --- a/src/integrationTests/async.spec.ts +++ b/src/integrationTests/async.spec.ts @@ -23,6 +23,8 @@ beforeEach(() => { xhrMock = new mocks.XhrMock(sdkWindow); _cryptoMock = new mocks.CryptoMock(sdkWindow); mocks.setCookieMock(sdkWindow.document); + removeUid2Cookie(); + removeUid2LocalStorage(); }); afterEach(() => { @@ -40,24 +42,18 @@ const testCookieAndLocalStorage = (test: () => void, only = false) => { const describeFn = only ? describe.only : describe; describeFn('Using default: ', () => { beforeEach(() => { - removeUid2Cookie(); - removeUid2LocalStorage(); useCookie = undefined; }); test(); }); describeFn('Using cookies ', () => { beforeEach(() => { - removeUid2Cookie(); - removeUid2LocalStorage(); useCookie = true; }); test(); }); describeFn('Using local storage ', () => { beforeEach(() => { - removeUid2Cookie(); - removeUid2LocalStorage(); useCookie = false; }); test(); @@ -167,11 +163,6 @@ testCookieAndLocalStorage(() => { }); describe("when initialisation failed", () => { - - // beforeEach(() => { - // removeUid2Cookie(); - // removeUid2LocalStorage(); - // }); test("it should reject promise", () => { uid2.init({}); return expect(uid2.getAdvertisingTokenAsync()).rejects.toBeInstanceOf( @@ -239,7 +230,6 @@ testCookieAndLocalStorage(() => { console.log("Succeeded"); } }); - // only passes for cookies test("the SDK should be initialized correctly", () => { sdkWindow.__uid2 = { callbacks: [] }; sdkWindow.__uid2.callbacks!.push(callback); diff --git a/src/integrationTests/options.test.ts b/src/integrationTests/options.test.ts index 73cfe6f..2433332 100644 --- a/src/integrationTests/options.test.ts +++ b/src/integrationTests/options.test.ts @@ -26,6 +26,8 @@ beforeEach(() => { xhrMock = new mocks.XhrMock(sdkWindow); jest.spyOn(document, "URL", "get").mockImplementation(() => mockUrl); cookieMock = new mocks.CookieMock(sdkWindow.document); + removeUid2Cookie(); + removeUid2LocalStorage(); }); afterEach(() => { @@ -166,11 +168,6 @@ describe("refreshRetryPeriod option", () => { describe("useCookie option", () => { const identity = makeIdentity(); - beforeEach(() => { - removeUid2Cookie(); - removeUid2LocalStorage(); - }); - describe("when using default value", () => { beforeEach(() => { uid2.init({ callback: callback, identity: identity }); From 65d6f041c2f8e7a65ce641f832adb5582532c924 Mon Sep 17 00:00:00 2001 From: Alex Yau Date: Wed, 27 Sep 2023 17:01:45 +1000 Subject: [PATCH 11/21] Use new uid2StorageManager Wraps uid2CookieManager and uid2LocalStorageManager, so the sdk only needs the uid2StorageManager, offloading logic off the sdk class. --- src/uid2LocalStorageManager.ts | 2 +- src/uid2Sdk.ts | 33 ++++++++---------------- src/uid2StorageManager.ts | 47 ++++++++++++++++++++++++++++++++++ 3 files changed, 58 insertions(+), 24 deletions(-) create mode 100644 src/uid2StorageManager.ts diff --git a/src/uid2LocalStorageManager.ts b/src/uid2LocalStorageManager.ts index f1bcd4c..2cd059e 100644 --- a/src/uid2LocalStorageManager.ts +++ b/src/uid2LocalStorageManager.ts @@ -10,7 +10,7 @@ export class UID2LocalStorageManager { public removeValue() { localStorage.removeItem(localStorageKeyName); } - public getValue() { + private getValue() { return localStorage.getItem(localStorageKeyName); } diff --git a/src/uid2Sdk.ts b/src/uid2Sdk.ts index f39eac0..dcf36ae 100644 --- a/src/uid2Sdk.ts +++ b/src/uid2Sdk.ts @@ -18,6 +18,7 @@ import { } from "./uid2ClientSideIdentityOptions"; import { bytesToBase64 } from "./uid2Base64"; import { UID2LocalStorageManager } from "./uid2LocalStorageManager"; +import { UID2StorageManager } from "./uid2StorageManager"; function hasExpired(expiry: number, now = Date.now()) { return expiry <= now; @@ -55,8 +56,7 @@ export class UID2 { private _callbackManager: Uid2CallbackManager; // Dependencies initialised on call to init due to requirement for options - private _cookieManager: UID2CookieManager | undefined; - private _localStorageManager: UID2LocalStorageManager | undefined; + private _storageManager: UID2StorageManager | undefined; private _apiClient: Uid2ApiClient | undefined; // State @@ -181,8 +181,8 @@ export class UID2 { public disconnect() { this.abort(`UID2 SDK disconnected.`); // Note: This silently fails to clear the cookie if init hasn't been called and a cookieDomain is used! - if (this._cookieManager) this._cookieManager.removeCookie(); - else new UID2CookieManager({}).removeCookie(); + if (this._storageManager) this._storageManager.removeValues(); + else new UID2StorageManager({}).removeValues(); this._identity = undefined; this._callbackManager.runCallbacks(UID2.EventType.IdentityUpdated, { identity: null, @@ -220,8 +220,7 @@ export class UID2 { ); this._opts = opts; - this._cookieManager = new UID2CookieManager({ ...opts }); - this._localStorageManager = new UID2LocalStorageManager(); + this._storageManager = new UID2StorageManager({ ...opts }); this._apiClient = new Uid2ApiClient(opts); this._tokenPromiseHandler.registerApiClient(this._apiClient); @@ -229,10 +228,7 @@ export class UID2 { if (this._opts.identity) { identity = this._opts.identity; } else { - const localStorageIdentity = this._localStorageManager.loadIdentityFromLocalStorage(); - const cookieIdentity = this._cookieManager.loadIdentityFromCookie(); - const shouldUseCookie = cookieIdentity && (!localStorageIdentity || cookieIdentity.identity_expires > localStorageIdentity.identity_expires); - identity = shouldUseCookie ? cookieIdentity : localStorageIdentity; + identity = this._storageManager.loadIdentityFromPreferredStorageWithFallback(); } const validatedIdentity = this.validateAndSetIdentity(identity); if (validatedIdentity) this.triggerRefreshOrSetTimer(validatedIdentity); @@ -328,7 +324,7 @@ export class UID2 { status?: IdentityStatus, statusText?: string ): Uid2Identity | null { - if (!this._cookieManager || !this._localStorageManager) + if (!this._storageManager) throw new Error("Cannot set identity before calling init."); const validity = this.getIdentityStatus(identity); if ( @@ -339,19 +335,10 @@ export class UID2 { this._identity = validity.identity; if (validity.identity) { - if (this._opts.useCookie) { - this._cookieManager.setCookie(validity.identity); - } - else if (this._opts.useCookie === false) { - this._localStorageManager.setValue(validity.identity); - if (this._localStorageManager.getValue()) this._cookieManager.removeCookie(); - } else { - this._localStorageManager.setValue(validity.identity); - } + this._storageManager.setValue(validity.identity); } else { this.abort(); - this._cookieManager.removeCookie(); - this._localStorageManager.removeValue(); + this._storageManager.removeValues(); } notifyInitCallback( this._opts, @@ -381,7 +368,7 @@ export class UID2 { this._refreshTimerId = setTimeout(() => { if (this.isLoginRequired()) return; const validatedIdentity = this.validateAndSetIdentity( - this._cookieManager?.loadIdentityFromCookie() ?? null + this._storageManager?.loadIdentity() ?? null ); if (validatedIdentity) this.triggerRefreshOrSetTimer(validatedIdentity); this._refreshTimerId = null; diff --git a/src/uid2StorageManager.ts b/src/uid2StorageManager.ts new file mode 100644 index 0000000..5b96834 --- /dev/null +++ b/src/uid2StorageManager.ts @@ -0,0 +1,47 @@ +import { UID2 } from "./uid2Sdk"; +import { isValidIdentity, Uid2Identity } from "./Uid2Identity"; +import { UID2CookieManager } from "./uid2CookieManager"; +import { UID2LocalStorageManager } from "./uid2LocalStorageManager"; +import { Uid2Options } from "./Uid2Options"; + +export class UID2StorageManager { + private _cookieManager: UID2CookieManager | undefined; + private _localStorageManager: UID2LocalStorageManager | undefined; + + private _opts: Uid2Options; + constructor(opts: Uid2Options) { + this._opts = opts; + this._cookieManager = new UID2CookieManager({ ...opts }); + this._localStorageManager = new UID2LocalStorageManager(); + } + + public loadIdentityFromPreferredStorageWithFallback(): Uid2Identity | null { + const localStorageIdentity = this._localStorageManager?.loadIdentityFromLocalStorage(); + const cookieIdentity = this._cookieManager?.loadIdentityFromCookie(); + const shouldUseCookie = cookieIdentity && (!localStorageIdentity || cookieIdentity.identity_expires > localStorageIdentity.identity_expires); + return shouldUseCookie ? cookieIdentity : localStorageIdentity ?? null; + }; + + public loadIdentity(): Uid2Identity | null { + return this._opts.useCookie + ? this._cookieManager?.loadIdentityFromCookie() ?? null + : this._localStorageManager?.loadIdentityFromLocalStorage() ?? null; + } + + public setValue(identity: Uid2Identity) { + if (this._opts.useCookie) { + this._cookieManager?.setCookie(identity); + } + else if (this._opts.useCookie === false) { + this._localStorageManager?.setValue(identity); + if (this._localStorageManager?.loadIdentityFromLocalStorage()) this._cookieManager?.removeCookie(); + } else { + this._localStorageManager?.setValue(identity); + } + } + + public removeValues() { + this._cookieManager?.removeCookie(); + this._localStorageManager?.removeValue(); + } +} From f5542c2f251ea17b0a453f6f34ad3a62df35d2c2 Mon Sep 17 00:00:00 2001 From: Alex Yau Date: Wed, 27 Sep 2023 17:03:02 +1000 Subject: [PATCH 12/21] Check for cookie/localStorage instead of cookie Also adjust the mock to return undefined instead of null for localStorage for parity with cookie mock --- src/integrationTests/autoRefresh.test.ts | 56 +++++++++++++----------- src/integrationTests/options.test.ts | 2 +- src/mocks.ts | 6 ++- 3 files changed, 36 insertions(+), 28 deletions(-) diff --git a/src/integrationTests/autoRefresh.test.ts b/src/integrationTests/autoRefresh.test.ts index e54958d..3a3d042 100644 --- a/src/integrationTests/autoRefresh.test.ts +++ b/src/integrationTests/autoRefresh.test.ts @@ -24,14 +24,18 @@ beforeEach(() => { xhrMock = new mocks.XhrMock(sdkWindow); _cryptoMock = new mocks.CryptoMock(sdkWindow); mocks.setCookieMock(sdkWindow.document); + removeUid2Cookie(); + removeUid2LocalStorage(); }); afterEach(() => { mocks.resetFakeTime(); }); -const getUid2Cookie = mocks.getUid2Cookie; +const getUid2 = mocks.getUid2; const makeIdentity = mocks.makeIdentityV2; +const removeUid2Cookie = mocks.removeUid2Cookie; +const removeUid2LocalStorage = mocks.removeUid2LocalStorage; let useCookie: boolean | undefined = undefined; @@ -66,7 +70,7 @@ testCookieAndLocalStorage(() => { getAdvertisingTokenPromise = uid2.getAdvertisingTokenAsync(); jest.clearAllMocks(); jest.runOnlyPendingTimers(); - uid2.init({ callback: callback, identity: originalIdentity }); + uid2.init({ callback: callback, identity: originalIdentity, useCookie: useCookie }); }); test("should invoke the callback", () => { @@ -102,7 +106,7 @@ testCookieAndLocalStorage(() => { }); beforeEach(() => { - uid2.init({ callback: callback, identity: originalIdentity }); + uid2.init({ callback: callback, identity: originalIdentity, useCookie: useCookie }); jest.clearAllMocks(); jest.setSystemTime(refreshFrom); jest.runOnlyPendingTimers(); @@ -141,8 +145,8 @@ testCookieAndLocalStorage(() => { }) ); }); - test("should set cookie", () => { - expect(getUid2Cookie().advertising_token).toBe( + test("should store value", () => { + expect(getUid2(useCookie).advertising_token).toBe( updatedIdentity.advertising_token ); }); @@ -188,8 +192,8 @@ testCookieAndLocalStorage(() => { }) ); }); - test("should clear cookie", () => { - expect(getUid2Cookie()).toBeUndefined(); + test("should clear value", () => { + expect(getUid2(useCookie)).toBeUndefined(); }); test("should not set refresh timer", () => { expect(setTimeout).not.toHaveBeenCalled(); @@ -227,8 +231,8 @@ testCookieAndLocalStorage(() => { }) ); }); - test("should clear cookie", () => { - expect(getUid2Cookie()).toBeUndefined(); + test("should clear value", () => { + expect(getUid2(useCookie)).toBeUndefined(); }); test("should not set refresh timer", () => { expect(setTimeout).not.toHaveBeenCalled(); @@ -260,8 +264,8 @@ testCookieAndLocalStorage(() => { ); }); - test("should not update cookie", () => { - expect(getUid2Cookie().advertising_token).toBe( + test("should not update value", () => { + expect(getUid2(useCookie).advertising_token).toBe( originalIdentity.advertising_token ); }); @@ -304,8 +308,8 @@ testCookieAndLocalStorage(() => { }) ); }); - test("should clear cookie", () => { - expect(getUid2Cookie()).toBeUndefined(); + test("should clear value", () => { + expect(getUid2(useCookie)).toBeUndefined(); }); test("should not set refresh timer", () => { expect(setTimeout).not.toHaveBeenCalled(); @@ -339,8 +343,8 @@ testCookieAndLocalStorage(() => { }) ); }); - test("should set cookie", () => { - expect(getUid2Cookie().advertising_token).toBe( + test("should store value", () => { + expect(getUid2(useCookie).advertising_token).toBe( manualSetIdentity.advertising_token ); }); @@ -374,7 +378,7 @@ testCookieAndLocalStorage(() => { }); beforeEach(() => { - uid2.init({ callback: callback, identity: originalIdentity }); + uid2.init({ callback: callback, identity: originalIdentity, useCookie: useCookie }); jest.clearAllMocks(); jest.setSystemTime(refreshFrom); jest.runOnlyPendingTimers(); @@ -413,8 +417,8 @@ testCookieAndLocalStorage(() => { }) ); }); - test("should set cookie", () => { - expect(getUid2Cookie().advertising_token).toBe( + test("should store value", () => { + expect(getUid2(useCookie).advertising_token).toBe( updatedIdentity.advertising_token ); }); @@ -459,8 +463,8 @@ testCookieAndLocalStorage(() => { }) ); }); - test("should clear cookie", () => { - expect(getUid2Cookie()).toBeUndefined(); + test("should clear value", () => { + expect(getUid2(useCookie)).toBeUndefined(); }); test("should not set refresh timer", () => { expect(setTimeout).not.toHaveBeenCalled(); @@ -498,8 +502,8 @@ testCookieAndLocalStorage(() => { }) ); }); - test("should clear cookie", () => { - expect(getUid2Cookie()).toBeUndefined(); + test("should clear value", () => { + expect(getUid2(useCookie)).toBeUndefined(); }); test("should not set refresh timer", () => { expect(setTimeout).not.toHaveBeenCalled(); @@ -528,8 +532,8 @@ testCookieAndLocalStorage(() => { test("getAdvertisingTokenPromise should reject", () => { expect(expection).toEqual(new Error("No identity available.")); }); - test("should not update cookie", () => { - expect(getUid2Cookie().advertising_token).toBe( + test("should not update value", () => { + expect(getUid2(useCookie).advertising_token).toBe( originalIdentity.advertising_token ); }); @@ -572,8 +576,8 @@ testCookieAndLocalStorage(() => { }) ); }); - test("should clear cookie", () => { - expect(getUid2Cookie()).toBeUndefined(); + test("should clear value", () => { + expect(getUid2(useCookie)).toBeUndefined(); }); test("should not set refresh timer", () => { expect(setTimeout).not.toHaveBeenCalled(); diff --git a/src/integrationTests/options.test.ts b/src/integrationTests/options.test.ts index 2433332..dd14aba 100644 --- a/src/integrationTests/options.test.ts +++ b/src/integrationTests/options.test.ts @@ -191,7 +191,7 @@ describe("useCookie option", () => { }); test("should set identity in cookie only", () => { expect(getUid2Cookie().advertising_token).toBe(identity.advertising_token); - expect(getUid2LocalStorage()).toBeNull(); + expect(getUid2LocalStorage()).toBeUndefined(); }); }); }); diff --git a/src/mocks.ts b/src/mocks.ts index 4cd1b5c..2c55155 100644 --- a/src/mocks.ts +++ b/src/mocks.ts @@ -157,6 +157,10 @@ export async function flushPromises() { await Promise.resolve(); } +export function getUid2(useCookie?: boolean) { + return useCookie ? getUid2Cookie() : getUid2LocalStorage(); +} + export function getUid2Cookie() { const docCookie = document.cookie; if (docCookie) { @@ -180,7 +184,7 @@ export function setUid2LocalStorage(identity: string) { export function getUid2LocalStorage() { const value = localStorage.getItem(localStorageKeyName); - return value !== null ? JSON.parse(value) : null; + return value !== null ? JSON.parse(value) : undefined; } export function setEuidCookie(value: any) { From 2b5e1ad33d4c327a4a0be64872fd27de559bf599 Mon Sep 17 00:00:00 2001 From: Alex Yau Date: Wed, 27 Sep 2023 17:04:21 +1000 Subject: [PATCH 13/21] Fix typo expection -> exception --- src/integrationTests/autoRefresh.test.ts | 46 ++++++++++++------------ 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/src/integrationTests/autoRefresh.test.ts b/src/integrationTests/autoRefresh.test.ts index 3a3d042..81ede29 100644 --- a/src/integrationTests/autoRefresh.test.ts +++ b/src/integrationTests/autoRefresh.test.ts @@ -168,7 +168,7 @@ testCookieAndLocalStorage(() => { }); describe("when token refresh returns optout", () => { - let expection: any; + let exception: any; beforeEach(async () => { try { getAdvertisingTokenPromise = uid2.getAdvertisingTokenAsync(); @@ -176,11 +176,11 @@ testCookieAndLocalStorage(() => { xhrMock.onreadystatechange(new Event("")); await getAdvertisingTokenPromise; } catch (err) { - expection = err; + exception = err; } }); test("getAdvertisingTokenPromise should reject", () => { - expect(expection).toEqual(new Error("UID2 SDK aborted.")); + expect(exception).toEqual(new Error("UID2 SDK aborted.")); }); test("should invoke the callback", () => { expect(callback).toHaveBeenNthCalledWith( @@ -205,7 +205,7 @@ testCookieAndLocalStorage(() => { }); describe("when token refresh returns refresh token expired", () => { - let expection: any; + let exception: any; beforeEach(async () => { try { getAdvertisingTokenPromise = uid2.getAdvertisingTokenAsync(); @@ -215,11 +215,11 @@ testCookieAndLocalStorage(() => { xhrMock.onreadystatechange(new Event("")); await getAdvertisingTokenPromise; } catch (err) { - expection = err; + exception = err; } }); test("getAdvertisingTokenPromise should reject", () => { - expect(expection).toEqual(new Error("UID2 SDK aborted.")); + expect(exception).toEqual(new Error("UID2 SDK aborted.")); }); test("should invoke the callback", () => { expect(callback).toHaveBeenNthCalledWith( @@ -244,7 +244,7 @@ testCookieAndLocalStorage(() => { }); describe("when token refresh returns an error status", () => { - let expection: any; + let exception: any; beforeEach(async () => { try { getAdvertisingTokenPromise = uid2.getAdvertisingTokenAsync(); @@ -255,7 +255,7 @@ testCookieAndLocalStorage(() => { xhrMock.onreadystatechange(new Event("")); await getAdvertisingTokenPromise; } catch (err) { - expection = err; + exception = err; } }); test("getAdvertisingTokenPromise should return current advertising token", async () => { @@ -281,7 +281,7 @@ testCookieAndLocalStorage(() => { }); describe("when token refresh fails and current identity expires", () => { - let expection: any; + let exception: any; beforeEach(async () => { try { getAdvertisingTokenPromise = uid2.getAdvertisingTokenAsync(); @@ -290,12 +290,12 @@ testCookieAndLocalStorage(() => { xhrMock.onreadystatechange(new Event("")); await getAdvertisingTokenPromise; } catch (err) { - expection = err; + exception = err; } }); test("getAdvertisingTokenPromise should reject", () => { - expect(expection).toEqual(new Error("UID2 SDK aborted.")); + expect(exception).toEqual(new Error("UID2 SDK aborted.")); }); test("should invoke the callback", () => { @@ -439,7 +439,7 @@ testCookieAndLocalStorage(() => { }); describe("when token refresh returns optout", () => { - let expection: any; + let exception: any; beforeEach(async () => { try { getAdvertisingTokenPromise = uid2.getAdvertisingTokenAsync(); @@ -447,11 +447,11 @@ testCookieAndLocalStorage(() => { xhrMock.onreadystatechange(new Event("")); await getAdvertisingTokenPromise; } catch (err) { - expection = err; + exception = err; } }); test("getAdvertisingTokenPromise should reject", () => { - expect(expection).toEqual(new Error("UID2 SDK aborted.")); + expect(exception).toEqual(new Error("UID2 SDK aborted.")); }); test("should invoke the callback", () => { expect(callback).toHaveBeenNthCalledWith( @@ -476,7 +476,7 @@ testCookieAndLocalStorage(() => { }); describe("when token refresh returns refresh token expired", () => { - let expection: any; + let exception: any; beforeEach(async () => { try { getAdvertisingTokenPromise = uid2.getAdvertisingTokenAsync(); @@ -486,11 +486,11 @@ testCookieAndLocalStorage(() => { xhrMock.onreadystatechange(new Event("")); await getAdvertisingTokenPromise; } catch (err) { - expection = err; + exception = err; } }); test("getAdvertisingTokenPromise should reject", () => { - expect(expection).toEqual(new Error("UID2 SDK aborted.")); + expect(exception).toEqual(new Error("UID2 SDK aborted.")); }); test("should invoke the callback", () => { expect(callback).toHaveBeenNthCalledWith( @@ -515,7 +515,7 @@ testCookieAndLocalStorage(() => { }); describe("when token refresh returns an error status", () => { - let expection: any; + let exception: any; beforeEach(async () => { try { getAdvertisingTokenPromise = uid2.getAdvertisingTokenAsync(); @@ -526,11 +526,11 @@ testCookieAndLocalStorage(() => { xhrMock.onreadystatechange(new Event("")); await getAdvertisingTokenPromise; } catch (err) { - expection = err; + exception = err; } }); test("getAdvertisingTokenPromise should reject", () => { - expect(expection).toEqual(new Error("No identity available.")); + expect(exception).toEqual(new Error("No identity available.")); }); test("should not update value", () => { expect(getUid2(useCookie).advertising_token).toBe( @@ -549,7 +549,7 @@ testCookieAndLocalStorage(() => { }); describe("when token refresh fails and current identity expires", () => { - let expection: any; + let exception: any; beforeEach(async () => { try { getAdvertisingTokenPromise = uid2.getAdvertisingTokenAsync(); @@ -558,12 +558,12 @@ testCookieAndLocalStorage(() => { xhrMock.onreadystatechange(new Event("")); await getAdvertisingTokenPromise; } catch (err) { - expection = err; + exception = err; } }); test("getAdvertisingTokenPromise should reject", () => { - expect(expection).toEqual(new Error("UID2 SDK aborted.")); + expect(exception).toEqual(new Error("UID2 SDK aborted.")); }); test("should invoke the callback", () => { From 7416a7be11c5a4d902e3bd08e89cf434242cc437 Mon Sep 17 00:00:00 2001 From: Alex Yau Date: Wed, 27 Sep 2023 17:44:34 +1000 Subject: [PATCH 14/21] use mock getUid2 for tests --- src/integrationTests/basic.test.ts | 176 ++++++--------------- src/integrationTests/compatibility.test.ts | 43 ++--- src/mocks.ts | 2 +- 3 files changed, 64 insertions(+), 157 deletions(-) diff --git a/src/integrationTests/basic.test.ts b/src/integrationTests/basic.test.ts index 3a0bb45..288bca1 100644 --- a/src/integrationTests/basic.test.ts +++ b/src/integrationTests/basic.test.ts @@ -30,11 +30,10 @@ afterEach(() => { }); const setUid2Cookie = mocks.setUid2Cookie; -const getUid2Cookie = mocks.getUid2Cookie; +const setUid2LocalStorage = mocks.setUid2LocalStorage; +const getUid2 = mocks.getUid2; const removeUid2Cookie = mocks.removeUid2Cookie; const removeUid2LocalStorage = mocks.removeUid2LocalStorage; -const setUid2LocalStorage = mocks.setUid2LocalStorage; -const getUid2LocalStorage = mocks.getUid2LocalStorage; const makeIdentityV1 = mocks.makeIdentityV1; const makeIdentityV2 = mocks.makeIdentityV2; @@ -165,8 +164,8 @@ testCookieAndLocalStorage(() => { }) ); }); - test("should not set cookie", () => { - expect(getUid2Cookie()).toBeUndefined(); + test("should not set value", () => { + expect(getUid2(useCookie)).toBeUndefined(); }); test("should not set refresh timer", () => { expect(setTimeout).not.toHaveBeenCalled(); @@ -179,7 +178,7 @@ testCookieAndLocalStorage(() => { describe("when uid2 cookie with invalid JSON is available", () => { beforeEach(() => { - setUid2Cookie({}); + setUid2Cookie({}); //todo? uid2.init({ callback: callback, useCookie: useCookie }); }); @@ -193,8 +192,8 @@ testCookieAndLocalStorage(() => { }) ); }); - test("should clear cookie", () => { - expect(getUid2Cookie()).toBeUndefined(); + test("should clear value", () => { + expect(getUid2(useCookie)).toBeUndefined(); }); test("should not set refresh timer", () => { expect(setTimeout).not.toHaveBeenCalled(); @@ -224,11 +223,7 @@ testCookieAndLocalStorage(() => { ); }); test("should set value", () => { - if (useCookie) { - expect(getUid2Cookie().advertising_token).toBe(identity.advertising_token); - } else { - expect(getUid2LocalStorage().advertising_token).toBe(identity.advertising_token); - } + expect(getUid2(useCookie).advertising_token).toBe(identity.advertising_token); }); test("should set refresh timer", () => { expect(setTimeout).toHaveBeenCalledTimes(1); @@ -259,8 +254,8 @@ testCookieAndLocalStorage(() => { }) ); }); - test("should clear cookie", () => { - expect(getUid2Cookie()).toBeUndefined(); + test("should clear value", () => { + expect(getUid2(useCookie)).toBeUndefined(); }); test("should not set refresh timer", () => { expect(setTimeout).not.toHaveBeenCalled(); @@ -373,8 +368,8 @@ testCookieAndLocalStorage(() => { }) ); }); - test("should clear cookie", () => { - expect(getUid2Cookie()).toBeUndefined(); + test("should clear value", () => { + expect(getUid2(useCookie)).toBeUndefined(); }); test("should not set refresh timer", () => { expect(setTimeout).not.toHaveBeenCalled(); @@ -403,16 +398,9 @@ testCookieAndLocalStorage(() => { ); }); test("should set value", () => { - if (useCookie) { - expect(getUid2Cookie().advertising_token).toBe( - identity.advertising_token - ); - } - else { - expect(getUid2LocalStorage().advertising_token).toBe( - identity.advertising_token - ); - } + expect(getUid2(useCookie).advertising_token).toBe( + identity.advertising_token + ); }); test("should set refresh timer", () => { expect(setTimeout).toHaveBeenCalledTimes(1); @@ -447,16 +435,9 @@ testCookieAndLocalStorage(() => { ); }); test("should set value", () => { - if (useCookie) { - expect(getUid2Cookie().advertising_token).toBe( - initIdentity.advertising_token - ); - } - else { - expect(getUid2LocalStorage().advertising_token).toBe( - initIdentity.advertising_token - ); - } + expect(getUid2(useCookie).advertising_token).toBe( + initIdentity.advertising_token + ); }); test("should set refresh timer", () => { expect(setTimeout).toHaveBeenCalledTimes(1); @@ -501,16 +482,9 @@ testCookieAndLocalStorage(() => { ); }); test("should set value", () => { - if (useCookie) { - expect(getUid2Cookie().advertising_token).toBe( - updatedIdentity.advertising_token - ); - } - else { - expect(getUid2LocalStorage().advertising_token).toBe( - updatedIdentity.advertising_token - ); - } + expect(getUid2(useCookie).advertising_token).toBe( + updatedIdentity.advertising_token + ); }); test("should set refresh timer", () => { expect(setTimeout).toHaveBeenCalledTimes(1); @@ -540,16 +514,9 @@ testCookieAndLocalStorage(() => { ); }); test("should set value", () => { - if (useCookie) { - expect(getUid2Cookie().advertising_token).toBe( - originalIdentity.advertising_token - ); - } - else { - expect(getUid2LocalStorage().advertising_token).toBe( - originalIdentity.advertising_token - ); - } + expect(getUid2(useCookie).advertising_token).toBe( + originalIdentity.advertising_token + ); }); test("should set refresh timer", () => { expect(setTimeout).toHaveBeenCalledTimes(1); @@ -578,7 +545,7 @@ testCookieAndLocalStorage(() => { ); }); test("should not set cookie", () => { - expect(getUid2Cookie()).toBeUndefined(); + expect(getUid2(useCookie)).toBeUndefined(); }); test("should not set refresh timer", () => { expect(setTimeout).not.toHaveBeenCalled(); @@ -606,7 +573,7 @@ testCookieAndLocalStorage(() => { ); }); test("should not set cookie", () => { - expect(getUid2Cookie()).toBeUndefined(); + expect(getUid2(useCookie)).toBeUndefined(); }); test("should not set refresh timer", () => { expect(setTimeout).not.toHaveBeenCalled(); @@ -637,16 +604,9 @@ testCookieAndLocalStorage(() => { ); }); test("should set value", () => { - if (useCookie) { - expect(getUid2Cookie().advertising_token).toBe( - originalIdentity.advertising_token - ); - } - else { - expect(getUid2LocalStorage().advertising_token).toBe( - originalIdentity.advertising_token - ); - } + expect(getUid2(useCookie).advertising_token).toBe( + originalIdentity.advertising_token + ); }); test("should set refresh timer", () => { expect(setTimeout).toHaveBeenCalledTimes(1); @@ -676,16 +636,9 @@ testCookieAndLocalStorage(() => { ); }); test("should set value", () => { - if (useCookie) { - expect(getUid2Cookie().advertising_token).toBe( - originalIdentity.advertising_token - ); - } - else { - expect(getUid2LocalStorage().advertising_token).toBe( - originalIdentity.advertising_token - ); - } + expect(getUid2(useCookie).advertising_token).toBe( + originalIdentity.advertising_token + ); }); test("should set refresh timer", () => { expect(setTimeout).toHaveBeenCalledTimes(1); @@ -715,16 +668,9 @@ testCookieAndLocalStorage(() => { ); }); test("should set value", () => { - if (useCookie) { - expect(getUid2Cookie().advertising_token).toBe( - originalIdentity.advertising_token - ); - } - else { - expect(getUid2LocalStorage().advertising_token).toBe( - originalIdentity.advertising_token - ); - } + expect(getUid2(useCookie).advertising_token).toBe( + originalIdentity.advertising_token + ); }); test("should set refresh timer", () => { expect(setTimeout).toHaveBeenCalledTimes(1); @@ -754,16 +700,9 @@ testCookieAndLocalStorage(() => { ); }); test("should set value", () => { - if (useCookie) { - expect(getUid2Cookie().advertising_token).toBe( - originalIdentity.advertising_token - ); - } - else { - expect(getUid2LocalStorage().advertising_token).toBe( - originalIdentity.advertising_token - ); - } + expect(getUid2(useCookie).advertising_token).toBe( + originalIdentity.advertising_token + ); }); test("should set refresh timer", () => { expect(setTimeout).toHaveBeenCalledTimes(1); @@ -793,7 +732,7 @@ testCookieAndLocalStorage(() => { ); }); test("should not set cookie", () => { - expect(getUid2Cookie()).toBeUndefined(); + expect(getUid2(useCookie)).toBeUndefined(); }); test("should not set refresh timer", () => { expect(setTimeout).not.toHaveBeenCalled(); @@ -838,16 +777,9 @@ testCookieAndLocalStorage(() => { ); }); test("should set value", () => { - if (useCookie) { - expect(getUid2Cookie().advertising_token).toBe( - updatedIdentity.advertising_token - ); - } - else { - expect(getUid2LocalStorage().advertising_token).toBe( - updatedIdentity.advertising_token - ); - } + expect(getUid2(useCookie).advertising_token).toBe( + updatedIdentity.advertising_token + ); }); test("should set refresh timer", () => { expect(setTimeout).toHaveBeenCalledTimes(1); @@ -876,7 +808,7 @@ testCookieAndLocalStorage(() => { ); }); test("should not set cookie", () => { - expect(getUid2Cookie()).toBeUndefined(); + expect(getUid2(useCookie)).toBeUndefined(); }); test("should not set refresh timer", () => { expect(setTimeout).not.toHaveBeenCalled(); @@ -905,7 +837,7 @@ testCookieAndLocalStorage(() => { ); }); test("should not set cookie", () => { - expect(getUid2Cookie()).toBeUndefined(); + expect(getUid2(useCookie)).toBeUndefined(); }); test("should not set refresh timer", () => { expect(setTimeout).not.toHaveBeenCalled(); @@ -936,16 +868,9 @@ testCookieAndLocalStorage(() => { ); }); test("should set value", () => { - if (useCookie) { - expect(getUid2Cookie().advertising_token).toBe( - originalIdentity.advertising_token - ); - } - else { - expect(getUid2LocalStorage().advertising_token).toBe( - originalIdentity.advertising_token - ); - } + expect(getUid2(useCookie).advertising_token).toBe( + originalIdentity.advertising_token + ); }); test("should set refresh timer", () => { expect(setTimeout).toHaveBeenCalledTimes(1); @@ -974,7 +899,7 @@ testCookieAndLocalStorage(() => { ); }); test("should not set cookie", () => { - expect(getUid2Cookie()).toBeUndefined(); + expect(getUid2(useCookie)).toBeUndefined(); }); test("should not set refresh timer", () => { expect(setTimeout).not.toHaveBeenCalled(); @@ -990,8 +915,9 @@ testCookieAndLocalStorage(() => { test("should not clear cookie", () => { const identity = makeIdentityV2(); setUid2Cookie(identity); + setUid2LocalStorage(identity); uid2.abort(); - expect(getUid2Cookie().advertising_token).toBe(identity.advertising_token); + expect(getUid2(useCookie).advertising_token).toBe(identity.advertising_token); }); test("should abort refresh timer", () => { uid2.init({ callback: callback, identity: makeIdentityV2(), useCookie: useCookie }); @@ -1035,7 +961,7 @@ testCookieAndLocalStorage(() => { test("should clear cookie", () => { setUid2Cookie(makeIdentityV2()); uid2.disconnect(); - expect(getUid2Cookie()).toBeUndefined(); + expect(getUid2(useCookie)).toBeUndefined(); }); test("should abort refresh timer", () => { uid2.init({ callback: callback, identity: makeIdentityV2(), useCookie: useCookie }); diff --git a/src/integrationTests/compatibility.test.ts b/src/integrationTests/compatibility.test.ts index 7afac76..c9d76d2 100644 --- a/src/integrationTests/compatibility.test.ts +++ b/src/integrationTests/compatibility.test.ts @@ -28,8 +28,7 @@ afterEach(() => { }); const setUid2Cookie = mocks.setUid2Cookie; -const getUid2Cookie = mocks.getUid2Cookie; -const getUid2LocalStorage = mocks.getUid2LocalStorage; +const getUid2 = mocks.getUid2; const makeIdentity = mocks.makeIdentityV2; let useCookie: boolean | undefined = undefined; @@ -100,11 +99,7 @@ testCookieAndLocalStorage(() => { ); }); test("should set value", () => { - if (useCookie) { - expect(getUid2Cookie().advertising_token).toBe(updatedIdentity.advertising_token); - } else { - expect(getUid2LocalStorage().advertising_token).toBe(updatedIdentity.advertising_token); - } + expect(getUid2(useCookie).advertising_token).toBe(updatedIdentity.advertising_token); }); test("should set refresh timer", () => { expect(setTimeout).toHaveBeenCalledTimes(1); @@ -137,30 +132,16 @@ testCookieAndLocalStorage(() => { ); }); test("should set enriched value", () => { - if (useCookie) { - const cookie = getUid2Cookie(); - expect(cookie.refresh_token).toBe( - originalIdentity.refresh_token - ); - expect(cookie.refresh_from).toBe(Date.now()); - expect(cookie.identity_expires).toBeGreaterThan(Date.now()); - expect(cookie.refresh_expires).toBeGreaterThan(Date.now()); - expect(cookie.identity_expires).toBeLessThan( - cookie.refresh_expires - ); - } - else { - const localStorageValue = getUid2LocalStorage(); - expect(localStorageValue.refresh_token).toBe( - originalIdentity.refresh_token - ); - expect(localStorageValue.refresh_from).toBe(Date.now()); - expect(localStorageValue.identity_expires).toBeGreaterThan(Date.now()); - expect(localStorageValue.refresh_expires).toBeGreaterThan(Date.now()); - expect(localStorageValue.identity_expires).toBeLessThan( - localStorageValue.refresh_expires - ); - } + const value = getUid2(useCookie); + expect(value.refresh_token).toBe( + originalIdentity.refresh_token + ); + expect(value.refresh_from).toBe(Date.now()); + expect(value.identity_expires).toBeGreaterThan(Date.now()); + expect(value.refresh_expires).toBeGreaterThan(Date.now()); + expect(value.identity_expires).toBeLessThan( + value.refresh_expires + ); }); test("should set refresh timer", () => { expect(setTimeout).toHaveBeenCalledTimes(1); diff --git a/src/mocks.ts b/src/mocks.ts index 2c55155..6ef67b2 100644 --- a/src/mocks.ts +++ b/src/mocks.ts @@ -177,7 +177,7 @@ export function removeUid2LocalStorage() { localStorage.removeItem(localStorageKeyName); } -export function setUid2LocalStorage(identity: string) { +export function setUid2LocalStorage(identity: any) { const value = JSON.stringify(identity); localStorage.setItem(localStorageKeyName, value); } From c9c312cefedf9f5e775ed84d9d9bce9bc39392bc Mon Sep 17 00:00:00 2001 From: Alex Yau Date: Thu, 28 Sep 2023 10:55:01 +1000 Subject: [PATCH 15/21] Use setUid2 instead of setting cookie & identity --- src/integrationTests/basic.test.ts | 36 ++++++++++++++---------------- src/mocks.ts | 4 ++++ 2 files changed, 21 insertions(+), 19 deletions(-) diff --git a/src/integrationTests/basic.test.ts b/src/integrationTests/basic.test.ts index 288bca1..0851462 100644 --- a/src/integrationTests/basic.test.ts +++ b/src/integrationTests/basic.test.ts @@ -29,9 +29,8 @@ afterEach(() => { mocks.resetFakeTime(); }); -const setUid2Cookie = mocks.setUid2Cookie; -const setUid2LocalStorage = mocks.setUid2LocalStorage; const getUid2 = mocks.getUid2; +const setUid2 = mocks.setUid2; const removeUid2Cookie = mocks.removeUid2Cookie; const removeUid2LocalStorage = mocks.removeUid2LocalStorage; const makeIdentityV1 = mocks.makeIdentityV1; @@ -149,7 +148,7 @@ testCookieAndLocalStorage(() => { }); describe("when initialised without identity", () => { - describe("when uid2 cookie is not available", () => { + describe("when uid2 value is not available", () => { beforeEach(() => { uid2.init({ callback: callback, useCookie: useCookie }); }); @@ -176,9 +175,9 @@ testCookieAndLocalStorage(() => { }); }); - describe("when uid2 cookie with invalid JSON is available", () => { + describe("when uid2 value with invalid JSON is available", () => { beforeEach(() => { - setUid2Cookie({}); //todo? + setUid2({}, useCookie); uid2.init({ callback: callback, useCookie: useCookie }); }); @@ -204,11 +203,11 @@ testCookieAndLocalStorage(() => { }); }); - describe("when uid2 cookie with up-to-date identity is available v2", () => { + describe("when uid2 value with up-to-date identity is available v2", () => { const identity = makeIdentityV2(); beforeEach(() => { - setUid2Cookie(identity); + setUid2(identity, useCookie); uid2.init({ callback: callback, useCookie: useCookie }); }); @@ -240,7 +239,7 @@ testCookieAndLocalStorage(() => { }); beforeEach(() => { - setUid2Cookie(identity); + setUid2(identity, useCookie); uid2.init({ callback: callback, useCookie: useCookie }); }); @@ -272,7 +271,7 @@ testCookieAndLocalStorage(() => { }); beforeEach(() => { - setUid2Cookie(identity); + setUid2(identity, useCookie); uid2.init({ callback: callback, useCookie: useCookie }); }); @@ -300,7 +299,7 @@ testCookieAndLocalStorage(() => { xhrMock.open.mockClear(); xhrMock.send.mockClear(); cryptoMock = new mocks.CryptoMock(sdkWindow); - setUid2Cookie(identity); + setUid2(identity, useCookie); uid2.init({ callback: callback, useCookie: useCookie }); }); @@ -334,7 +333,7 @@ testCookieAndLocalStorage(() => { }); beforeEach(() => { - setUid2Cookie(identity); + setUid2(identity, useCookie); uid2.init({ callback: callback, useCookie: useCookie }); }); @@ -380,7 +379,7 @@ testCookieAndLocalStorage(() => { }); }); - describe("when valid v2 identity is supplied and using cookie", () => { + describe("when valid v2 identity is supplied", () => { const identity = makeIdentityV2(); beforeEach(() => { @@ -411,16 +410,16 @@ testCookieAndLocalStorage(() => { }); }); - describe("when valid identity is supplied and cookie is available", () => { + describe("when valid identity is supplied and existing value is available", () => { const initIdentity = makeIdentityV2({ advertising_token: "init_advertising_token", }); - const cookieIdentity = makeIdentityV2({ - advertising_token: "cookie_advertising_token", + const existingIdentity = makeIdentityV2({ + advertising_token: "existing_advertising_token", }); beforeEach(() => { - setUid2Cookie(cookieIdentity); + setUid2(existingIdentity, useCookie); uid2.init({ callback: callback, identity: initIdentity, useCookie: useCookie }); }); @@ -914,8 +913,7 @@ testCookieAndLocalStorage(() => { describe("abort()", () => { test("should not clear cookie", () => { const identity = makeIdentityV2(); - setUid2Cookie(identity); - setUid2LocalStorage(identity); + setUid2(identity, useCookie); uid2.abort(); expect(getUid2(useCookie).advertising_token).toBe(identity.advertising_token); }); @@ -959,7 +957,7 @@ testCookieAndLocalStorage(() => { describe("disconnect()", () => { test("should clear cookie", () => { - setUid2Cookie(makeIdentityV2()); + setUid2(makeIdentityV2(), useCookie); uid2.disconnect(); expect(getUid2(useCookie)).toBeUndefined(); }); diff --git a/src/mocks.ts b/src/mocks.ts index 6ef67b2..d8ef834 100644 --- a/src/mocks.ts +++ b/src/mocks.ts @@ -161,6 +161,10 @@ export function getUid2(useCookie?: boolean) { return useCookie ? getUid2Cookie() : getUid2LocalStorage(); } +export function setUid2(value: any, useCookie?: boolean) { + return useCookie ? setUid2Cookie(value) : setUid2LocalStorage(value); +} + export function getUid2Cookie() { const docCookie = document.cookie; if (docCookie) { From bf795195bdb1218b1e77de98a196bee380ea31c6 Mon Sep 17 00:00:00 2001 From: Alex Yau Date: Thu, 28 Sep 2023 14:27:51 +1000 Subject: [PATCH 16/21] Rename method that loads identity --- src/uid2StorageManager.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/uid2StorageManager.ts b/src/uid2StorageManager.ts index 5b96834..5aa2b59 100644 --- a/src/uid2StorageManager.ts +++ b/src/uid2StorageManager.ts @@ -15,7 +15,7 @@ export class UID2StorageManager { this._localStorageManager = new UID2LocalStorageManager(); } - public loadIdentityFromPreferredStorageWithFallback(): Uid2Identity | null { + public loadIdentityWithFallback(): Uid2Identity | null { const localStorageIdentity = this._localStorageManager?.loadIdentityFromLocalStorage(); const cookieIdentity = this._cookieManager?.loadIdentityFromCookie(); const shouldUseCookie = cookieIdentity && (!localStorageIdentity || cookieIdentity.identity_expires > localStorageIdentity.identity_expires); From b78fe2643617e1b925ab7f167f51263ee890c9f7 Mon Sep 17 00:00:00 2001 From: Alex Yau Date: Thu, 28 Sep 2023 14:55:09 +1000 Subject: [PATCH 17/21] Addressing feedback - Clean up imports - Rename usage of loadIdentityFromPreferredStorageWithFallback - Return early in `setValue` method --- src/uid2Sdk.ts | 20 +++++++++----------- src/uid2StorageManager.ts | 15 ++++++++------- 2 files changed, 17 insertions(+), 18 deletions(-) diff --git a/src/uid2Sdk.ts b/src/uid2Sdk.ts index dcf36ae..b3f503c 100644 --- a/src/uid2Sdk.ts +++ b/src/uid2Sdk.ts @@ -1,23 +1,21 @@ +import { version } from "../package.json"; +import { Uid2Identity } from "./Uid2Identity"; +import { IdentityStatus, notifyInitCallback } from "./Uid2InitCallbacks"; +import { Uid2Options, isUID2OptionsOrThrow } from "./Uid2Options"; import { Uid2ApiClient } from "./uid2ApiClient"; +import { bytesToBase64 } from "./uid2Base64"; import { EventType, Uid2CallbackHandler, Uid2CallbackManager, } from "./uid2CallbackManager"; -import { UID2CookieManager } from "./uid2CookieManager"; -import { Uid2Identity } from "./Uid2Identity"; -import { IdentityStatus, notifyInitCallback } from "./Uid2InitCallbacks"; -import { isUID2OptionsOrThrow, Uid2Options } from "./Uid2Options"; -import { UID2PromiseHandler } from "./uid2PromiseHandler"; -import { version } from "../package.json"; -import { isBase64Hash } from "./uid2HashedDii"; -import { isNormalizedPhone, normalizeEmail } from "./uid2DiiNormalization"; import { ClientSideIdentityOptions, isClientSideIdentityOptionsOrThrow, } from "./uid2ClientSideIdentityOptions"; -import { bytesToBase64 } from "./uid2Base64"; -import { UID2LocalStorageManager } from "./uid2LocalStorageManager"; +import { isNormalizedPhone, normalizeEmail } from "./uid2DiiNormalization"; +import { isBase64Hash } from "./uid2HashedDii"; +import { UID2PromiseHandler } from "./uid2PromiseHandler"; import { UID2StorageManager } from "./uid2StorageManager"; function hasExpired(expiry: number, now = Date.now()) { @@ -228,7 +226,7 @@ export class UID2 { if (this._opts.identity) { identity = this._opts.identity; } else { - identity = this._storageManager.loadIdentityFromPreferredStorageWithFallback(); + identity = this._storageManager.loadIdentityWithFallback(); } const validatedIdentity = this.validateAndSetIdentity(identity); if (validatedIdentity) this.triggerRefreshOrSetTimer(validatedIdentity); diff --git a/src/uid2StorageManager.ts b/src/uid2StorageManager.ts index 5aa2b59..689ba8e 100644 --- a/src/uid2StorageManager.ts +++ b/src/uid2StorageManager.ts @@ -1,6 +1,5 @@ -import { UID2 } from "./uid2Sdk"; -import { isValidIdentity, Uid2Identity } from "./Uid2Identity"; import { UID2CookieManager } from "./uid2CookieManager"; +import { Uid2Identity } from "./Uid2Identity"; import { UID2LocalStorageManager } from "./uid2LocalStorageManager"; import { Uid2Options } from "./Uid2Options"; @@ -31,12 +30,14 @@ export class UID2StorageManager { public setValue(identity: Uid2Identity) { if (this._opts.useCookie) { this._cookieManager?.setCookie(identity); + return; } - else if (this._opts.useCookie === false) { - this._localStorageManager?.setValue(identity); - if (this._localStorageManager?.loadIdentityFromLocalStorage()) this._cookieManager?.removeCookie(); - } else { - this._localStorageManager?.setValue(identity); + + this._localStorageManager?.setValue(identity); + if (this._opts.useCookie === false && + this._localStorageManager?.loadIdentityFromLocalStorage() + ) { + this._cookieManager?.removeCookie(); } } From f9d20aed4f463c11b1d1a46664a216f21efc3375 Mon Sep 17 00:00:00 2001 From: Alex Yau Date: Fri, 29 Sep 2023 13:21:25 +1000 Subject: [PATCH 18/21] Addressing comments - Use localStorageManager methods in mocks or in tests directly - Remove ununsed imports --- src/Uid2Identity.ts | 2 +- src/integrationTests/async.spec.ts | 8 +++---- src/integrationTests/autoRefresh.test.ts | 6 ++--- src/integrationTests/basic.test.ts | 11 ++++----- src/integrationTests/options.test.ts | 13 ++++++----- src/mocks.ts | 29 +++++++----------------- 6 files changed, 26 insertions(+), 43 deletions(-) diff --git a/src/Uid2Identity.ts b/src/Uid2Identity.ts index b76bc65..8676a8d 100644 --- a/src/Uid2Identity.ts +++ b/src/Uid2Identity.ts @@ -5,7 +5,7 @@ interface IdentityBase { refresh_token: string; refresh_expires: number; } -interface IdentityV2 extends IdentityBase { +export interface IdentityV2 extends IdentityBase { // eslint-disable-next-line camelcase refresh_response_key: string; } diff --git a/src/integrationTests/async.spec.ts b/src/integrationTests/async.spec.ts index 810af33..8950f3e 100644 --- a/src/integrationTests/async.spec.ts +++ b/src/integrationTests/async.spec.ts @@ -10,12 +10,14 @@ import { import * as mocks from "../mocks"; import { __uid2InternalHandleScriptLoad, sdkWindow, UID2 } from "../uid2Sdk"; import { EventType } from "../uid2CallbackManager"; +import { UID2StorageManager } from "../uid2StorageManager"; let callback: any; let uid2: UID2; let xhrMock: any; let _cryptoMock: any; mocks.setupFakeTime(); +const uid2StorageManager = new UID2StorageManager({}); beforeEach(() => { callback = jest.fn(); @@ -23,17 +25,13 @@ beforeEach(() => { xhrMock = new mocks.XhrMock(sdkWindow); _cryptoMock = new mocks.CryptoMock(sdkWindow); mocks.setCookieMock(sdkWindow.document); - removeUid2Cookie(); - removeUid2LocalStorage(); + uid2StorageManager.removeValues(); }); afterEach(() => { mocks.resetFakeTime(); }); -const removeUid2Cookie = mocks.removeUid2Cookie; -const removeUid2LocalStorage = mocks.removeUid2LocalStorage; - const makeIdentity = mocks.makeIdentityV2; let useCookie: boolean | undefined = undefined; diff --git a/src/integrationTests/autoRefresh.test.ts b/src/integrationTests/autoRefresh.test.ts index 81ede29..9977c7a 100644 --- a/src/integrationTests/autoRefresh.test.ts +++ b/src/integrationTests/autoRefresh.test.ts @@ -9,6 +9,7 @@ import { import * as mocks from "../mocks"; import { sdkWindow, UID2 } from "../uid2Sdk"; +import { UID2StorageManager } from "../uid2StorageManager"; let callback: any; let uid2: UID2; @@ -17,6 +18,7 @@ let _cryptoMock; let getAdvertisingTokenPromise: Promise; mocks.setupFakeTime(); +const uid2StorageManager = new UID2StorageManager({}); beforeEach(() => { callback = jest.fn(); @@ -24,8 +26,6 @@ beforeEach(() => { xhrMock = new mocks.XhrMock(sdkWindow); _cryptoMock = new mocks.CryptoMock(sdkWindow); mocks.setCookieMock(sdkWindow.document); - removeUid2Cookie(); - removeUid2LocalStorage(); }); afterEach(() => { @@ -34,8 +34,6 @@ afterEach(() => { const getUid2 = mocks.getUid2; const makeIdentity = mocks.makeIdentityV2; -const removeUid2Cookie = mocks.removeUid2Cookie; -const removeUid2LocalStorage = mocks.removeUid2LocalStorage; let useCookie: boolean | undefined = undefined; diff --git a/src/integrationTests/basic.test.ts b/src/integrationTests/basic.test.ts index 0851462..4ba1eff 100644 --- a/src/integrationTests/basic.test.ts +++ b/src/integrationTests/basic.test.ts @@ -9,20 +9,23 @@ import { import * as mocks from "../mocks"; import { sdkWindow, UID2 } from "../uid2Sdk"; +import { UID2StorageManager } from "../uid2StorageManager"; let callback: any; let uid2: UID2; let xhrMock: any; mocks.setupFakeTime(); +const uid2StorageManager = new UID2StorageManager({}); + +let useCookie: boolean | undefined = undefined; beforeEach(() => { callback = jest.fn(); uid2 = new UID2(); xhrMock = new mocks.XhrMock(sdkWindow); mocks.setCookieMock(sdkWindow.document); - removeUid2Cookie(); - removeUid2LocalStorage(); + uid2StorageManager.removeValues(); }); afterEach(() => { @@ -31,13 +34,9 @@ afterEach(() => { const getUid2 = mocks.getUid2; const setUid2 = mocks.setUid2; -const removeUid2Cookie = mocks.removeUid2Cookie; -const removeUid2LocalStorage = mocks.removeUid2LocalStorage; const makeIdentityV1 = mocks.makeIdentityV1; const makeIdentityV2 = mocks.makeIdentityV2; -let useCookie: boolean | undefined = undefined; - const testCookieAndLocalStorage = (test: () => void, only = false) => { const describeFn = only ? describe.only : describe; describeFn('Using default: ', () => { diff --git a/src/integrationTests/options.test.ts b/src/integrationTests/options.test.ts index dd14aba..1a17a1a 100644 --- a/src/integrationTests/options.test.ts +++ b/src/integrationTests/options.test.ts @@ -9,6 +9,7 @@ import { import * as mocks from "../mocks"; import { sdkWindow, UID2 } from "../uid2Sdk"; +import { UID2StorageManager } from "../uid2StorageManager"; let callback: any; let uid2: UID2; @@ -20,14 +21,15 @@ mocks.setupFakeTime(); const mockDomain = "www.uidapi.com"; const mockUrl = `http://${mockDomain}/test/index.html`; +const uid2StorageManager = new UID2StorageManager({}); + beforeEach(() => { callback = jest.fn(); uid2 = new UID2(); xhrMock = new mocks.XhrMock(sdkWindow); jest.spyOn(document, "URL", "get").mockImplementation(() => mockUrl); cookieMock = new mocks.CookieMock(sdkWindow.document); - removeUid2Cookie(); - removeUid2LocalStorage(); + uid2StorageManager.removeValues(); }); afterEach(() => { @@ -37,8 +39,7 @@ afterEach(() => { const makeIdentity = mocks.makeIdentityV2; const getUid2Cookie = mocks.getUid2Cookie; const getUid2LocalStorage = mocks.getUid2LocalStorage; -const removeUid2Cookie = mocks.removeUid2Cookie; -const removeUid2LocalStorage = mocks.removeUid2LocalStorage; +const setUid2Cookie = mocks.setUid2Cookie; describe("cookieDomain option", () => { describe("when using default value", () => { @@ -173,7 +174,7 @@ describe("useCookie option", () => { uid2.init({ callback: callback, identity: identity }); }); test("should set identity in local storage", () => { - expect(getUid2LocalStorage().advertising_token).toBe(identity.advertising_token); + expect(getUid2LocalStorage()?.advertising_token).toBe(identity.advertising_token); }); }); describe("when useCookie is false", () => { @@ -181,7 +182,7 @@ describe("useCookie option", () => { uid2.init({ callback: callback, identity: identity, useCookie: false }); }); test("should set identity in local storage only", () => { - expect(getUid2LocalStorage().advertising_token).toBe(identity.advertising_token); + expect(getUid2LocalStorage()?.advertising_token).toBe(identity.advertising_token); expect(getUid2Cookie()).toBeUndefined(); }); }); diff --git a/src/mocks.ts b/src/mocks.ts index d8ef834..9716bca 100644 --- a/src/mocks.ts +++ b/src/mocks.ts @@ -1,8 +1,8 @@ import * as jsdom from "jsdom"; import { Cookie } from "tough-cookie"; +import { IdentityV2, Uid2Identity } from "./Uid2Identity"; +import { UID2LocalStorageManager } from "./uid2LocalStorageManager"; import { UID2 } from "./uid2Sdk"; -import { Uid2Identity } from "./Uid2Identity"; -import { localStorageKeyName } from "./uid2LocalStorageManager"; export class CookieMock { jar: jsdom.CookieJar; @@ -122,6 +122,8 @@ export class CryptoMock { } } +const uid2LocalStorageManager = new UID2LocalStorageManager(); + export function setupFakeTime() { jest.useFakeTimers(); jest.spyOn(global, "setTimeout"); @@ -147,11 +149,6 @@ export function setUid2Cookie(value: any) { UID2.COOKIE_NAME + "=" + encodeURIComponent(JSON.stringify(value)); } -export function removeUid2Cookie() { - document.cookie = - document.cookie + "=;expires=Tue, 1 Jan 1980 23:59:59 GMT"; -} - export async function flushPromises() { await Promise.resolve(); await Promise.resolve(); @@ -161,8 +158,8 @@ export function getUid2(useCookie?: boolean) { return useCookie ? getUid2Cookie() : getUid2LocalStorage(); } -export function setUid2(value: any, useCookie?: boolean) { - return useCookie ? setUid2Cookie(value) : setUid2LocalStorage(value); +export function setUid2(identity: any, useCookie?: boolean) { + return useCookie ? setUid2Cookie(identity) : uid2LocalStorageManager.setValue(identity); } export function getUid2Cookie() { @@ -177,18 +174,8 @@ export function getUid2Cookie() { } } -export function removeUid2LocalStorage() { - localStorage.removeItem(localStorageKeyName); -} - -export function setUid2LocalStorage(identity: any) { - const value = JSON.stringify(identity); - localStorage.setItem(localStorageKeyName, value); -} - -export function getUid2LocalStorage() { - const value = localStorage.getItem(localStorageKeyName); - return value !== null ? JSON.parse(value) : undefined; +export function getUid2LocalStorage(): IdentityV2 | null | undefined { + return uid2LocalStorageManager.loadIdentityFromLocalStorage() ?? undefined; } export function setEuidCookie(value: any) { From 5311892c836b995ba803885ccfbe9f6ae57b51e1 Mon Sep 17 00:00:00 2001 From: Alex Yau Date: Wed, 4 Oct 2023 16:57:33 +1100 Subject: [PATCH 19/21] Address feedback Drop | undefined from managers inside UID2StorageManager and associted null coalescing. Was not necessary and gave confusing code coverage insights --- src/uid2StorageManager.ts | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/uid2StorageManager.ts b/src/uid2StorageManager.ts index 689ba8e..18850a1 100644 --- a/src/uid2StorageManager.ts +++ b/src/uid2StorageManager.ts @@ -4,8 +4,8 @@ import { UID2LocalStorageManager } from "./uid2LocalStorageManager"; import { Uid2Options } from "./Uid2Options"; export class UID2StorageManager { - private _cookieManager: UID2CookieManager | undefined; - private _localStorageManager: UID2LocalStorageManager | undefined; + private _cookieManager: UID2CookieManager; + private _localStorageManager: UID2LocalStorageManager; private _opts: Uid2Options; constructor(opts: Uid2Options) { @@ -15,34 +15,34 @@ export class UID2StorageManager { } public loadIdentityWithFallback(): Uid2Identity | null { - const localStorageIdentity = this._localStorageManager?.loadIdentityFromLocalStorage(); - const cookieIdentity = this._cookieManager?.loadIdentityFromCookie(); + const localStorageIdentity = this._localStorageManager.loadIdentityFromLocalStorage(); + const cookieIdentity = this._cookieManager.loadIdentityFromCookie(); const shouldUseCookie = cookieIdentity && (!localStorageIdentity || cookieIdentity.identity_expires > localStorageIdentity.identity_expires); - return shouldUseCookie ? cookieIdentity : localStorageIdentity ?? null; + return shouldUseCookie ? cookieIdentity : localStorageIdentity; }; public loadIdentity(): Uid2Identity | null { return this._opts.useCookie - ? this._cookieManager?.loadIdentityFromCookie() ?? null - : this._localStorageManager?.loadIdentityFromLocalStorage() ?? null; + ? this._cookieManager.loadIdentityFromCookie() + : this._localStorageManager.loadIdentityFromLocalStorage(); } public setValue(identity: Uid2Identity) { if (this._opts.useCookie) { - this._cookieManager?.setCookie(identity); + this._cookieManager.setCookie(identity); return; } - this._localStorageManager?.setValue(identity); + this._localStorageManager.setValue(identity); if (this._opts.useCookie === false && - this._localStorageManager?.loadIdentityFromLocalStorage() + this._localStorageManager.loadIdentityFromLocalStorage() ) { - this._cookieManager?.removeCookie(); + this._cookieManager.removeCookie(); } } public removeValues() { - this._cookieManager?.removeCookie(); - this._localStorageManager?.removeValue(); + this._cookieManager.removeCookie(); + this._localStorageManager.removeValue(); } } From fe714e3c357a5a4f20f6e1ded5adf1736e7720bc Mon Sep 17 00:00:00 2001 From: Alex Yau Date: Thu, 5 Oct 2023 14:27:21 +1100 Subject: [PATCH 20/21] Revert "Addressing comments" This reverts commit f9d20aed4f463c11b1d1a46664a216f21efc3375. --- src/Uid2Identity.ts | 2 +- src/integrationTests/async.spec.ts | 8 ++++--- src/integrationTests/autoRefresh.test.ts | 6 +++-- src/integrationTests/basic.test.ts | 11 +++++---- src/integrationTests/options.test.ts | 13 +++++------ src/mocks.ts | 29 +++++++++++++++++------- 6 files changed, 43 insertions(+), 26 deletions(-) diff --git a/src/Uid2Identity.ts b/src/Uid2Identity.ts index 8676a8d..b76bc65 100644 --- a/src/Uid2Identity.ts +++ b/src/Uid2Identity.ts @@ -5,7 +5,7 @@ interface IdentityBase { refresh_token: string; refresh_expires: number; } -export interface IdentityV2 extends IdentityBase { +interface IdentityV2 extends IdentityBase { // eslint-disable-next-line camelcase refresh_response_key: string; } diff --git a/src/integrationTests/async.spec.ts b/src/integrationTests/async.spec.ts index 8950f3e..810af33 100644 --- a/src/integrationTests/async.spec.ts +++ b/src/integrationTests/async.spec.ts @@ -10,14 +10,12 @@ import { import * as mocks from "../mocks"; import { __uid2InternalHandleScriptLoad, sdkWindow, UID2 } from "../uid2Sdk"; import { EventType } from "../uid2CallbackManager"; -import { UID2StorageManager } from "../uid2StorageManager"; let callback: any; let uid2: UID2; let xhrMock: any; let _cryptoMock: any; mocks.setupFakeTime(); -const uid2StorageManager = new UID2StorageManager({}); beforeEach(() => { callback = jest.fn(); @@ -25,13 +23,17 @@ beforeEach(() => { xhrMock = new mocks.XhrMock(sdkWindow); _cryptoMock = new mocks.CryptoMock(sdkWindow); mocks.setCookieMock(sdkWindow.document); - uid2StorageManager.removeValues(); + removeUid2Cookie(); + removeUid2LocalStorage(); }); afterEach(() => { mocks.resetFakeTime(); }); +const removeUid2Cookie = mocks.removeUid2Cookie; +const removeUid2LocalStorage = mocks.removeUid2LocalStorage; + const makeIdentity = mocks.makeIdentityV2; let useCookie: boolean | undefined = undefined; diff --git a/src/integrationTests/autoRefresh.test.ts b/src/integrationTests/autoRefresh.test.ts index 9977c7a..81ede29 100644 --- a/src/integrationTests/autoRefresh.test.ts +++ b/src/integrationTests/autoRefresh.test.ts @@ -9,7 +9,6 @@ import { import * as mocks from "../mocks"; import { sdkWindow, UID2 } from "../uid2Sdk"; -import { UID2StorageManager } from "../uid2StorageManager"; let callback: any; let uid2: UID2; @@ -18,7 +17,6 @@ let _cryptoMock; let getAdvertisingTokenPromise: Promise; mocks.setupFakeTime(); -const uid2StorageManager = new UID2StorageManager({}); beforeEach(() => { callback = jest.fn(); @@ -26,6 +24,8 @@ beforeEach(() => { xhrMock = new mocks.XhrMock(sdkWindow); _cryptoMock = new mocks.CryptoMock(sdkWindow); mocks.setCookieMock(sdkWindow.document); + removeUid2Cookie(); + removeUid2LocalStorage(); }); afterEach(() => { @@ -34,6 +34,8 @@ afterEach(() => { const getUid2 = mocks.getUid2; const makeIdentity = mocks.makeIdentityV2; +const removeUid2Cookie = mocks.removeUid2Cookie; +const removeUid2LocalStorage = mocks.removeUid2LocalStorage; let useCookie: boolean | undefined = undefined; diff --git a/src/integrationTests/basic.test.ts b/src/integrationTests/basic.test.ts index 4ba1eff..0851462 100644 --- a/src/integrationTests/basic.test.ts +++ b/src/integrationTests/basic.test.ts @@ -9,23 +9,20 @@ import { import * as mocks from "../mocks"; import { sdkWindow, UID2 } from "../uid2Sdk"; -import { UID2StorageManager } from "../uid2StorageManager"; let callback: any; let uid2: UID2; let xhrMock: any; mocks.setupFakeTime(); -const uid2StorageManager = new UID2StorageManager({}); - -let useCookie: boolean | undefined = undefined; beforeEach(() => { callback = jest.fn(); uid2 = new UID2(); xhrMock = new mocks.XhrMock(sdkWindow); mocks.setCookieMock(sdkWindow.document); - uid2StorageManager.removeValues(); + removeUid2Cookie(); + removeUid2LocalStorage(); }); afterEach(() => { @@ -34,9 +31,13 @@ afterEach(() => { const getUid2 = mocks.getUid2; const setUid2 = mocks.setUid2; +const removeUid2Cookie = mocks.removeUid2Cookie; +const removeUid2LocalStorage = mocks.removeUid2LocalStorage; const makeIdentityV1 = mocks.makeIdentityV1; const makeIdentityV2 = mocks.makeIdentityV2; +let useCookie: boolean | undefined = undefined; + const testCookieAndLocalStorage = (test: () => void, only = false) => { const describeFn = only ? describe.only : describe; describeFn('Using default: ', () => { diff --git a/src/integrationTests/options.test.ts b/src/integrationTests/options.test.ts index 1a17a1a..dd14aba 100644 --- a/src/integrationTests/options.test.ts +++ b/src/integrationTests/options.test.ts @@ -9,7 +9,6 @@ import { import * as mocks from "../mocks"; import { sdkWindow, UID2 } from "../uid2Sdk"; -import { UID2StorageManager } from "../uid2StorageManager"; let callback: any; let uid2: UID2; @@ -21,15 +20,14 @@ mocks.setupFakeTime(); const mockDomain = "www.uidapi.com"; const mockUrl = `http://${mockDomain}/test/index.html`; -const uid2StorageManager = new UID2StorageManager({}); - beforeEach(() => { callback = jest.fn(); uid2 = new UID2(); xhrMock = new mocks.XhrMock(sdkWindow); jest.spyOn(document, "URL", "get").mockImplementation(() => mockUrl); cookieMock = new mocks.CookieMock(sdkWindow.document); - uid2StorageManager.removeValues(); + removeUid2Cookie(); + removeUid2LocalStorage(); }); afterEach(() => { @@ -39,7 +37,8 @@ afterEach(() => { const makeIdentity = mocks.makeIdentityV2; const getUid2Cookie = mocks.getUid2Cookie; const getUid2LocalStorage = mocks.getUid2LocalStorage; -const setUid2Cookie = mocks.setUid2Cookie; +const removeUid2Cookie = mocks.removeUid2Cookie; +const removeUid2LocalStorage = mocks.removeUid2LocalStorage; describe("cookieDomain option", () => { describe("when using default value", () => { @@ -174,7 +173,7 @@ describe("useCookie option", () => { uid2.init({ callback: callback, identity: identity }); }); test("should set identity in local storage", () => { - expect(getUid2LocalStorage()?.advertising_token).toBe(identity.advertising_token); + expect(getUid2LocalStorage().advertising_token).toBe(identity.advertising_token); }); }); describe("when useCookie is false", () => { @@ -182,7 +181,7 @@ describe("useCookie option", () => { uid2.init({ callback: callback, identity: identity, useCookie: false }); }); test("should set identity in local storage only", () => { - expect(getUid2LocalStorage()?.advertising_token).toBe(identity.advertising_token); + expect(getUid2LocalStorage().advertising_token).toBe(identity.advertising_token); expect(getUid2Cookie()).toBeUndefined(); }); }); diff --git a/src/mocks.ts b/src/mocks.ts index 9716bca..d8ef834 100644 --- a/src/mocks.ts +++ b/src/mocks.ts @@ -1,8 +1,8 @@ import * as jsdom from "jsdom"; import { Cookie } from "tough-cookie"; -import { IdentityV2, Uid2Identity } from "./Uid2Identity"; -import { UID2LocalStorageManager } from "./uid2LocalStorageManager"; import { UID2 } from "./uid2Sdk"; +import { Uid2Identity } from "./Uid2Identity"; +import { localStorageKeyName } from "./uid2LocalStorageManager"; export class CookieMock { jar: jsdom.CookieJar; @@ -122,8 +122,6 @@ export class CryptoMock { } } -const uid2LocalStorageManager = new UID2LocalStorageManager(); - export function setupFakeTime() { jest.useFakeTimers(); jest.spyOn(global, "setTimeout"); @@ -149,6 +147,11 @@ export function setUid2Cookie(value: any) { UID2.COOKIE_NAME + "=" + encodeURIComponent(JSON.stringify(value)); } +export function removeUid2Cookie() { + document.cookie = + document.cookie + "=;expires=Tue, 1 Jan 1980 23:59:59 GMT"; +} + export async function flushPromises() { await Promise.resolve(); await Promise.resolve(); @@ -158,8 +161,8 @@ export function getUid2(useCookie?: boolean) { return useCookie ? getUid2Cookie() : getUid2LocalStorage(); } -export function setUid2(identity: any, useCookie?: boolean) { - return useCookie ? setUid2Cookie(identity) : uid2LocalStorageManager.setValue(identity); +export function setUid2(value: any, useCookie?: boolean) { + return useCookie ? setUid2Cookie(value) : setUid2LocalStorage(value); } export function getUid2Cookie() { @@ -174,8 +177,18 @@ export function getUid2Cookie() { } } -export function getUid2LocalStorage(): IdentityV2 | null | undefined { - return uid2LocalStorageManager.loadIdentityFromLocalStorage() ?? undefined; +export function removeUid2LocalStorage() { + localStorage.removeItem(localStorageKeyName); +} + +export function setUid2LocalStorage(identity: any) { + const value = JSON.stringify(identity); + localStorage.setItem(localStorageKeyName, value); +} + +export function getUid2LocalStorage() { + const value = localStorage.getItem(localStorageKeyName); + return value !== null ? JSON.parse(value) : undefined; } export function setEuidCookie(value: any) { From 736c841b2db1b37d6deabecfbacf548dd51d5769 Mon Sep 17 00:00:00 2001 From: Alex Yau Date: Mon, 9 Oct 2023 12:46:35 +1100 Subject: [PATCH 21/21] Storage mocks return null, update assertions --- src/integrationTests/autoRefresh.test.ts | 12 ++++++------ src/integrationTests/basic.test.ts | 22 +++++++++++----------- src/integrationTests/options.test.ts | 4 ++-- src/mocks.ts | 3 ++- 4 files changed, 21 insertions(+), 20 deletions(-) diff --git a/src/integrationTests/autoRefresh.test.ts b/src/integrationTests/autoRefresh.test.ts index 81ede29..4dcb6d6 100644 --- a/src/integrationTests/autoRefresh.test.ts +++ b/src/integrationTests/autoRefresh.test.ts @@ -193,7 +193,7 @@ testCookieAndLocalStorage(() => { ); }); test("should clear value", () => { - expect(getUid2(useCookie)).toBeUndefined(); + expect(getUid2(useCookie)).toBeNull(); }); test("should not set refresh timer", () => { expect(setTimeout).not.toHaveBeenCalled(); @@ -232,7 +232,7 @@ testCookieAndLocalStorage(() => { ); }); test("should clear value", () => { - expect(getUid2(useCookie)).toBeUndefined(); + expect(getUid2(useCookie)).toBeNull(); }); test("should not set refresh timer", () => { expect(setTimeout).not.toHaveBeenCalled(); @@ -309,7 +309,7 @@ testCookieAndLocalStorage(() => { ); }); test("should clear value", () => { - expect(getUid2(useCookie)).toBeUndefined(); + expect(getUid2(useCookie)).toBeNull(); }); test("should not set refresh timer", () => { expect(setTimeout).not.toHaveBeenCalled(); @@ -464,7 +464,7 @@ testCookieAndLocalStorage(() => { ); }); test("should clear value", () => { - expect(getUid2(useCookie)).toBeUndefined(); + expect(getUid2(useCookie)).toBeNull(); }); test("should not set refresh timer", () => { expect(setTimeout).not.toHaveBeenCalled(); @@ -503,7 +503,7 @@ testCookieAndLocalStorage(() => { ); }); test("should clear value", () => { - expect(getUid2(useCookie)).toBeUndefined(); + expect(getUid2(useCookie)).toBeNull(); }); test("should not set refresh timer", () => { expect(setTimeout).not.toHaveBeenCalled(); @@ -577,7 +577,7 @@ testCookieAndLocalStorage(() => { ); }); test("should clear value", () => { - expect(getUid2(useCookie)).toBeUndefined(); + expect(getUid2(useCookie)).toBeNull(); }); test("should not set refresh timer", () => { expect(setTimeout).not.toHaveBeenCalled(); diff --git a/src/integrationTests/basic.test.ts b/src/integrationTests/basic.test.ts index 0851462..2341bf5 100644 --- a/src/integrationTests/basic.test.ts +++ b/src/integrationTests/basic.test.ts @@ -164,7 +164,7 @@ testCookieAndLocalStorage(() => { ); }); test("should not set value", () => { - expect(getUid2(useCookie)).toBeUndefined(); + expect(getUid2(useCookie)).toBeNull(); }); test("should not set refresh timer", () => { expect(setTimeout).not.toHaveBeenCalled(); @@ -192,7 +192,7 @@ testCookieAndLocalStorage(() => { ); }); test("should clear value", () => { - expect(getUid2(useCookie)).toBeUndefined(); + expect(getUid2(useCookie)).toBeNull(); }); test("should not set refresh timer", () => { expect(setTimeout).not.toHaveBeenCalled(); @@ -254,7 +254,7 @@ testCookieAndLocalStorage(() => { ); }); test("should clear value", () => { - expect(getUid2(useCookie)).toBeUndefined(); + expect(getUid2(useCookie)).toBeNull(); }); test("should not set refresh timer", () => { expect(setTimeout).not.toHaveBeenCalled(); @@ -368,7 +368,7 @@ testCookieAndLocalStorage(() => { ); }); test("should clear value", () => { - expect(getUid2(useCookie)).toBeUndefined(); + expect(getUid2(useCookie)).toBeNull(); }); test("should not set refresh timer", () => { expect(setTimeout).not.toHaveBeenCalled(); @@ -544,7 +544,7 @@ testCookieAndLocalStorage(() => { ); }); test("should not set cookie", () => { - expect(getUid2(useCookie)).toBeUndefined(); + expect(getUid2(useCookie)).toBeNull(); }); test("should not set refresh timer", () => { expect(setTimeout).not.toHaveBeenCalled(); @@ -572,7 +572,7 @@ testCookieAndLocalStorage(() => { ); }); test("should not set cookie", () => { - expect(getUid2(useCookie)).toBeUndefined(); + expect(getUid2(useCookie)).toBeNull(); }); test("should not set refresh timer", () => { expect(setTimeout).not.toHaveBeenCalled(); @@ -731,7 +731,7 @@ testCookieAndLocalStorage(() => { ); }); test("should not set cookie", () => { - expect(getUid2(useCookie)).toBeUndefined(); + expect(getUid2(useCookie)).toBeNull(); }); test("should not set refresh timer", () => { expect(setTimeout).not.toHaveBeenCalled(); @@ -807,7 +807,7 @@ testCookieAndLocalStorage(() => { ); }); test("should not set cookie", () => { - expect(getUid2(useCookie)).toBeUndefined(); + expect(getUid2(useCookie)).toBeNull(); }); test("should not set refresh timer", () => { expect(setTimeout).not.toHaveBeenCalled(); @@ -836,7 +836,7 @@ testCookieAndLocalStorage(() => { ); }); test("should not set cookie", () => { - expect(getUid2(useCookie)).toBeUndefined(); + expect(getUid2(useCookie)).toBeNull(); }); test("should not set refresh timer", () => { expect(setTimeout).not.toHaveBeenCalled(); @@ -898,7 +898,7 @@ testCookieAndLocalStorage(() => { ); }); test("should not set cookie", () => { - expect(getUid2(useCookie)).toBeUndefined(); + expect(getUid2(useCookie)).toBeNull(); }); test("should not set refresh timer", () => { expect(setTimeout).not.toHaveBeenCalled(); @@ -959,7 +959,7 @@ testCookieAndLocalStorage(() => { test("should clear cookie", () => { setUid2(makeIdentityV2(), useCookie); uid2.disconnect(); - expect(getUid2(useCookie)).toBeUndefined(); + expect(getUid2(useCookie)).toBeNull(); }); test("should abort refresh timer", () => { uid2.init({ callback: callback, identity: makeIdentityV2(), useCookie: useCookie }); diff --git a/src/integrationTests/options.test.ts b/src/integrationTests/options.test.ts index dd14aba..ffc196c 100644 --- a/src/integrationTests/options.test.ts +++ b/src/integrationTests/options.test.ts @@ -182,7 +182,7 @@ describe("useCookie option", () => { }); test("should set identity in local storage only", () => { expect(getUid2LocalStorage().advertising_token).toBe(identity.advertising_token); - expect(getUid2Cookie()).toBeUndefined(); + expect(getUid2Cookie()).toBeNull(); }); }); describe("when useCookie is true", () => { @@ -191,7 +191,7 @@ describe("useCookie option", () => { }); test("should set identity in cookie only", () => { expect(getUid2Cookie().advertising_token).toBe(identity.advertising_token); - expect(getUid2LocalStorage()).toBeUndefined(); + expect(getUid2LocalStorage()).toBeNull(); }); }); }); diff --git a/src/mocks.ts b/src/mocks.ts index d8ef834..46b788a 100644 --- a/src/mocks.ts +++ b/src/mocks.ts @@ -175,6 +175,7 @@ export function getUid2Cookie() { return JSON.parse(decodeURIComponent(payload.split("=")[1])); } } + return null; } export function removeUid2LocalStorage() { @@ -188,7 +189,7 @@ export function setUid2LocalStorage(identity: any) { export function getUid2LocalStorage() { const value = localStorage.getItem(localStorageKeyName); - return value !== null ? JSON.parse(value) : undefined; + return value !== null ? JSON.parse(value) : null; } export function setEuidCookie(value: any) {