From a19c697d4f24703ba8e739b3dd36424c7e075698 Mon Sep 17 00:00:00 2001 From: Robert Ing Date: Thu, 21 Dec 2023 16:40:14 -0500 Subject: [PATCH] Finish tests, add removing expired identity cache dates to init --- src/identity-utils.ts | 336 +++--------------------- src/identity.js | 68 +++-- src/mp-instance.js | 3 + src/sdkRuntimeModels.ts | 2 +- test/src/tests-identities-attributes.js | 7 +- test/src/tests-identity-utils.ts | 153 +++++++++-- test/src/tests-identity.js | 93 +++++-- test/src/tests-main.js | 1 + test/src/tests-self-hosting-specific.js | 3 + 9 files changed, 299 insertions(+), 367 deletions(-) diff --git a/src/identity-utils.ts b/src/identity-utils.ts index fb1f09be..d09aa6db 100644 --- a/src/identity-utils.ts +++ b/src/identity-utils.ts @@ -65,15 +65,21 @@ export const concatenateIdentities = ( return concatenatedIdentities; }; -export const shouldCallIdentity = ( +export const hasValidCachedIdentity = ( method: string, proposedUserIdentities: IKnownIdentities, - idCache: LocalStorageVault + idCache?: LocalStorageVault ): Boolean => { - const cache = idCache.retrieve(); - + // There is an edhge case where multiple identity calls are taking place + // before identify fires, so there may not be a cache. See what happens when + // the ? in idCache is removed to the following test + // "queued events contain login mpid instead of identify mpid when calling + // login immediately after mParticle initializes" + const cache = idCache?.retrieve(); + + // if there is no cache, then there is no valid cached identity if (!cache) { - return true; + return false; } const cacheKey: string = concatenateIdentities( @@ -81,12 +87,22 @@ export const shouldCallIdentity = ( proposedUserIdentities ); - if (cache.hasOwnProperty(cacheKey)) { - const expireTimestamp = cache[cacheKey].expireTimestamp; - if (expireTimestamp > new Date().getTime()) return false; + // if cache doesn't have the cacheKey, there is no valid cached identity + if (!cache.hasOwnProperty(cacheKey)) { + return false; + } + + // If there is a valid cache key, compare the expireTimestamp to the current time + // and return + const expireTimestamp = cache[cacheKey].expireTimestamp; + + // if the current time is greater than the expireTimestamp, it is not a valid + // cached identity. + if (expireTimestamp < new Date().getTime()) { + return false; + } else { + return true; } - - return true; }; export const getCachedIdentity = ( @@ -126,293 +142,19 @@ export const createKnownIdentities = ( return identitiesResult; }; -// export const parseCachedIdentityResponse = ( -// cachedIdentity: ICachedIdentityCall, -// previousMPID: string, -// callback, -// // identityApiData, -// // method, -// // knownIdentities, -// mpInstance: MParticleWebSDK -// ) { -// var prevUser = mpInstance.Identity.getUser(previousMPID), -// newUser, -// mpidIsNotInCookies, -// identityApiResult, -// indexOfMPID, -// newIdentitiesByType = {}, -// previousUIByName = prevUser -// ? prevUser.getUserIdentities().userIdentities -// : {}, -// previousUIByNameCopy = mpInstance._Helpers.extend( -// {}, -// previousUIByName -// ); -// // mpInstance._Store.identityCallInFlight = false; - -// mpInstance._Store.isLoggedIn = cachedIdentity.isLoggedIn; - -// // set currentUser -// if ( -// !prevUser || -// (prevUser.getMPID() && -// identityApiResult.mpid && -// identityApiResult.mpid !== prevUser.getMPID()) -// ) { -// mpInstance._Store.mpid = identityApiResult.mpid; - -// if (prevUser) { -// mpInstance._Persistence.setLastSeenTime(previousMPID); -// } - -// if ( -// !mpInstance._Persistence.getFirstSeenTime( -// identityApiResult.mpid -// ) -// ) -// mpidIsNotInCookies = true; -// mpInstance._Persistence.setFirstSeenTime( -// identityApiResult.mpid -// ); -// } - -// if (xhr.status === 200) { -// // const CACHE_HEADER = 'X-MP-Max-Age'; -// // const idCacheTimeout = xhr.getAllResponseHeaders(); -// // magic code to get CACHE_HEADER -// const oneDayInMS = 86400 * 60 * 60 * 24; -// const timeout = new Date().getTime() + oneDayInMS; - -// if (method === 'login' || method === 'identify') { -// cacheIdentityRequest( -// method, -// knownIdentities, -// identityApiResult.mpid, -// timeout, -// self.idCache -// ); -// } - -// if (method === 'modify') { -// newIdentitiesByType = mpInstance._Identity.IdentityRequest.combineUserIdentities( -// previousUIByName, -// identityApiData.userIdentities -// ); - -// mpInstance._Persistence.saveUserIdentitiesToPersistence( -// previousMPID, -// newIdentitiesByType -// ); -// } else { -// var incomingUser = self.IdentityAPI.getUser( -// identityApiResult.mpid -// ); - -// var incomingMpidUIByName = incomingUser -// ? incomingUser.getUserIdentities().userIdentities -// : {}; - -// var incomingMpidUIByNameCopy = mpInstance._Helpers.extend( -// {}, -// incomingMpidUIByName -// ); -// mpInstance.Logger.verbose( -// 'Successfully parsed Identity Response' -// ); +export const removeExpiredIdentityCacheDates = function(idCache: LocalStorageVault): void { + const cache: Dictionary = idCache.retrieve() || {}; -// //this covers an edge case where, users stored before "firstSeenTime" was introduced -// //will not have a value for "fst" until the current MPID changes, and in some cases, -// //the current MPID will never change -// if ( -// method === 'identify' && -// prevUser && -// identityApiResult.mpid === prevUser.getMPID() -// ) { -// mpInstance._Persistence.setFirstSeenTime( -// identityApiResult.mpid -// ); -// } + idCache.purge(); + + const currentTime:number = new Date().getTime(); -// indexOfMPID = mpInstance._Store.currentSessionMPIDs.indexOf( -// identityApiResult.mpid -// ); - -// if ( -// mpInstance._Store.sessionId && -// identityApiResult.mpid && -// previousMPID !== identityApiResult.mpid && -// indexOfMPID < 0 -// ) { -// mpInstance._Store.currentSessionMPIDs.push( -// identityApiResult.mpid -// ); -// } - -// if (indexOfMPID > -1) { -// mpInstance._Store.currentSessionMPIDs = mpInstance._Store.currentSessionMPIDs -// .slice(0, indexOfMPID) -// .concat( -// mpInstance._Store.currentSessionMPIDs.slice( -// indexOfMPID + 1, -// mpInstance._Store.currentSessionMPIDs -// .length -// ) -// ); -// mpInstance._Store.currentSessionMPIDs.push( -// identityApiResult.mpid -// ); -// } - -// mpInstance._CookieSyncManager.attemptCookieSync( -// previousMPID, -// identityApiResult.mpid, -// mpidIsNotInCookies -// ); - -// self.checkIdentitySwap( -// previousMPID, -// identityApiResult.mpid, -// mpInstance._Store.currentSessionMPIDs -// ); - -// if ( -// identityApiData && -// identityApiData.userIdentities && -// Object.keys(identityApiData.userIdentities).length -// ) { -// newIdentitiesByType = self.IdentityRequest.combineUserIdentities( -// incomingMpidUIByName, -// identityApiData.userIdentities -// ); -// } - -// mpInstance._Persistence.saveUserIdentitiesToPersistence( -// identityApiResult.mpid, -// newIdentitiesByType -// ); -// mpInstance._Persistence.update(); - -// mpInstance._Persistence.findPrevCookiesBasedOnUI( -// identityApiData -// ); - -// mpInstance._Store.context = -// identityApiResult.context || -// mpInstance._Store.context; -// } - -// newUser = mpInstance.Identity.getCurrentUser(); - -// if ( -// identityApiData && -// identityApiData.onUserAlias && -// mpInstance._Helpers.Validators.isFunction( -// identityApiData.onUserAlias -// ) -// ) { -// try { -// mpInstance.Logger.warning( -// 'Deprecated function onUserAlias will be removed in future releases' -// ); -// identityApiData.onUserAlias(prevUser, newUser); -// } catch (e) { -// mpInstance.Logger.error( -// 'There was an error with your onUserAlias function - ' + -// e -// ); -// } -// } -// var persistence = mpInstance._Persistence.getPersistence(); - -// if (newUser) { -// mpInstance._Persistence.storeDataInMemory( -// persistence, -// newUser.getMPID() -// ); -// if ( -// !prevUser || -// newUser.getMPID() !== prevUser.getMPID() || -// prevUser.isLoggedIn() !== newUser.isLoggedIn() -// ) { -// mpInstance._Forwarders.initForwarders( -// newUser.getUserIdentities().userIdentities, -// mpInstance._APIClient.prepareForwardingStats -// ); -// } -// mpInstance._Forwarders.setForwarderUserIdentities( -// newUser.getUserIdentities().userIdentities -// ); -// mpInstance._Forwarders.setForwarderOnIdentityComplete( -// newUser, -// method -// ); -// mpInstance._Forwarders.setForwarderOnUserIdentified( -// newUser, -// method -// ); -// } -// var newIdentitiesByName = {}; - -// for (var key in newIdentitiesByType) { -// newIdentitiesByName[ -// Types.IdentityType.getIdentityName( -// mpInstance._Helpers.parseNumber(key) -// ) -// ] = newIdentitiesByType[key]; -// } - -// self.sendUserIdentityChangeEvent( -// newIdentitiesByName, -// method, -// identityApiResult.mpid, -// method === 'modify' -// ? previousUIByNameCopy -// : incomingMpidUIByNameCopy -// ); -// } - -// if (callback) { -// if (xhr.status === 0) { -// mpInstance._Helpers.invokeCallback( -// callback, -// HTTPCodes.noHttpCoverage, -// identityApiResult || null, -// newUser -// ); -// } else { -// mpInstance._Helpers.invokeCallback( -// callback, -// xhr.status, -// identityApiResult || null, -// newUser -// ); -// } -// } else { -// if ( -// identityApiResult && -// identityApiResult.errors && -// identityApiResult.errors.length -// ) { -// mpInstance.Logger.error( -// 'Received HTTP response code of ' + -// xhr.status + -// ' - ' + -// identityApiResult.errors[0].message -// ); -// } -// } + // Iterate over the cache and remove any key/value pairs that are expired + for (let key in cache) { + if (cache[key].expireTimestamp < currentTime) { + delete cache[key]; + } + }; -// mpInstance._APIClient.processQueuedEvents(); -// } catch (e) { -// if (callback) { -// mpInstance._Helpers.invokeCallback( -// callback, -// xhr.status, -// identityApiResult || null -// ); -// } -// mpInstance.Logger.error( -// 'Error parsing JSON response from Identity server: ' + e -// ); -// } -// }; + idCache.store(cache); +} \ No newline at end of file diff --git a/src/identity.js b/src/identity.js index 5d2ef423..c2a2cbf3 100644 --- a/src/identity.js +++ b/src/identity.js @@ -2,7 +2,7 @@ import Constants from './constants'; import Types from './types'; import { cacheIdentityRequest, - shouldCallIdentity, + hasValidCachedIdentity, getCachedIdentity, createKnownIdentities, } from './identity-utils'; @@ -251,27 +251,30 @@ export default function Identity(mpInstance) { mpid ); - let canCallIdentity = shouldCallIdentity( + const shouldReturnCachedIdentity = hasValidCachedIdentity( 'identify', identityApiRequest.known_identities, self.idCache ); - // not calling identity means that there is something in the cache - if (!canCallIdentity) { - // const cachedIdentity = getCachedIdentity( - // 'identify', - // identityApiRequest.known_identities, - // self.idCache - // ); - // this.parseCachedIdentityResponse(cachedIdentity); - // try to DRY up invoking callback - mpInstance._Helpers.invokeCallback( + // If Identity is cached, then immediately parse the identity response + if (shouldReturnCachedIdentity) { + const cachedIdentity = getCachedIdentity( + 'identify', + identityApiRequest.known_identities, + self.idCache + ); + + self.parseIdentityResponse( + cachedIdentity, + mpid, callback, - HTTPCodes.validationIssue, - preProcessResult.error + identityApiData, + 'identify', + identityApiRequest.known_identities, + true ); - mpInstance.Logger.verbose(preProcessResult); + return; } @@ -305,12 +308,10 @@ export default function Identity(mpInstance) { mpInstance._Helpers.invokeCallback( callback, HTTPCodes.loggingDisabledOrMissingAPIKey, - Messages.InformationMessages - .AbandonLogEvent + Messages.InformationMessages.AbandonLogEvent ); mpInstance.Logger.verbose( - Messages.InformationMessages - .AbandonLogEvent + Messages.InformationMessages.AbandonLogEvent ); } } else { @@ -441,20 +442,30 @@ export default function Identity(mpInstance) { mpid ); - let canCallIdentity = shouldCallIdentity( + let shouldReturnCachedIdentity = hasValidCachedIdentity( 'login', identityApiRequest.known_identities, self.idCache ); - if (!canCallIdentity) { - // try to DRY up invoking callback - mpInstance._Helpers.invokeCallback( + // If Identity is cached, then immediately parse the identity response + if (shouldReturnCachedIdentity) { + const cachedIdentity = getCachedIdentity( + 'identify', + identityApiRequest.known_identities, + self.idCache + ); + + self.parseIdentityResponse( + cachedIdentity, + mpid, callback, - HTTPCodes.validationIssue, - preProcessResult.error + identityApiData, + 'identify', + identityApiRequest.known_identities, + true ); - mpInstance.Logger.verbose(preProcessResult); + return; } @@ -1459,7 +1470,8 @@ export default function Identity(mpInstance) { callback, identityApiData, method, - knownIdentities + knownIdentities, + fromCache, ) { var prevUser = mpInstance.Identity.getUser(previousMPID), newUser, @@ -1521,6 +1533,7 @@ export default function Identity(mpInstance) { const expireTimestamp = new Date().getTime() + oneDayInMS; if (method === 'login' || method === 'identify') { + // if (fromCache) { cacheIdentityRequest( method, knownIdentities, @@ -1528,6 +1541,7 @@ export default function Identity(mpInstance) { self.idCache, xhr ); + // } } if (method === 'modify') { diff --git a/src/mp-instance.js b/src/mp-instance.js index a581d73c..2f3def0a 100644 --- a/src/mp-instance.js +++ b/src/mp-instance.js @@ -37,6 +37,7 @@ import KitBlocker from './kitBlocking'; import ConfigAPIClient from './configAPIClient'; import IdentityAPIClient from './identityApiClient'; import { LocalStorageVault } from './vault'; +import { removeExpiredIdentityCacheDates } from './identity-utils'; var Messages = Constants.Messages, HTTPCodes = Constants.HTTPCodes; @@ -1316,6 +1317,8 @@ function completeSDKInitialization(apiKey, config, mpInstance) { logger: mpInstance.Logger, } ); + + removeExpiredIdentityCacheDates(mpInstance._Identity.idCache); if (config.hasOwnProperty('workspaceToken')) { mpInstance._Store.SDKConfig.workspaceToken = config.workspaceToken; } else { diff --git a/src/sdkRuntimeModels.ts b/src/sdkRuntimeModels.ts index 20da16b7..aebad9c0 100644 --- a/src/sdkRuntimeModels.ts +++ b/src/sdkRuntimeModels.ts @@ -237,7 +237,7 @@ export interface SDKIdentityApi { login; logout; modify; - getUser(); + getUser(mpid: string); } export interface SDKHelpersApi { diff --git a/test/src/tests-identities-attributes.js b/test/src/tests-identities-attributes.js index a1e98b84..d1f29109 100644 --- a/test/src/tests-identities-attributes.js +++ b/test/src/tests-identities-attributes.js @@ -3,7 +3,8 @@ import sinon from 'sinon'; import fetchMock from 'fetch-mock/esm/client'; import { urls, apiKey, testMPID, - MPConfig } from './config'; + MPConfig, + MILLISECONDS_IN_ONE_DAY_PLUS_ONE_SECOND} from './config'; const findEventFromRequest = Utils.findEventFromRequest, findBatch = Utils.findBatch, @@ -981,6 +982,7 @@ describe('identities and attributes', function() { }); it('should send historical UIs on batches when MPID changes', function(done) { + const clock = sinon.useFakeTimers(); mParticle._resetForTests(MPConfig); window.mParticle.config.identifyRequest = { @@ -1043,6 +1045,8 @@ describe('identities and attributes', function() { JSON.stringify({ mpid: testMPID, is_logged_in: true }), ]); + clock.tick(MILLISECONDS_IN_ONE_DAY_PLUS_ONE_SECOND) + mParticle.Identity.login(loginUser); // switching back to logged in user shoudl not result in any UIC events @@ -1054,6 +1058,7 @@ describe('identities and attributes', function() { batch.user_identities.should.have.property('email', 'initial@gmail.com'); batch.user_identities.should.have.property('customer_id', 'customerid1'); + clock.restore(); done(); }); diff --git a/test/src/tests-identity-utils.ts b/test/src/tests-identity-utils.ts index 38540b9f..825d45aa 100644 --- a/test/src/tests-identity-utils.ts +++ b/test/src/tests-identity-utils.ts @@ -1,15 +1,16 @@ import { cacheIdentityRequest, concatenateIdentities, - shouldCallIdentity, + hasValidCachedIdentity, createKnownIdentities, + removeExpiredIdentityCacheDates, IKnownIdentities, ICachedIdentityCall } from "../../src/identity-utils"; import { LocalStorageVault } from "../../src/vault"; import { Dictionary } from "../../src/utils"; import { expect } from 'chai'; -import { testMPID } from './config'; +import { MILLISECONDS_IN_ONE_DAY, MILLISECONDS_IN_ONE_DAY_PLUS_ONE_SECOND, testMPID } from './config'; import sinon from 'sinon'; @@ -81,7 +82,6 @@ describe('identity-utils', () => { }); it('should save a login request to local storage', () => { - debugger; const mpIdCache = window.localStorage.getItem(mpLocalStorageKey); expect(mpIdCache).to.equal(null); @@ -174,7 +174,7 @@ describe('identity-utils', () => { }); }); - describe('#shouldCallIdentity', () => { + describe('#hasValidCachedIdentity', () => { let clock; beforeEach(() => { @@ -210,24 +210,25 @@ describe('identity-utils', () => { yahoo: '06', }; - it('should return true if idCache is empty', () => { + it('should return false if idCache is empty', () => { const mpIdCache = window.localStorage.getItem(mpLocalStorageKey); expect(mpIdCache).to.equal(null); const cacheVault = new LocalStorageVault(mpLocalStorageKey); - const result = shouldCallIdentity('identify', userIdentities, cacheVault); - expect(result).to.equal(true); + const result = hasValidCachedIdentity('identify', userIdentities, cacheVault); + expect(result).to.equal(false); }); - it('should return false if idCache has the identity method and new identity call is within 1 day of previously cached identity call', () => { + it('should return true if idCache has the identity method and new identity call is within 1 day of previously cached identity call', () => { const mpIdCache = window.localStorage.getItem(mpLocalStorageKey); expect(mpIdCache).to.equal(null); const cacheVault = new LocalStorageVault(mpLocalStorageKey); - const result1 = shouldCallIdentity('identify', userIdentities, cacheVault); - expect(result1).to.equal(true); + // check to ensure there is nothing on the cache first + const result1 = hasValidCachedIdentity('identify', userIdentities, cacheVault); + expect(result1).to.equal(false); const oneDayInMS = 86400 * 60 * 60 * 24; @@ -258,9 +259,10 @@ describe('identity-utils', () => { xhr ); + // tick forward less than oneDayInMS clock.tick(5000); - const result2 = shouldCallIdentity('identify', userIdentities, cacheVault); - expect(result2).to.equal(false); + const result2 = hasValidCachedIdentity('identify', userIdentities, cacheVault); + expect(result2).to.equal(true); }); it('should return true if idCache has the identity method and new identity call is beyond of 1 day of previously cached identity call', () => { @@ -298,8 +300,129 @@ describe('identity-utils', () => { ); clock.tick(oneDayInMS +1); - const result3 = shouldCallIdentity('identify', userIdentities, cacheVault); - expect(result3).to.equal(true); + const result3 = hasValidCachedIdentity('identify', userIdentities, cacheVault); + expect(result3).to.equal(false); }); }); -}); + + describe('#createKnownIdentities', () => { + it('should return an object whose keys are each identity type passed to it from the userIdentities object, in addition to device_application_stamp', () => { + const identities = { + userIdentities: { + other: 'other', + customerid: 'customerid', + facebook: 'facebook', + twitter: 'twitter', + google: 'google', + microsoft: 'microsoft', + yahoo: 'yahoo', + email: 'email', + facebookcustomaudienceid: 'facebookcustomaudienceid', + other2: 'other2', + other3: 'other3', + other4: 'other4', + other5: 'other5', + other6: 'other6', + other7: 'other7', + other8: 'other8', + other9: 'other9', + other10: 'other10', + mobile_number: 'mobile_number', + phone_number_2: 'phone_number_2', + phone_number_3: 'phone_number_3', + }}; + + const knownIdentities: IKnownIdentities = createKnownIdentities( + identities, + DEVICE_ID + ); + + const expectedResult: IKnownIdentities = { + ...identities.userIdentities, + device_application_stamp: DEVICE_ID, + }; + + expect(knownIdentities).to.deep.equal(expectedResult); + }); + }); + + describe('#removeExpiredIdentityCacheDates', () => { + it('remove any timestamps that are expired, and keep any timestamps that are not expired', () => { + // set up clock in order to force some time stamps to expire later in the test + const clock = sinon.useFakeTimers(); + + const cacheVault = new LocalStorageVault(mpLocalStorageKey); + const knownIdentities1: IKnownIdentities = createKnownIdentities({ + userIdentities: {customerid: 'id1'}}, + DEVICE_ID + ); + const knownIdentities2: IKnownIdentities = createKnownIdentities({ + userIdentities: {customerid: 'id2'}}, + DEVICE_ID + ); + + const identifyResponse = { + context: null, + matched_identities: { + device_application_stamp: "test-das" + }, + is_ephemeral: false, + mpid: testMPID, + is_logged_in: false + }; + + const xhr: XMLHttpRequest = { + status: 200, + responseText: JSON.stringify(identifyResponse), + } as XMLHttpRequest; + + // Cache 1st identity response to expire in 1 day + cacheIdentityRequest( + 'identify', + knownIdentities1, + MILLISECONDS_IN_ONE_DAY, + cacheVault, + xhr + ); + + // Cache 2nd identity response to expire in 1 day + 100ms + cacheIdentityRequest( + 'identify', + knownIdentities2, + MILLISECONDS_IN_ONE_DAY + 100, + cacheVault, + xhr + ); + + const updatedMpIdCache = cacheVault.retrieve(); + + const knownIdentities1CachedKey = + 'identify:device_application_stamp=test-device-id;customerid=id1;'; + const knownIdentities2CachedKey = + 'identify:device_application_stamp=test-device-id;customerid=id2;'; + + + // both known identities cache keys should exist on the cacheVault + expect(updatedMpIdCache!.hasOwnProperty(knownIdentities1CachedKey)).to.equal(true); + expect(updatedMpIdCache!.hasOwnProperty(knownIdentities2CachedKey)).to.equal(true); + + // we do not tick the clock forward at all, so the expiration date should not yet be reached + // meaning both cached keys are still in the cache vault + removeExpiredIdentityCacheDates(cacheVault); + const updatedMpIdCache2 = cacheVault.retrieve(); + expect(updatedMpIdCache2!.hasOwnProperty(knownIdentities1CachedKey)).to.equal(true); + expect(updatedMpIdCache2!.hasOwnProperty(knownIdentities2CachedKey)).to.equal(true); + + // tick the clock forward 1 day + 1 ms, expiring knownIdentities1CachedKey but not knownIdentities2CachedKey + clock.tick(MILLISECONDS_IN_ONE_DAY_PLUS_ONE_SECOND); + + removeExpiredIdentityCacheDates(cacheVault); + const updatedMpIdCache3 = cacheVault.retrieve(); + + expect(updatedMpIdCache3!.hasOwnProperty(knownIdentities1CachedKey)).to.equal(false); + expect(updatedMpIdCache3!.hasOwnProperty(knownIdentities2CachedKey)).to.equal(true); + + clock.restore(); + }); + }); +}); \ No newline at end of file diff --git a/test/src/tests-identity.js b/test/src/tests-identity.js index d860500c..b94583b4 100644 --- a/test/src/tests-identity.js +++ b/test/src/tests-identity.js @@ -5,7 +5,9 @@ import fetchMock from 'fetch-mock/esm/client'; import { urls, apiKey, testMPID, MPConfig, - workspaceCookieName } from './config'; + workspaceCookieName, + MILLISECONDS_IN_ONE_DAY_PLUS_ONE_SECOND +} from './config'; const getLocalStorage = Utils.getLocalStorage, setLocalStorage = Utils.setLocalStorage, @@ -26,6 +28,7 @@ describe('identity', function() { fetchMock.post(urls.events, 200); mockServer = sinon.createFakeServer(); mockServer.respondImmediately = true; + localStorage.clear(); mockServer.respondWith(urls.identify, [ 200, @@ -160,7 +163,13 @@ describe('identity', function() { JSON.stringify({ mpid: 'otherMPID', is_logged_in: false }), ]); - mParticle.Identity.login(); + const userIdentities1 = { + userIdentities: { + customerid: 'foo1', + }, + }; + + mParticle.Identity.login(userIdentities1); const localStorageDataBeforeSessionEnd = mParticle .getInstance() ._Persistence.getLocalStorage(); @@ -174,7 +183,7 @@ describe('identity', function() { localStorageDataAfterSessionEnd1.gs.should.not.have.property('csm'); mParticle.logEvent('hi'); - mParticle.Identity.login(); + mParticle.Identity.login(userIdentities1); const localStorageAfterLoggingEvent = mParticle .getInstance() @@ -202,7 +211,13 @@ describe('identity', function() { JSON.stringify({ mpid: 'otherMPID', is_logged_in: false }), ]); - mParticle.Identity.login(); + const userIdentities1 = { + userIdentities: { + customerid: 'foo1', + }, + }; + + mParticle.Identity.login(userIdentities1); const cookiesAfterMPIDChange = mParticle .getInstance() ._Persistence.getLocalStorage(); @@ -272,7 +287,13 @@ describe('identity', function() { JSON.stringify({ mpid: 'otherMPID', is_logged_in: false }), ]); - mParticle.Identity.login(); + const userIdentities1 = { + userIdentities: { + customerid: 'foo1', + }, + }; + + mParticle.Identity.login(userIdentities1); const cookiesAfterMPIDChange = findCookie(); cookiesAfterMPIDChange.should.have.properties([ @@ -1048,12 +1069,21 @@ describe('identity', function() { it('getUsers should return all mpids available in local storage', function(done) { mParticle._resetForTests(MPConfig); - const user1 = {}; - const user2 = {}; - const user3 = { + const userIdentities1 = { userIdentities: { - customerid: 'customerid3', - email: 'email3@test.com', + customerid: 'foo1', + }, + }; + + const userIdentities2 = { + userIdentities: { + customerid: 'foo2', + }, + }; + + const userIdentities3 = { + userIdentities: { + customerid: 'foo3', }, }; @@ -1065,8 +1095,8 @@ describe('identity', function() { {}, JSON.stringify({ mpid: 'user1', is_logged_in: false }), ]); - - mParticle.Identity.login(user1); + debugger; + mParticle.Identity.login(userIdentities1); // get user 2 into cookies mockServer.respondWith(urls.login, [ @@ -1075,7 +1105,7 @@ describe('identity', function() { JSON.stringify({ mpid: 'user2', is_logged_in: false }), ]); - mParticle.Identity.login(user2); + mParticle.Identity.login(userIdentities2); // get user 3 into cookies mockServer.respondWith(urls.login, [ @@ -1084,7 +1114,7 @@ describe('identity', function() { JSON.stringify({ mpid: 'user3', is_logged_in: false }), ]); - mParticle.Identity.login(user3); + mParticle.Identity.login(userIdentities3); // init again using user 1 mockServer.respondWith(urls.login, [ @@ -1093,7 +1123,8 @@ describe('identity', function() { JSON.stringify({ mpid: 'user1', is_logged_in: false }), ]); - mParticle.identifyRequest = user1; + + mParticle.identifyRequest = userIdentities1; mParticle.init(apiKey, window.mParticle.config); const users = mParticle.Identity.getUsers(); @@ -1106,6 +1137,7 @@ describe('identity', function() { Should.not.exist(mParticle.Identity.getUser('cu')); Should.not.exist(mParticle.Identity.getUser('0')); Should.not.exist(mParticle.Identity.getUser('user4')); + done(); }); @@ -2282,7 +2314,7 @@ describe('identity', function() { mockServer.respondWith(urls.identify, [ 200, {}, - JSON.stringify({ mpid: 'MPID1', is_logged_in: false }), + JSON.stringify({ mpid: testMPID, is_logged_in: false }), ]); mockServer.requests = []; @@ -2300,35 +2332,41 @@ describe('identity', function() { mockServer.respondWith(urls.login, [ 200, {}, - JSON.stringify({ mpid: 'MPID2', is_logged_in: false }), + JSON.stringify({ mpid: 'MPID1', is_logged_in: false }), ]); + const userIdentities1 = { + userIdentities: { + customerid: 'foo1', + }, + }; + mockServer.requests = []; - mParticle.Identity.login(); + mParticle.Identity.login(userIdentities1); currentUser = mParticle.Identity.getCurrentUser(); - currentUser.getMPID().should.equal('MPID2'); + currentUser.getMPID().should.equal('MPID1'); - //new user's firstSeenTime should be greater than or equal to the preceeding user's lastSeenTime + // new user's firstSeenTime should be greater than or equal to the preceeding user's lastSeenTime (currentUser.getFirstSeenTime() >= user1LastSeen).should.equal(true); currentUser.getFirstSeenTime().should.equal(120); clock.tick(20); - const user1 = mParticle.Identity.getUser('MPID1'); + const user1 = mParticle.Identity.getUser(testMPID); user1.getFirstSeenTime().should.equal(user1FirstSeen); mockServer.respondWith(urls.login, [ 200, {}, - JSON.stringify({ mpid: 'MPID1', is_logged_in: false }), + JSON.stringify({ mpid: testMPID, is_logged_in: false }), ]); mockServer.requests = []; mParticle.Identity.login(); currentUser = mParticle.Identity.getCurrentUser(); - currentUser.getMPID().should.equal('MPID1'); + currentUser.getMPID().should.equal(testMPID); currentUser.getFirstSeenTime().should.equal(user1FirstSeen); (currentUser.getLastSeenTime() > user1LastSeen).should.equal(true); @@ -3078,14 +3116,17 @@ describe('identity', function() { } mParticle.config.identifyRequest = identities; - + debugger; mParticle.init(apiKey, window.mParticle.config); const initialIdentityCall = getIdentityEvent(mockServer.requests, 'identify'); initialIdentityCall.should.be.ok(); mockServer.requests = []; - - mParticle.Identity.identify(identities); + function callback(result) { + debugger; + } + debugger; + mParticle.Identity.identify(identities, callback); const duplicateIdentityCall = getIdentityEvent(mockServer.requests, 'identify'); Should(duplicateIdentityCall).not.be.ok(); diff --git a/test/src/tests-main.js b/test/src/tests-main.js index cfd20b58..2622d933 100644 --- a/test/src/tests-main.js +++ b/test/src/tests-main.js @@ -11,6 +11,7 @@ beforeEach(function() { } else { window.mParticle.getInstance().Identity.getCurrentUser = userApi; } + localStorage.clear(); window.mParticle = window.mParticle || {}; window.mParticle.config = { workspaceToken: workspaceToken, diff --git a/test/src/tests-self-hosting-specific.js b/test/src/tests-self-hosting-specific.js index 0262fc0d..7ba5d6d3 100644 --- a/test/src/tests-self-hosting-specific.js +++ b/test/src/tests-self-hosting-specific.js @@ -64,6 +64,7 @@ describe('/config self-hosting integration tests', function() { done(); }); + // TODO: LOGIN needs self.idCache to exist, but it('queued events contain login mpid instead of identify mpid when calling login immediately after mParticle initializes', function(done) { const messages = []; mParticle._resetForTests(MPConfig); @@ -94,6 +95,8 @@ describe('/config self-hosting integration tests', function() { urls.config, [200, {}, JSON.stringify({ workspaceToken: 'workspaceTokenTest' })] ); + + debugger; mockServer.respondWith(urls.identify, [ 200, {},