From 5b7ffa0b65c247691a4345339f441fe61f3b169c Mon Sep 17 00:00:00 2001 From: darshan-iterable Date: Wed, 2 Oct 2024 20:48:19 +0530 Subject: [PATCH 1/2] [MOB-9578] implements identity resolution (#458) --- .../tests/userMergeScenarios.test.ts | 184 +++++++++++++----- src/authorization/authorization.ts | 66 ++++--- src/utils/config.ts | 16 +- 3 files changed, 189 insertions(+), 77 deletions(-) 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 + } }; } }; From 604ea663f9658ee35c2287b389f5fd5c36c4ae67 Mon Sep 17 00:00:00 2001 From: darshan-iterable Date: Wed, 2 Oct 2024 20:58:27 +0530 Subject: [PATCH 2/2] MOB-9650 Added support for nested criteria match a.b.c (#457) * MOB-9650 Added support for nested criteria match a.b.c * fix: removed updatecart from nested criteria --- .../criteriaCompletionChecker.ts | 4 +- src/anonymousUserTracking/tests/constants.ts | 37 +++++ .../tests/nestedTesting.test.ts | 154 +++++++++++++++++- 3 files changed, 191 insertions(+), 4 deletions(-) diff --git a/src/anonymousUserTracking/criteriaCompletionChecker.ts b/src/anonymousUserTracking/criteriaCompletionChecker.ts index db2121a8..2ec9958b 100644 --- a/src/anonymousUserTracking/criteriaCompletionChecker.ts +++ b/src/anonymousUserTracking/criteriaCompletionChecker.ts @@ -383,9 +383,9 @@ class CriteriaCompletionChecker { } private getFieldValue(data: any, field: string): any { - let fields = field.split('.'); + const fields: string[] = field.split('.'); if (data?.eventType === TRACK_EVENT && data?.eventName === fields[0]) { - fields = [fields[fields.length - 1]]; + fields.shift(); } return fields.reduce( (value, currentField) => diff --git a/src/anonymousUserTracking/tests/constants.ts b/src/anonymousUserTracking/tests/constants.ts index c99ed181..c49530f2 100644 --- a/src/anonymousUserTracking/tests/constants.ts +++ b/src/anonymousUserTracking/tests/constants.ts @@ -834,6 +834,43 @@ export const NESTED_CRITERIA = { ] }; +export const NESTED_CRITERIA_MULTI_LEVEL = { + count: 1, + criteriaSets: [ + { + criteriaId: '425', + name: 'Multi level Nested field criteria', + createdAt: 1721251169153, + updatedAt: 1723488175352, + searchQuery: { + combinator: 'And', + searchQueries: [ + { + combinator: 'And', + searchQueries: [ + { + dataType: 'customEvent', + searchCombo: { + combinator: 'And', + searchQueries: [ + { + dataType: 'customEvent', + field: 'button-clicked.browserVisit.website.domain', + comparatorType: 'Equals', + value: 'https://mybrand.com/socks', + fieldType: 'string' + } + ] + } + } + ] + } + ] + } + } + ] +}; + export const IS_ONE_OF_CRITERIA = { count: 1, criteriaSets: [ diff --git a/src/anonymousUserTracking/tests/nestedTesting.test.ts b/src/anonymousUserTracking/tests/nestedTesting.test.ts index c1a85db9..68cffb8d 100644 --- a/src/anonymousUserTracking/tests/nestedTesting.test.ts +++ b/src/anonymousUserTracking/tests/nestedTesting.test.ts @@ -1,6 +1,6 @@ import { SHARED_PREFS_EVENT_LIST_KEY } from '../../constants'; import CriteriaCompletionChecker from '../criteriaCompletionChecker'; -import { NESTED_CRITERIA } from './constants'; +import { NESTED_CRITERIA, NESTED_CRITERIA_MULTI_LEVEL } from './constants'; const localStorageMock = { getItem: jest.fn(), @@ -53,7 +53,7 @@ describe('nestedTesting', () => { expect(result).toEqual('168'); }); - it('should return criteriaId 168 (nested field - No match)', () => { + it('should return criteriaId null (nested field - No match)', () => { (localStorage.getItem as jest.Mock).mockImplementation((key) => { if (key === SHARED_PREFS_EVENT_LIST_KEY) { return JSON.stringify([ @@ -92,4 +92,154 @@ describe('nestedTesting', () => { const result = checker.getMatchedCriteria(JSON.stringify(NESTED_CRITERIA)); expect(result).toEqual(null); }); + + it('should return criteriaId 425 (Multi level Nested field criteria)', () => { + (localStorage.getItem as jest.Mock).mockImplementation((key) => { + if (key === SHARED_PREFS_EVENT_LIST_KEY) { + return JSON.stringify([ + { + eventName: 'button-clicked', + dataFields: { + browserVisit: { website: { domain: 'https://mybrand.com/socks' } } + }, + eventType: 'customEvent' + } + ]); + } + return null; + }); + + const localStoredEventList = localStorage.getItem( + SHARED_PREFS_EVENT_LIST_KEY + ); + + const checker = new CriteriaCompletionChecker( + localStoredEventList === null ? '' : localStoredEventList + ); + const result = checker.getMatchedCriteria( + JSON.stringify(NESTED_CRITERIA_MULTI_LEVEL) + ); + expect(result).toEqual('425'); + }); + + it('should return criteriaId 425 (Multi level Nested field criteria - No match)', () => { + (localStorage.getItem as jest.Mock).mockImplementation((key) => { + if (key === SHARED_PREFS_EVENT_LIST_KEY) { + return JSON.stringify([ + { + eventName: 'button-clicked', + dataFields: { + 'button-clicked': { + browserVisit: { + website: { domain: 'https://mybrand.com/socks' } + } + } + }, + eventType: 'customEvent' + } + ]); + } + return null; + }); + + const localStoredEventList = localStorage.getItem( + SHARED_PREFS_EVENT_LIST_KEY + ); + + const checker = new CriteriaCompletionChecker( + localStoredEventList === null ? '' : localStoredEventList + ); + const result = checker.getMatchedCriteria( + JSON.stringify(NESTED_CRITERIA_MULTI_LEVEL) + ); + expect(result).toEqual(null); + }); + + it('should return criteriaId null (Multi level Nested field criteria - No match)', () => { + (localStorage.getItem as jest.Mock).mockImplementation((key) => { + if (key === SHARED_PREFS_EVENT_LIST_KEY) { + return JSON.stringify([ + { + eventName: 'button-clicked', + dataFields: { + 'browserVisit.website.domain': 'https://mybrand.com/socks' + }, + eventType: 'customEvent' + } + ]); + } + return null; + }); + + const localStoredEventList = localStorage.getItem( + SHARED_PREFS_EVENT_LIST_KEY + ); + + const checker = new CriteriaCompletionChecker( + localStoredEventList === null ? '' : localStoredEventList + ); + const result = checker.getMatchedCriteria( + JSON.stringify(NESTED_CRITERIA_MULTI_LEVEL) + ); + expect(result).toEqual(null); + }); + + it('should return criteriaId null (Multi level Nested field criteria - No match)', () => { + (localStorage.getItem as jest.Mock).mockImplementation((key) => { + if (key === SHARED_PREFS_EVENT_LIST_KEY) { + return JSON.stringify([ + { + eventName: 'button-clicked', + dataFields: { + browserVisit: { website: { domain: 'https://mybrand.com' } } + }, + eventType: 'customEvent' + } + ]); + } + return null; + }); + + const localStoredEventList = localStorage.getItem( + SHARED_PREFS_EVENT_LIST_KEY + ); + + const checker = new CriteriaCompletionChecker( + localStoredEventList === null ? '' : localStoredEventList + ); + const result = checker.getMatchedCriteria( + JSON.stringify(NESTED_CRITERIA_MULTI_LEVEL) + ); + expect(result).toEqual(null); + }); + + it('should return criteriaId null (Multi level Nested field criteria - No match)', () => { + (localStorage.getItem as jest.Mock).mockImplementation((key) => { + if (key === SHARED_PREFS_EVENT_LIST_KEY) { + return JSON.stringify([ + { + eventName: 'button-clicked', + dataFields: { + quantity: 11, + domain: 'https://mybrand.com/socks' + }, + eventType: 'customEvent' + } + ]); + } + return null; + }); + + const localStoredEventList = localStorage.getItem( + SHARED_PREFS_EVENT_LIST_KEY + ); + + const checker = new CriteriaCompletionChecker( + localStoredEventList === null ? '' : localStoredEventList + ); + const result = checker.getMatchedCriteria( + JSON.stringify(NESTED_CRITERIA_MULTI_LEVEL) + ); + expect(result).toEqual(null); + }); });