diff --git a/src/anonymousUserTracking/tests/userMergeScenarios.test.ts b/src/anonymousUserTracking/tests/userMergeScenarios.test.ts index d7a5dd4b..2e040590 100644 --- a/src/anonymousUserTracking/tests/userMergeScenarios.test.ts +++ b/src/anonymousUserTracking/tests/userMergeScenarios.test.ts @@ -94,10 +94,16 @@ describe('UserMergeScenariosTests', () => { }); describe('UserMergeScenariosTests with setUserID', () => { - it('criteria not met with disableEventReplay true with setUserId', async () => { + it('criteria not met with merge false with setUserId', async () => { const { setUserID, logout } = initializeWithConfig({ authToken: '123', - configOptions: { enableAnonTracking: true } + configOptions: { + enableAnonTracking: true, + identityResolution: { + replayOnVisitorToKnown: false, + mergeOnAnonymousToKnown: false + } + } }); logout(); // logout to remove logged in users before this test try { @@ -109,7 +115,7 @@ describe('UserMergeScenariosTests', () => { SHARED_PREFS_EVENT_LIST_KEY, expect.any(String) ); - await setUserID('testuser123', true); + await setUserID('testuser123'); const response = await getInAppMessages({ count: 10, packageName: 'my-lil-website' @@ -127,10 +133,16 @@ describe('UserMergeScenariosTests', () => { expect(mergePostRequestData).toBeUndefined(); // ensure that merge API Do NOT get called }); - it('criteria not met with disableEventReplay false with setUserId', async () => { + it('criteria not met with merge true with setUserId', async () => { const { setUserID, logout } = initializeWithConfig({ authToken: '123', - configOptions: { enableAnonTracking: true } + configOptions: { + enableAnonTracking: true, + identityResolution: { + replayOnVisitorToKnown: true, + mergeOnAnonymousToKnown: true + } + } }); logout(); // logout to remove logged in users before this test try { @@ -142,7 +154,7 @@ describe('UserMergeScenariosTests', () => { SHARED_PREFS_EVENT_LIST_KEY, expect.any(String) ); - await setUserID('testuser123', false); + await setUserID('testuser123'); const response = await getInAppMessages({ count: 10, packageName: 'my-lil-website' @@ -162,10 +174,16 @@ describe('UserMergeScenariosTests', () => { expect(mergePostRequestData).toBeUndefined(); // ensure that merge API Do NOT get called }); - it('criteria not met with disableEventReplay default value with setUserId', async () => { + it('criteria not met with merge default value with setUserId', async () => { const { setUserID, logout } = initializeWithConfig({ authToken: '123', - configOptions: { enableAnonTracking: true } + configOptions: { + enableAnonTracking: true, + identityResolution: { + replayOnVisitorToKnown: true, + mergeOnAnonymousToKnown: false + } + } }); logout(); // logout to remove logged in users before this test try { @@ -197,7 +215,7 @@ describe('UserMergeScenariosTests', () => { expect(mergePostRequestData).toBeUndefined(); // ensure that merge API Do NOT get called }); - it('criteria is met with disableEventReplay true with setUserId', async () => { + it('criteria is met with merge false with setUserId', async () => { (localStorage.getItem as jest.Mock).mockImplementation((key) => { if (key === SHARED_PREFS_EVENT_LIST_KEY) { return JSON.stringify([eventDataMatched]); @@ -212,7 +230,13 @@ describe('UserMergeScenariosTests', () => { }); const { setUserID, logout } = initializeWithConfig({ authToken: '123', - configOptions: { enableAnonTracking: true } + configOptions: { + enableAnonTracking: true, + identityResolution: { + replayOnVisitorToKnown: true, + mergeOnAnonymousToKnown: false + } + } }); logout(); // logout to remove logged in users before this test try { @@ -220,7 +244,7 @@ describe('UserMergeScenariosTests', () => { } catch (e) { console.log(''); } - await setUserID('testuser123', true); + await setUserID('testuser123'); expect(localStorageMock.removeItem).toHaveBeenCalledWith( SHARED_PREF_ANON_USER_ID ); @@ -235,7 +259,7 @@ describe('UserMergeScenariosTests', () => { expect(mergePostRequestData).toBeUndefined(); // ensure that merge API Do NOT get called }); - it('criteria is met with disableEventReplay false with setUserId', async () => { + it('criteria is met with merge true with setUserId', async () => { (localStorage.getItem as jest.Mock).mockImplementation((key) => { if (key === SHARED_PREFS_EVENT_LIST_KEY) { return JSON.stringify([eventDataMatched]); @@ -250,7 +274,13 @@ describe('UserMergeScenariosTests', () => { }); const { setUserID, logout } = initializeWithConfig({ authToken: '123', - configOptions: { enableAnonTracking: true } + configOptions: { + enableAnonTracking: true, + identityResolution: { + replayOnVisitorToKnown: true, + mergeOnAnonymousToKnown: true + } + } }); logout(); // logout to remove logged in users before this test try { @@ -263,7 +293,7 @@ describe('UserMergeScenariosTests', () => { count: 10, packageName: 'my-lil-website' }); - await setUserID('testuser123', false); + await setUserID('testuser123'); expect(localStorageMock.removeItem).toHaveBeenCalledWith( SHARED_PREF_ANON_USER_ID ); @@ -277,7 +307,7 @@ describe('UserMergeScenariosTests', () => { jest.runAllTimers(); }); - it('criteria is met with disableEventReplay default with setUserId', async () => { + it('criteria is met with merge default with setUserId', async () => { (localStorage.getItem as jest.Mock).mockImplementation((key) => { if (key === SHARED_PREFS_EVENT_LIST_KEY) { return JSON.stringify([eventDataMatched]); @@ -295,7 +325,9 @@ describe('UserMergeScenariosTests', () => { }); const { setUserID, logout } = initializeWithConfig({ authToken: '123', - configOptions: { enableAnonTracking: true } + configOptions: { + enableAnonTracking: true + } }); logout(); // logout to remove logged in users before this test try { @@ -321,10 +353,16 @@ describe('UserMergeScenariosTests', () => { jest.runAllTimers(); }); - it('current user identified with setUserId disableEventReplay true', async () => { + it('current user identified with setUserId merge false', async () => { const { setUserID, logout } = initializeWithConfig({ authToken: '123', - configOptions: { enableAnonTracking: true } + configOptions: { + enableAnonTracking: true, + identityResolution: { + replayOnVisitorToKnown: true, + mergeOnAnonymousToKnown: false + } + } }); logout(); // logout to remove logged in users before this test await setUserID('testuser123'); @@ -341,7 +379,7 @@ describe('UserMergeScenariosTests', () => { expect(localStorageMock.setItem).not.toHaveBeenCalledWith( SHARED_PREF_ANON_USER_ID ); - await setUserID('testuseranotheruser', true); + await setUserID('testuseranotheruser'); const secondResponse = await getInAppMessages({ count: 10, packageName: 'my-lil-website' @@ -353,10 +391,16 @@ describe('UserMergeScenariosTests', () => { expect(mergePostRequestData).toBeUndefined(); // ensure that merge API Do NOT get called }); - it('current user identified with setUserId disableEventReplay false', async () => { + it('current user identified with setUserId merge true', async () => { const { setUserID, logout } = initializeWithConfig({ authToken: '123', - configOptions: { enableAnonTracking: true } + configOptions: { + enableAnonTracking: true, + identityResolution: { + replayOnVisitorToKnown: true, + mergeOnAnonymousToKnown: true + } + } }); logout(); // logout to remove logged in users before this test await setUserID('testuser123'); @@ -368,7 +412,7 @@ describe('UserMergeScenariosTests', () => { expect(localStorageMock.setItem).not.toHaveBeenCalledWith( SHARED_PREF_ANON_USER_ID ); - await setUserID('testuseranotheruser', false); + await setUserID('testuseranotheruser'); const secondResponse = await getInAppMessages({ count: 10, packageName: 'my-lil-website' @@ -380,10 +424,16 @@ describe('UserMergeScenariosTests', () => { expect(mergePostRequestData).toBeDefined(); // ensure that merge API gets called }); - it('current user identified with setUserId disableEventReplay default', async () => { + it('current user identified with setUserId merge default', async () => { const { setUserID, logout } = initializeWithConfig({ authToken: '123', - configOptions: { enableAnonTracking: true } + configOptions: { + enableAnonTracking: true, + identityResolution: { + replayOnVisitorToKnown: true, + mergeOnAnonymousToKnown: false + } + } }); logout(); // logout to remove logged in users before this test await setUserID('testuser123'); @@ -404,15 +454,21 @@ describe('UserMergeScenariosTests', () => { const mergePostRequestData = mockRequest.history.post.find( (req) => req.url === ENDPOINT_MERGE_USER ); - expect(mergePostRequestData).toBeDefined(); // ensure that merge API gets called + expect(mergePostRequestData).toBeUndefined(); // ensure that merge API Do NOT get called }); }); describe('UserMergeScenariosTests with setEmail', () => { - it('criteria not met with disableEventReplay true with setEmail', async () => { + it('criteria not met with merge false with setEmail', async () => { const { setEmail, logout } = initializeWithConfig({ authToken: '123', - configOptions: { enableAnonTracking: true } + configOptions: { + enableAnonTracking: true, + identityResolution: { + replayOnVisitorToKnown: false, + mergeOnAnonymousToKnown: false + } + } }); logout(); // logout to remove logged in users before this test try { @@ -424,7 +480,7 @@ describe('UserMergeScenariosTests', () => { SHARED_PREFS_EVENT_LIST_KEY, expect.any(String) ); - await setEmail('testuser123@test.com', true); + await setEmail('testuser123@test.com'); const response = await getInAppMessages({ count: 10, packageName: 'my-lil-website' @@ -442,10 +498,16 @@ describe('UserMergeScenariosTests', () => { expect(mergePostRequestData).toBeUndefined(); // ensure that merge API Do NOT get called }); - it('criteria not met with disableEventReplay false with setEmail', async () => { + it('criteria not met with merge true with setEmail', async () => { const { setEmail, logout } = initializeWithConfig({ authToken: '123', - configOptions: { enableAnonTracking: true } + configOptions: { + enableAnonTracking: true, + identityResolution: { + replayOnVisitorToKnown: true, + mergeOnAnonymousToKnown: true + } + } }); logout(); // logout to remove logged in users before this test try { @@ -457,7 +519,7 @@ describe('UserMergeScenariosTests', () => { SHARED_PREFS_EVENT_LIST_KEY, expect.any(String) ); - await setEmail('testuser123@test.com', false); + await setEmail('testuser123@test.com'); const response = await getInAppMessages({ count: 10, packageName: 'my-lil-website' @@ -477,10 +539,12 @@ describe('UserMergeScenariosTests', () => { expect(mergePostRequestData).toBeUndefined(); // ensure that merge API Do NOT get called }); - it('criteria not met with disableEventReplay default value with setEmail', async () => { + it('criteria not met with merge default value with setEmail', async () => { const { setEmail, logout } = initializeWithConfig({ authToken: '123', - configOptions: { enableAnonTracking: true } + configOptions: { + enableAnonTracking: true + } }); logout(); // logout to remove logged in users before this test try { @@ -512,7 +576,7 @@ describe('UserMergeScenariosTests', () => { expect(mergePostRequestData).toBeUndefined(); // ensure that merge API Do NOT get called }); - it('criteria is met with disableEventReplay false with setEmail', async () => { + it('criteria is met with merge true with setEmail', async () => { (localStorage.getItem as jest.Mock).mockImplementation((key) => { if (key === SHARED_PREFS_EVENT_LIST_KEY) { return JSON.stringify([eventDataMatched]); @@ -527,7 +591,13 @@ describe('UserMergeScenariosTests', () => { }); const { setEmail, logout } = initializeWithConfig({ authToken: '123', - configOptions: { enableAnonTracking: true } + configOptions: { + enableAnonTracking: true, + identityResolution: { + replayOnVisitorToKnown: true, + mergeOnAnonymousToKnown: true + } + } }); logout(); // logout to remove logged in users before this test try { @@ -539,7 +609,7 @@ describe('UserMergeScenariosTests', () => { count: 10, packageName: 'my-lil-website' }); - await setEmail('testuser123@test.com', false); + await setEmail('testuser123@test.com'); expect(localStorageMock.removeItem).toHaveBeenCalledWith( SHARED_PREF_ANON_USER_ID ); @@ -553,7 +623,7 @@ describe('UserMergeScenariosTests', () => { jest.runAllTimers(); }); - it('criteria is met with disableEventReplay default with setEmail', async () => { + it('criteria is met with merge default with setEmail', async () => { (localStorage.getItem as jest.Mock).mockImplementation((key) => { if (key === SHARED_PREFS_EVENT_LIST_KEY) { return JSON.stringify([eventDataMatched]); @@ -571,7 +641,9 @@ describe('UserMergeScenariosTests', () => { }); const { setEmail, logout } = initializeWithConfig({ authToken: '123', - configOptions: { enableAnonTracking: true } + configOptions: { + enableAnonTracking: true + } }); logout(); // logout to remove logged in users before this test try { @@ -597,10 +669,16 @@ describe('UserMergeScenariosTests', () => { jest.runAllTimers(); }); - it('current user identified with setEmail with disableEventReplay true', async () => { + it('current user identified with setEmail with merge false', async () => { const { setEmail, logout } = initializeWithConfig({ authToken: '123', - configOptions: { enableAnonTracking: true } + configOptions: { + enableAnonTracking: true, + identityResolution: { + replayOnVisitorToKnown: true, + mergeOnAnonymousToKnown: false + } + } }); logout(); // logout to remove logged in users before this test await setEmail('testuser123@test.com'); @@ -617,7 +695,7 @@ describe('UserMergeScenariosTests', () => { expect(localStorageMock.setItem).not.toHaveBeenCalledWith( SHARED_PREF_ANON_USER_ID ); - await setEmail('testuseranotheruser@test.com', true); + await setEmail('testuseranotheruser@test.com'); const secondResponse = await getInAppMessages({ count: 10, packageName: 'my-lil-website' @@ -631,10 +709,16 @@ describe('UserMergeScenariosTests', () => { expect(mergePostRequestData).toBeUndefined(); // ensure that merge API Do NOT get called }); - it('current user identified with setEmail disableEventReplay false', async () => { + it('current user identified with setEmail merge true', async () => { const { setEmail, logout } = initializeWithConfig({ authToken: '123', - configOptions: { enableAnonTracking: true } + configOptions: { + enableAnonTracking: true, + identityResolution: { + replayOnVisitorToKnown: true, + mergeOnAnonymousToKnown: true + } + } }); logout(); // logout to remove logged in users before this test await setEmail('testuser123@test.com'); @@ -651,7 +735,7 @@ describe('UserMergeScenariosTests', () => { expect(localStorageMock.setItem).not.toHaveBeenCalledWith( SHARED_PREF_ANON_USER_ID ); - await setEmail('testuseranotheruser@test.com', false); + await setEmail('testuseranotheruser@test.com'); const secondResponse = await getInAppMessages({ count: 10, packageName: 'my-lil-website' @@ -665,10 +749,16 @@ describe('UserMergeScenariosTests', () => { expect(mergePostRequestData).toBeDefined(); // ensure that merge API gets called }); - it('current user identified with setEmail disableEventReplay default', async () => { + it('current user identified with setEmail merge default', async () => { const { setEmail, logout } = initializeWithConfig({ authToken: '123', - configOptions: { enableAnonTracking: true } + configOptions: { + enableAnonTracking: true, + identityResolution: { + replayOnVisitorToKnown: true, + mergeOnAnonymousToKnown: false + } + } }); logout(); // logout to remove logged in users before this test await setEmail('testuser123@test.com'); @@ -696,7 +786,7 @@ describe('UserMergeScenariosTests', () => { const mergePostRequestData = mockRequest.history.post.find( (req) => req.url === ENDPOINT_MERGE_USER ); - expect(mergePostRequestData).toBeDefined(); // ensure that merge API gets called + expect(mergePostRequestData).toBeUndefined(); // ensure that merge API Do NOT get called }); }); }); diff --git a/src/authorization/authorization.ts b/src/authorization/authorization.ts index e7ca34a6..1e48d0eb 100644 --- a/src/authorization/authorization.ts +++ b/src/authorization/authorization.ts @@ -62,8 +62,8 @@ const doesRequestUrlContain = (routeConfig: RouteConfig) => ); export interface WithJWT { clearRefresh: () => void; - setEmail: (email: string, disableEventReplay?: boolean) => Promise; - setUserID: (userId: string, disableEventReplay?: boolean) => Promise; + setEmail: (email: string) => Promise; + setUserID: (userId: string) => Promise; logout: () => void; refreshJwtToken: (authTypes: string) => Promise; } @@ -71,8 +71,8 @@ export interface WithJWT { export interface WithoutJWT { setNewAuthToken: (newToken?: string) => void; clearAuthToken: () => void; - setEmail: (email: string, disableEventReplay?: boolean) => Promise; - setUserID: (userId: string, disableEventReplay?: boolean) => Promise; + setEmail: (email: string) => Promise; + setUserID: (userId: string) => Promise; logout: () => void; } @@ -108,13 +108,10 @@ const getAnonUserId = () => { } }; -const initializeUserIdAndSync = ( - userId: string, - disableEventReplay?: boolean -) => { +const initializeUserIdAndSync = (userId: string, replay?: boolean) => { addUserIdToRequest(userId); clearAnonymousUser(); - if (!disableEventReplay) { + if (replay) { syncEvents(); } }; @@ -214,13 +211,10 @@ const addUserIdToRequest = (userId: string) => { }); }; -const initializeEmailUserAndSync = ( - email: string, - disableEventReplay?: boolean -) => { +const initializeEmailUserAndSync = (email: string, replay?: boolean) => { addEmailToRequest(email); clearAnonymousUser(); - if (!disableEventReplay) { + if (replay) { syncEvents(); } }; @@ -426,7 +420,7 @@ export function initialize( const tryMergeUser = async ( emailOrUserId: string, isEmail: boolean, - disableEventReplay?: boolean + merge?: boolean ): Promise => { const enableAnonTracking = config.getConfig('enableAnonTracking'); const sourceUserIdOrEmail = @@ -438,7 +432,7 @@ export function initialize( // This function will try to merge if anon user exists if ( (getAnonUserId() !== null || authIdentifier !== null) && - !disableEventReplay && + merge && enableAnonTracking ) { const anonymousUserMerge = new AnonymousUserMerge(); @@ -479,12 +473,16 @@ export function initialize( baseAxiosRequest.interceptors.request.eject(authInterceptor); } }, - setEmail: async (email: string, disableEventReplay?: boolean) => { + setEmail: async (email: string) => { clearMessages(); try { - const result = await tryMergeUser(email, true, disableEventReplay); + const identityResolution = config.getConfig('identityResolution'); + const merge = identityResolution?.mergeOnAnonymousToKnown; + const replay = identityResolution?.replayOnVisitorToKnown; + + const result = await tryMergeUser(email, true, merge); if (result) { - initializeEmailUserAndSync(email, disableEventReplay); + initializeEmailUserAndSync(email, replay); return Promise.resolve(); } } catch (error) { @@ -492,12 +490,16 @@ export function initialize( return Promise.reject(`merging failed: ${error}`); } }, - setUserID: async (userId: string, disableEventReplay?: boolean) => { + setUserID: async (userId: string) => { clearMessages(); try { - const result = await tryMergeUser(userId, false, disableEventReplay); + const identityResolution = config.getConfig('identityResolution'); + const merge = identityResolution?.mergeOnAnonymousToKnown; + const replay = identityResolution?.replayOnVisitorToKnown; + + const result = await tryMergeUser(userId, false, merge); if (result) { - initializeUserIdAndSync(userId, disableEventReplay); + initializeUserIdAndSync(userId, replay); return Promise.resolve(); } } catch (error) { @@ -783,13 +785,17 @@ export function initialize( /* this will just clear the existing timeout */ handleTokenExpiration(''); }, - setEmail: async (email: string, disableEventReplay?: boolean) => { + setEmail: async (email: string) => { /* clear previous user */ clearMessages(); try { - const result = await tryMergeUser(email, true, disableEventReplay); + const identityResolution = config.getConfig('identityResolution'); + const merge = identityResolution?.mergeOnAnonymousToKnown; + const replay = identityResolution?.replayOnVisitorToKnown; + + const result = await tryMergeUser(email, true, merge); if (result) { - initializeEmailUserAndSync(email, disableEventReplay); + initializeEmailUserAndSync(email, replay); try { return doRequest({ email }).catch((e) => { if (logLevel === 'verbose') { @@ -809,12 +815,16 @@ export function initialize( return Promise.reject(`merging failed: ${error}`); } }, - setUserID: async (userId: string, disableEventReplay?: boolean) => { + setUserID: async (userId: string) => { clearMessages(); try { - const result = await tryMergeUser(userId, false, disableEventReplay); + const identityResolution = config.getConfig('identityResolution'); + const merge = identityResolution?.mergeOnAnonymousToKnown; + const replay = identityResolution?.replayOnVisitorToKnown; + + const result = await tryMergeUser(userId, false, merge); if (result) { - initializeUserIdAndSync(userId, disableEventReplay); + initializeUserIdAndSync(userId, replay); try { return doRequest({ userID: userId }) .then(async (token) => { diff --git a/src/utils/config.ts b/src/utils/config.ts index 0c66ee24..ea518dfb 100644 --- a/src/utils/config.ts +++ b/src/utils/config.ts @@ -7,6 +7,10 @@ export type Options = { isEuIterableService: boolean; dangerouslyAllowJsPopups: boolean; eventThresholdLimit?: number; + identityResolution?: { + replayOnVisitorToKnown?: boolean; + mergeOnAnonymousToKnown?: boolean; + }; }; const _config = () => { @@ -16,7 +20,11 @@ const _config = () => { enableAnonTracking: false, isEuIterableService: false, dangerouslyAllowJsPopups: false, - eventThresholdLimit: DEFAULT_EVENT_THRESHOLD_LIMIT + eventThresholdLimit: DEFAULT_EVENT_THRESHOLD_LIMIT, + identityResolution: { + replayOnVisitorToKnown: true, + mergeOnAnonymousToKnown: true + } }; const getConfig = (option: K) => options[option]; @@ -26,7 +34,11 @@ const _config = () => { setConfig: (newOptions: Partial) => { options = { ...options, - ...newOptions + ...newOptions, + identityResolution: { + ...options.identityResolution, + ...newOptions.identityResolution + } }; } };