From cb7c896822e3509798db5485bc63f807f037ef58 Mon Sep 17 00:00:00 2001 From: Darshan Parmar Date: Thu, 26 Sep 2024 12:36:32 +0530 Subject: [PATCH 1/5] MOB-9650 Added support for nested criteria match a.b.c --- .../criteriaCompletionChecker.ts | 4 +- src/anonymousUserTracking/tests/constants.ts | 45 +++++ .../tests/nestedTesting.test.ts | 158 +++++++++++++++++- 3 files changed, 203 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..328d40fa 100644 --- a/src/anonymousUserTracking/tests/constants.ts +++ b/src/anonymousUserTracking/tests/constants.ts @@ -834,6 +834,51 @@ 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.updateCart.updatedShoppingCartItems.quantity', + comparatorType: 'Equals', + value: '10', + fieldType: 'long' + }, + { + 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..19a9c451 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,158 @@ 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: { + updateCart: { updatedShoppingCartItems: { quantity: 10 } }, + 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': { + updateCart: { updatedShoppingCartItems: { quantity: 10 } }, + 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: { + 'updateCart.updatedShoppingCartItems.quantity': 10, + '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: { + updateCart: { updatedShoppingCartItems: { quantity: 11 } }, + 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); + }); }); From 6ad85a2b2004e9cdee53bd226205ae0ff93ce471 Mon Sep 17 00:00:00 2001 From: Darshan Parmar Date: Fri, 27 Sep 2024 17:32:30 +0530 Subject: [PATCH 2/5] fix: removed updatecart from nested criteria --- src/anonymousUserTracking/tests/constants.ts | 8 -------- src/anonymousUserTracking/tests/nestedTesting.test.ts | 4 ---- 2 files changed, 12 deletions(-) diff --git a/src/anonymousUserTracking/tests/constants.ts b/src/anonymousUserTracking/tests/constants.ts index 328d40fa..c49530f2 100644 --- a/src/anonymousUserTracking/tests/constants.ts +++ b/src/anonymousUserTracking/tests/constants.ts @@ -853,14 +853,6 @@ export const NESTED_CRITERIA_MULTI_LEVEL = { searchCombo: { combinator: 'And', searchQueries: [ - { - dataType: 'customEvent', - field: - 'button-clicked.updateCart.updatedShoppingCartItems.quantity', - comparatorType: 'Equals', - value: '10', - fieldType: 'long' - }, { dataType: 'customEvent', field: 'button-clicked.browserVisit.website.domain', diff --git a/src/anonymousUserTracking/tests/nestedTesting.test.ts b/src/anonymousUserTracking/tests/nestedTesting.test.ts index 19a9c451..68cffb8d 100644 --- a/src/anonymousUserTracking/tests/nestedTesting.test.ts +++ b/src/anonymousUserTracking/tests/nestedTesting.test.ts @@ -100,7 +100,6 @@ describe('nestedTesting', () => { { eventName: 'button-clicked', dataFields: { - updateCart: { updatedShoppingCartItems: { quantity: 10 } }, browserVisit: { website: { domain: 'https://mybrand.com/socks' } } }, eventType: 'customEvent' @@ -131,7 +130,6 @@ describe('nestedTesting', () => { eventName: 'button-clicked', dataFields: { 'button-clicked': { - updateCart: { updatedShoppingCartItems: { quantity: 10 } }, browserVisit: { website: { domain: 'https://mybrand.com/socks' } } @@ -164,7 +162,6 @@ describe('nestedTesting', () => { { eventName: 'button-clicked', dataFields: { - 'updateCart.updatedShoppingCartItems.quantity': 10, 'browserVisit.website.domain': 'https://mybrand.com/socks' }, eventType: 'customEvent' @@ -194,7 +191,6 @@ describe('nestedTesting', () => { { eventName: 'button-clicked', dataFields: { - updateCart: { updatedShoppingCartItems: { quantity: 11 } }, browserVisit: { website: { domain: 'https://mybrand.com' } } }, eventType: 'customEvent' From e3c77f475da718929a030f2c63adda5cb5d231f8 Mon Sep 17 00:00:00 2001 From: Darshan Parmar Date: Mon, 30 Sep 2024 12:04:58 +0530 Subject: [PATCH 3/5] [MOB-9652] support for nested JSON array --- .../criteriaCompletionChecker.ts | 45 +++++++++++++---- src/anonymousUserTracking/tests/constants.ts | 43 ++++++++++++++++ .../tests/nestedTesting.test.ts | 49 ++++++++++++++++++- 3 files changed, 126 insertions(+), 11 deletions(-) diff --git a/src/anonymousUserTracking/criteriaCompletionChecker.ts b/src/anonymousUserTracking/criteriaCompletionChecker.ts index 2ec9958b..81582d77 100644 --- a/src/anonymousUserTracking/criteriaCompletionChecker.ts +++ b/src/anonymousUserTracking/criteriaCompletionChecker.ts @@ -350,16 +350,41 @@ class CriteriaCompletionChecker { ); if (field.includes('.')) { - const fields = field.split('.'); - const firstElement = eventData?.[fields[0]]; - if (Array.isArray(firstElement)) { - return firstElement?.some((item: any) => { - const data = { - ...eventData, - [fields[0]]: item - }; - return this.evaluateFieldLogic(searchQueries, data); - }); + const splitedField = field.split('.') as string[]; + const fields = + eventData?.eventType === TRACK_EVENT && + eventData?.eventName === splitedField[0] + ? splitedField.slice(1) + : splitedField; + + let fieldValue = eventData; + let isSubFieldArray = false; + let isSubMatch = false; + + fields.forEach((subField) => { + const subFieldValue = fieldValue[subField]; + if (Array.isArray(subFieldValue)) { + isSubFieldArray = true; + isSubMatch = subFieldValue.some((item: any) => { + const data = fields.reduceRight((acc: any, key) => { + if (key === subField) { + return { [key]: item }; + } + return { [key]: acc }; + }, {}); + + return this.evaluateFieldLogic(searchQueries, { + ...eventData, + ...data + }); + }); + } else { + fieldValue = subFieldValue; + } + }); + + if (isSubFieldArray) { + return isSubMatch; } const valueFromObj = this.getFieldValue(eventData, field); diff --git a/src/anonymousUserTracking/tests/constants.ts b/src/anonymousUserTracking/tests/constants.ts index c49530f2..016a8bbd 100644 --- a/src/anonymousUserTracking/tests/constants.ts +++ b/src/anonymousUserTracking/tests/constants.ts @@ -871,6 +871,49 @@ export const NESTED_CRITERIA_MULTI_LEVEL = { ] }; +export const NESTED_CRITERIA_MULTI_LEVEL_ARRAY = { + count: 1, + criteriaSets: [ + { + criteriaId: '436', + name: 'Criteria 2.1 - 09252024 Bug Bash', + createdAt: 1727286807360, + updatedAt: 1727445082036, + searchQuery: { + combinator: 'And', + searchQueries: [ + { + combinator: 'And', + searchQueries: [ + { + dataType: 'user', + searchCombo: { + combinator: 'And', + searchQueries: [ + { + dataType: 'user', + field: 'furniture.material.type', + comparatorType: 'Contains', + value: 'table', + fieldType: 'string' + }, + { + dataType: 'user', + field: 'furniture.material.color', + comparatorType: 'Equals', + values: ['black'] + } + ] + } + } + ] + } + ] + } + } + ] +}; + 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 68cffb8d..dad707ce 100644 --- a/src/anonymousUserTracking/tests/nestedTesting.test.ts +++ b/src/anonymousUserTracking/tests/nestedTesting.test.ts @@ -1,6 +1,10 @@ import { SHARED_PREFS_EVENT_LIST_KEY } from '../../constants'; import CriteriaCompletionChecker from '../criteriaCompletionChecker'; -import { NESTED_CRITERIA, NESTED_CRITERIA_MULTI_LEVEL } from './constants'; +import { + NESTED_CRITERIA, + NESTED_CRITERIA_MULTI_LEVEL, + NESTED_CRITERIA_MULTI_LEVEL_ARRAY +} from './constants'; const localStorageMock = { getItem: jest.fn(), @@ -242,4 +246,47 @@ describe('nestedTesting', () => { ); expect(result).toEqual(null); }); + + it('should return criteriaId 436 (Multi level Nested field criteria)', () => { + (localStorage.getItem as jest.Mock).mockImplementation((key) => { + if (key === SHARED_PREFS_EVENT_LIST_KEY) { + return JSON.stringify([ + { + dataFields: { + furniture: { + material: [ + { + type: 'table', + color: 'black', + lengthInches: 40, + widthInches: 60 + }, + { + type: 'Sofa', + color: 'Gray', + lengthInches: 20, + widthInches: 30 + } + ] + } + }, + eventType: 'user' + } + ]); + } + 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_ARRAY) + ); + expect(result).toEqual('436'); + }); }); From 8bb085e5a3696b9a77156d69dad119296b4b9b3a Mon Sep 17 00:00:00 2001 From: Darshan Parmar Date: Wed, 2 Oct 2024 10:40:11 +0530 Subject: [PATCH 4/5] [MOB-9652] customEvent test case for nested JSON array --- .../criteriaCompletionChecker.ts | 8 +- src/anonymousUserTracking/tests/constants.ts | 44 ++++++ .../tests/nestedTesting.test.ts | 126 +++++++++++++++++- 3 files changed, 173 insertions(+), 5 deletions(-) diff --git a/src/anonymousUserTracking/criteriaCompletionChecker.ts b/src/anonymousUserTracking/criteriaCompletionChecker.ts index 81582d77..59368e16 100644 --- a/src/anonymousUserTracking/criteriaCompletionChecker.ts +++ b/src/anonymousUserTracking/criteriaCompletionChecker.ts @@ -350,12 +350,12 @@ class CriteriaCompletionChecker { ); if (field.includes('.')) { - const splitedField = field.split('.') as string[]; + const splitField = field.split('.') as string[]; const fields = eventData?.eventType === TRACK_EVENT && - eventData?.eventName === splitedField[0] - ? splitedField.slice(1) - : splitedField; + eventData?.eventName === splitField[0] + ? splitField.slice(1) + : splitField; let fieldValue = eventData; let isSubFieldArray = false; diff --git a/src/anonymousUserTracking/tests/constants.ts b/src/anonymousUserTracking/tests/constants.ts index 016a8bbd..1ea20165 100644 --- a/src/anonymousUserTracking/tests/constants.ts +++ b/src/anonymousUserTracking/tests/constants.ts @@ -914,6 +914,50 @@ export const NESTED_CRITERIA_MULTI_LEVEL_ARRAY = { ] }; +export const NESTED_CRITERIA_MULTI_LEVEL_ARRAY_TRACK_EVENT = { + count: 1, + criteriaSets: [ + { + criteriaId: '459', + name: 'event a.h.b=d && a.h.c=g', + createdAt: 1721251169153, + updatedAt: 1723488175352, + searchQuery: { + combinator: 'And', + searchQueries: [ + { + combinator: 'And', + searchQueries: [ + { + dataType: 'customEvent', + searchCombo: { + combinator: 'And', + searchQueries: [ + { + dataType: 'customEvent', + field: 'TopLevelArrayObject.a.h.b', + comparatorType: 'Equals', + value: 'd', + fieldType: 'string' + }, + { + dataType: 'customEvent', + field: 'TopLevelArrayObject.a.h.c', + comparatorType: 'Equals', + value: 'g', + 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 dad707ce..be149ffc 100644 --- a/src/anonymousUserTracking/tests/nestedTesting.test.ts +++ b/src/anonymousUserTracking/tests/nestedTesting.test.ts @@ -3,7 +3,8 @@ import CriteriaCompletionChecker from '../criteriaCompletionChecker'; import { NESTED_CRITERIA, NESTED_CRITERIA_MULTI_LEVEL, - NESTED_CRITERIA_MULTI_LEVEL_ARRAY + NESTED_CRITERIA_MULTI_LEVEL_ARRAY, + NESTED_CRITERIA_MULTI_LEVEL_ARRAY_TRACK_EVENT } from './constants'; const localStorageMock = { @@ -289,4 +290,127 @@ describe('nestedTesting', () => { ); expect(result).toEqual('436'); }); + + 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([ + { + dataFields: { + furniture: { + material: [ + { + type: 'table', + color: 'Gray', + lengthInches: 40, + widthInches: 60 + }, + { + type: 'Sofa', + color: 'black', + lengthInches: 20, + widthInches: 30 + } + ] + } + }, + eventType: 'user' + } + ]); + } + 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_ARRAY) + ); + expect(result).toEqual(null); + }); + + it('should return criteriaId 459 (Multi level Nested field criteria)', () => { + (localStorage.getItem as jest.Mock).mockImplementation((key) => { + if (key === SHARED_PREFS_EVENT_LIST_KEY) { + return JSON.stringify([ + { + eventName: 'TopLevelArrayObject', + dataFields: { + a: { + h: [ + { + b: 'e', + c: 'h' + }, + { + b: 'd', + c: 'g' + } + ] + } + }, + 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_ARRAY_TRACK_EVENT) + ); + expect(result).toEqual('459'); + }); + + 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: 'TopLevelArrayObject', + dataFields: { + a: { + h: [ + { + b: 'd', + c: 'h' + }, + { + b: 'e', + c: 'g' + } + ] + } + }, + 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_ARRAY_TRACK_EVENT) + ); + expect(result).toEqual(null); + }); }); From b7ab517aeaeddcec55ef645735beaaab6fa576bd Mon Sep 17 00:00:00 2001 From: darshan-iterable Date: Thu, 3 Oct 2024 19:54:26 +0530 Subject: [PATCH 5/5] [MOB-9168] Automated unit tests against complex criteria (#461) * [MOB-9168] Automated unit tests against complex criteria * [MOB-9168] Automated unit tests against complex criteria --- .../tests/complexCriteria.test.ts | 253 +++++++++++ src/anonymousUserTracking/tests/constants.ts | 399 ++++++++++++++++++ 2 files changed, 652 insertions(+) diff --git a/src/anonymousUserTracking/tests/complexCriteria.test.ts b/src/anonymousUserTracking/tests/complexCriteria.test.ts index 06f5cbdf..973262eb 100644 --- a/src/anonymousUserTracking/tests/complexCriteria.test.ts +++ b/src/anonymousUserTracking/tests/complexCriteria.test.ts @@ -1,5 +1,10 @@ import { SHARED_PREFS_EVENT_LIST_KEY } from '../../constants'; import CriteriaCompletionChecker from '../criteriaCompletionChecker'; +import { + COMPLEX_CRITERIA_1, + COMPLEX_CRITERIA_2, + COMPLEX_CRITERIA_3 +} from './constants'; const localStorageMock = { getItem: jest.fn(), @@ -1598,4 +1603,252 @@ describe('complexCriteria', () => { ); expect(result).toEqual(null); }); + + // MARK: Complex criteria #1 + it('should return criteriaId 290 if (1 OR 2 OR 3) AND (4 AND 5) AND (6 NOT 7) matched', () => { + (localStorage.getItem as jest.Mock).mockImplementation((key) => { + if (key === SHARED_PREFS_EVENT_LIST_KEY) { + return JSON.stringify([ + { + dataFields: { + saved_cars: { color: 'black' }, + 'animal-found': { vaccinated: true }, + eventName: 'birthday' + }, + eventType: 'customEvent' + }, + { + dataFields: { reason: 'testing', total: 30 }, + eventType: 'purchase' + }, + { + dataFields: { firstName: 'Adam' }, + eventType: 'user' + } + ]); + } + return null; + }); + + const localStoredEventList = localStorage.getItem( + SHARED_PREFS_EVENT_LIST_KEY + ); + + const checker = new CriteriaCompletionChecker( + localStoredEventList === null ? '' : localStoredEventList + ); + const result = checker.getMatchedCriteria( + JSON.stringify(COMPLEX_CRITERIA_1) + ); + expect(result).toEqual('290'); + }); + + it('should return criteriaId null if (1 OR 2 OR 3) AND (4 AND 5) AND (6 NOT 7) - No match', () => { + (localStorage.getItem as jest.Mock).mockImplementation((key) => { + if (key === SHARED_PREFS_EVENT_LIST_KEY) { + return JSON.stringify([ + { + eventType: 'user', + dataFields: { + firstName: 'Alex' + } + }, + { + eventType: 'customEvent', + eventName: 'saved_cars', + dataFields: { + color: '' + } + }, + { + eventType: 'customEvent', + eventName: 'animal-found', + dataFields: { + vaccinated: true + } + }, + { + eventType: 'purchase', + dataFields: { + total: 30, + reason: 'testing' + } + } + ]); + } + return null; + }); + + const localStoredEventList = localStorage.getItem( + SHARED_PREFS_EVENT_LIST_KEY + ); + + const checker = new CriteriaCompletionChecker( + localStoredEventList === null ? '' : localStoredEventList + ); + const result = checker.getMatchedCriteria( + JSON.stringify(COMPLEX_CRITERIA_1) + ); + expect(result).toEqual(null); + }); + + // MARK: Complex criteria #2 + it('should return criteriaId 291 if (6 OR 7) OR (4 AND 5) OR (1 NOT 2 NOT 3) matched', () => { + (localStorage.getItem as jest.Mock).mockImplementation((key) => { + if (key === SHARED_PREFS_EVENT_LIST_KEY) { + return JSON.stringify([ + { + eventType: 'user', + dataFields: { + firstName: 'xcode' + } + }, + { + eventType: 'customEvent', + eventName: 'saved_cars', + dataFields: { + color: 'black' + } + }, + { + eventType: 'customEvent', + eventName: 'animal-found', + dataFields: { + vaccinated: true + } + }, + { + eventType: 'purchase', + dataFields: { + total: 110, + reason: 'testing' + } + } + ]); + } + return null; + }); + + const localStoredEventList = localStorage.getItem( + SHARED_PREFS_EVENT_LIST_KEY + ); + + const checker = new CriteriaCompletionChecker( + localStoredEventList === null ? '' : localStoredEventList + ); + const result = checker.getMatchedCriteria( + JSON.stringify(COMPLEX_CRITERIA_2) + ); + expect(result).toEqual('291'); + }); + + it('should return criteriaId null if (6 OR 7) OR (4 AND 5) OR (1 NOT 2 NOT 3) - No match', () => { + (localStorage.getItem as jest.Mock).mockImplementation((key) => { + if (key === SHARED_PREFS_EVENT_LIST_KEY) { + return JSON.stringify([ + { + eventType: 'user', + dataFields: { + firstName: 'Alex' + } + }, + { + eventType: 'purchase', + dataFields: { + total: 10, + reason: 'null' + } + } + ]); + } + return null; + }); + + const localStoredEventList = localStorage.getItem( + SHARED_PREFS_EVENT_LIST_KEY + ); + + const checker = new CriteriaCompletionChecker( + localStoredEventList === null ? '' : localStoredEventList + ); + const result = checker.getMatchedCriteria( + JSON.stringify(COMPLEX_CRITERIA_2) + ); + expect(result).toEqual(null); + }); + + // MARK: Complex criteria #3 + it('should return criteriaId 292 if (1 AND 2) NOR (3 OR 4 OR 5) NOR (6 NOR 7) matched', () => { + (localStorage.getItem as jest.Mock).mockImplementation((key) => { + if (key === SHARED_PREFS_EVENT_LIST_KEY) { + return JSON.stringify([ + { + dataType: 'user', + dataFields: { + firstName: 'xcode', + lastName: 'ssr' + } + }, + { + dataType: 'customEvent', + eventName: 'animal-found', + dataFields: { + vaccinated: true, + count: 10 + } + } + ]); + } + return null; + }); + + const localStoredEventList = localStorage.getItem( + SHARED_PREFS_EVENT_LIST_KEY + ); + + const checker = new CriteriaCompletionChecker( + localStoredEventList === null ? '' : localStoredEventList + ); + const result = checker.getMatchedCriteria( + JSON.stringify(COMPLEX_CRITERIA_3) + ); + expect(result).toEqual('292'); + }); + + it('should return criteriaId null if (1 AND 2) NOR (3 OR 4 OR 5) NOR (6 NOR 7) - No match', () => { + (localStorage.getItem as jest.Mock).mockImplementation((key) => { + if (key === SHARED_PREFS_EVENT_LIST_KEY) { + return JSON.stringify([ + { + eventType: 'user', + dataFields: { + firstName: 'Alex', + lastName: 'Aris' + } + }, + { + eventType: 'customEvent', + eventName: 'animal-found', + dataFields: { + vaccinated: false, + count: 4 + } + } + ]); + } + return null; + }); + + const localStoredEventList = localStorage.getItem( + SHARED_PREFS_EVENT_LIST_KEY + ); + + const checker = new CriteriaCompletionChecker( + localStoredEventList === null ? '' : localStoredEventList + ); + const result = checker.getMatchedCriteria( + JSON.stringify(COMPLEX_CRITERIA_3) + ); + expect(result).toEqual(null); + }); }); diff --git a/src/anonymousUserTracking/tests/constants.ts b/src/anonymousUserTracking/tests/constants.ts index 1ea20165..b8f1c047 100644 --- a/src/anonymousUserTracking/tests/constants.ts +++ b/src/anonymousUserTracking/tests/constants.ts @@ -1180,3 +1180,402 @@ export const USER_MERGE_SCENARIO_CRITERIA = { } ] }; + +// MARK:Complex Criteria + +export const COMPLEX_CRITERIA_1 = { + count: 1, + criteriaSets: [ + { + criteriaId: '290', + name: 'Complex Criteria Unit Test #1', + createdAt: 1722532861551, + updatedAt: 1722532861551, + searchQuery: { + combinator: 'And', + searchQueries: [ + { + combinator: 'Or', + searchQueries: [ + { + dataType: 'user', + searchCombo: { + combinator: 'And', + searchQueries: [ + { + dataType: 'user', + field: 'firstName', + comparatorType: 'StartsWith', + value: 'A', + fieldType: 'string' + } + ] + } + }, + { + dataType: 'user', + searchCombo: { + combinator: 'And', + searchQueries: [ + { + dataType: 'user', + field: 'firstName', + comparatorType: 'StartsWith', + value: 'B', + fieldType: 'string' + } + ] + } + }, + { + dataType: 'user', + searchCombo: { + combinator: 'And', + searchQueries: [ + { + dataType: 'user', + field: 'firstName', + comparatorType: 'StartsWith', + value: 'C', + fieldType: 'string' + } + ] + } + } + ] + }, + { + combinator: 'And', + searchQueries: [ + { + dataType: 'customEvent', + searchCombo: { + combinator: 'And', + searchQueries: [ + { + dataType: 'customEvent', + field: 'eventName', + comparatorType: 'IsSet', + value: '', + fieldType: 'string' + }, + { + dataType: 'customEvent', + field: 'saved_cars.color', + comparatorType: 'IsSet', + value: '', + fieldType: 'string' + } + ] + } + }, + { + dataType: 'customEvent', + searchCombo: { + combinator: 'And', + searchQueries: [ + { + dataType: 'customEvent', + field: 'eventName', + comparatorType: 'IsSet', + value: '', + fieldType: 'string' + }, + { + dataType: 'customEvent', + field: 'animal-found.vaccinated', + comparatorType: 'Equals', + value: 'true', + fieldType: 'boolean' + } + ] + } + } + ] + }, + { + combinator: 'Not', + searchQueries: [ + { + dataType: 'purchase', + searchCombo: { + combinator: 'And', + searchQueries: [ + { + dataType: 'purchase', + field: 'total', + comparatorType: 'LessThanOrEqualTo', + value: '100', + fieldType: 'double' + } + ] + } + }, + { + dataType: 'purchase', + searchCombo: { + combinator: 'And', + searchQueries: [ + { + dataType: 'purchase', + field: 'reason', + comparatorType: 'Equals', + value: 'null', + fieldType: 'string' + } + ] + } + } + ] + } + ] + } + } + ] +}; + +export const COMPLEX_CRITERIA_2 = { + count: 1, + criteriaSets: [ + { + criteriaId: '291', + name: 'Complex Criteria Unit Test #2', + createdAt: 1722533473263, + updatedAt: 1722533473263, + searchQuery: { + combinator: 'Or', + searchQueries: [ + { + combinator: 'Not', + searchQueries: [ + { + dataType: 'user', + searchCombo: { + combinator: 'And', + searchQueries: [ + { + dataType: 'user', + field: 'firstName', + comparatorType: 'StartsWith', + value: 'A', + fieldType: 'string' + } + ] + } + }, + { + dataType: 'user', + searchCombo: { + combinator: 'And', + searchQueries: [ + { + dataType: 'user', + field: 'firstName', + comparatorType: 'StartsWith', + value: 'B', + fieldType: 'string' + } + ] + } + }, + { + dataType: 'user', + searchCombo: { + combinator: 'And', + searchQueries: [ + { + dataType: 'user', + field: 'firstName', + comparatorType: 'StartsWith', + value: 'C', + fieldType: 'string' + } + ] + } + } + ] + }, + { + combinator: 'And', + searchQueries: [ + { + dataType: 'customEvent', + searchCombo: { + combinator: 'And', + searchQueries: [ + { + dataType: 'customEvent', + field: 'eventName', + comparatorType: 'IsSet', + value: '', + fieldType: 'string' + }, + { + dataType: 'customEvent', + field: 'saved_cars.color', + comparatorType: 'IsSet', + value: '', + fieldType: 'string' + } + ] + } + }, + { + dataType: 'customEvent', + searchCombo: { + combinator: 'And', + searchQueries: [ + { + dataType: 'customEvent', + field: 'animal-found.vaccinated', + comparatorType: 'Equals', + value: 'true', + fieldType: 'boolean' + } + ] + } + } + ] + }, + { + combinator: 'Or', + searchQueries: [ + { + dataType: 'purchase', + searchCombo: { + combinator: 'And', + searchQueries: [ + { + dataType: 'purchase', + field: 'total', + comparatorType: 'GreaterThanOrEqualTo', + value: '100', + fieldType: 'double' + } + ] + } + }, + { + dataType: 'purchase', + searchCombo: { + combinator: 'And', + searchQueries: [ + { + dataType: 'purchase', + field: 'reason', + comparatorType: 'DoesNotEqual', + value: 'null', + fieldType: 'string' + } + ] + } + } + ] + } + ] + } + } + ] +}; + +export const COMPLEX_CRITERIA_3 = { + count: 1, + criteriaSets: [ + { + criteriaId: '292', + name: 'Complex Criteria Unit Test #3', + createdAt: 1722533789589, + updatedAt: 1722533838989, + searchQuery: { + combinator: 'Not', + searchQueries: [ + { + combinator: 'And', + searchQueries: [ + { + dataType: 'user', + searchCombo: { + combinator: 'And', + searchQueries: [ + { + dataType: 'user', + field: 'firstName', + comparatorType: 'StartsWith', + value: 'A', + fieldType: 'string' + } + ] + } + }, + { + dataType: 'user', + searchCombo: { + combinator: 'And', + searchQueries: [ + { + dataType: 'user', + field: 'lastName', + comparatorType: 'StartsWith', + value: 'A', + fieldType: 'string' + } + ] + } + } + ] + }, + { + combinator: 'Or', + searchQueries: [ + { + dataType: 'user', + searchCombo: { + combinator: 'And', + searchQueries: [ + { + dataType: 'user', + field: 'firstName', + comparatorType: 'StartsWith', + value: 'C', + fieldType: 'string' + } + ] + } + }, + { + dataType: 'customEvent', + searchCombo: { + combinator: 'And', + searchQueries: [ + { + dataType: 'customEvent', + field: 'animal-found.vaccinated', + comparatorType: 'Equals', + value: 'false', + fieldType: 'boolean' + } + ] + } + }, + { + dataType: 'customEvent', + searchCombo: { + combinator: 'And', + searchQueries: [ + { + dataType: 'customEvent', + field: 'animal-found.count', + comparatorType: 'LessThan', + value: '5', + fieldType: 'long' + } + ] + } + } + ] + } + ] + } + } + ] +};