From 9ae4d4dc1428a7c021ec2f3e28c3df9e0c649e9c Mon Sep 17 00:00:00 2001 From: Alexander Sapountzis Date: Tue, 10 Jun 2025 12:46:48 -0400 Subject: [PATCH 1/5] style: Clean up lint --- package.json | 1 + src/apiClient.ts | 80 +- src/audience.ts | 4 +- src/audienceManager.ts | 57 +- src/batchUploader.ts | 68 +- src/configAPIClient.ts | 11 +- src/consent.ts | 75 +- src/cookieSyncManager.ts | 44 +- src/ecommerce.interfaces.ts | 38 +- src/ecommerce.js | 148 +- src/events.interfaces.ts | 20 +- src/events.js | 181 +- src/filteredMparticleUser.js | 53 +- src/foregroundTimeTracker.ts | 20 +- src/forwarders.interfaces.ts | 14 +- src/forwarders.js | 378 +- src/forwardingStatsUploader.js | 18 +- src/helpers.js | 91 +- src/identity-utils.ts | 44 +- src/identity.interfaces.ts | 32 +- src/identity.js | 692 ++-- src/identityApiClient.ts | 106 +- src/integrationCapture.ts | 57 +- src/kitBlocking.ts | 274 +- src/kitFilterHelper.ts | 82 +- src/logger.js | 18 +- src/mockBatchCreator.ts | 23 +- src/mp-instance.ts | 314 +- src/mparticle-instance-manager.ts | 207 +- src/nativeSdkHelpers.interfaces.ts | 8 +- src/nativeSdkHelpers.js | 54 +- src/persistence.interfaces.ts | 9 +- src/persistence.js | 272 +- src/polyfill.js | 60 +- src/pre-init-utils.ts | 16 +- src/roktManager.ts | 139 +- src/sdkRuntimeModels.ts | 63 +- src/sdkToEventsApiConverter.ts | 144 +- src/serverModel.ts | 121 +- src/sessionManager.ts | 51 +- src/sideloadedKit.ts | 35 +- src/store.ts | 75 +- src/stub/mparticle.stub.js | 6 +- src/types.ts | 13 +- src/uploaders.ts | 12 +- src/user-utils.ts | 18 +- src/utils.ts | 84 +- src/validators.ts | 55 +- src/vault.ts | 6 +- test/src/_test.index.ts | 1 - test/src/config/constants.ts | 13 +- test/src/config/setup.ts | 8 +- test/src/config/utils.js | 285 +- test/src/tests-apiClient.ts | 14 +- test/src/tests-audience-manager.ts | 105 +- test/src/tests-batchUploader.ts | 2123 ++++++----- test/src/tests-batchUploader_2.ts | 237 +- test/src/tests-batchUploader_3.ts | 671 ++-- test/src/tests-batchUploader_4.ts | 386 +- test/src/tests-beaconUpload.ts | 356 +- test/src/tests-config-api-client.ts | 29 +- test/src/tests-consent.ts | 352 +- test/src/tests-cookie-syncing.ts | 282 +- test/src/tests-core-sdk.js | 1891 +++++---- test/src/tests-eCommerce.js | 3394 ++++++++++------- test/src/tests-event-logging.js | 2615 ++++++------- test/src/tests-feature-flags.ts | 145 +- test/src/tests-forwarders.ts | 1444 ++++--- test/src/tests-helpers.js | 105 +- test/src/tests-identities-attributes.ts | 2549 +++++++------ test/src/tests-identity-utils.ts | 250 +- test/src/tests-identity.ts | 3583 ++++++++++-------- test/src/tests-identityApiClient.ts | 469 ++- test/src/tests-integration-capture.ts | 479 ++- test/src/tests-kit-blocking.ts | 2371 +++++++----- test/src/tests-legacy-alias-requests.ts | 239 +- test/src/tests-mParticleUser.js | 326 +- test/src/tests-mockBatchCreator.ts | 54 +- test/src/tests-mparticle-instance-manager.ts | 98 +- test/src/tests-native-sdk.js | 549 +-- test/src/tests-persistence.ts | 3128 +++++++-------- test/src/tests-queue-public-methods.js | 421 +- test/src/tests-runtimeToBatchEventsDTO.ts | 231 +- test/src/tests-self-hosting-specific.js | 135 +- test/src/tests-serverModel.ts | 557 ++- test/src/tests-session-manager.ts | 117 +- test/src/tests-store.ts | 272 +- test/src/tests-types.js | 102 +- test/src/tests-user.ts | 309 +- test/src/tests-utils.ts | 74 +- test/src/tests-validators.ts | 49 +- test/src/vault.spec.ts | 94 +- 92 files changed, 19554 insertions(+), 15749 deletions(-) diff --git a/package.json b/package.json index e652aa788..64d74c44e 100644 --- a/package.json +++ b/package.json @@ -65,6 +65,7 @@ "watch:all": "cross-env ENVIRONMENT=prod BUILDALL=true rollup --config rollup.config.js -w", "watch:tests": "cross-env ENVIRONMENT=dev TESTTYPE=main rollup --config rollup.test.config.js -w", "lint": "eslint src/ test/src/", + "lint:fix": "eslint src/ test/src/ --fix", "gts:check": "gts check", "gts:fix": "gts fix", "prettier": "node_modules/.bin/prettier --check \"**/*.js\"", diff --git a/src/apiClient.ts b/src/apiClient.ts index 5e0a2fe76..d95512104 100644 --- a/src/apiClient.ts +++ b/src/apiClient.ts @@ -20,12 +20,12 @@ export interface IAPIClient { sendSingleEventToServer: (event: SDKEvent) => void; sendBatchForwardingStatsToServer: ( forwardingStatsData: IForwardingStatsData, - xhr: XMLHttpRequest + xhr: XMLHttpRequest, ) => void; initializeForwarderStatsUploader: () => AsyncUploader; prepareForwardingStats: ( forwarder: MPForwarder, - event: IUploadObject + event: IUploadObject, ) => void; } @@ -46,16 +46,18 @@ export interface IForwardingStatsData { export default function APIClient( this: IAPIClient, mpInstance: IMParticleWebSDKInstance, - kitBlocker: KitBlocker + kitBlocker: KitBlocker, ) { this.uploader = null; const self = this; - this.queueEventForBatchUpload = function(event: SDKEvent) { + this.queueEventForBatchUpload = function (event: SDKEvent) { if (!this.uploader) { // https://go.mparticle.com/work/SQDSDKS-6317 - const millis: number = parseNumber(mpInstance._Helpers.getFeatureFlag( - Constants.FeatureFlags.EventBatchingIntervalMillis - ) as string); + const millis: number = parseNumber( + mpInstance._Helpers.getFeatureFlag( + Constants.FeatureFlags.EventBatchingIntervalMillis, + ) as string, + ); this.uploader = new BatchUploader(mpInstance, millis); } this.uploader.queueEvent(event); @@ -64,9 +66,9 @@ export default function APIClient( mpInstance._Persistence.update(); }; - this.processQueuedEvents = function() { - let mpid, - currentUser = mpInstance.Identity.getCurrentUser(); + this.processQueuedEvents = function () { + let mpid; + const currentUser = mpInstance.Identity.getCurrentUser(); if (currentUser) { mpid = currentUser.getMPID(); } @@ -74,21 +76,21 @@ export default function APIClient( const localQueueCopy = mpInstance._Store.eventQueue; mpInstance._Store.eventQueue = []; this.appendUserInfoToEvents(currentUser, localQueueCopy); - localQueueCopy.forEach(function(event) { + localQueueCopy.forEach(function (event) { self.sendEventToServer(event); }); } }; - this.appendUserInfoToEvents = function(user, events) { - events.forEach(function(event) { + this.appendUserInfoToEvents = function (user, events) { + events.forEach(function (event) { if (!event.MPID) { appendUserInfo(user, event); } }); }; - this.sendEventToServer = function(event, _options) { + this.sendEventToServer = function (event, _options) { const defaultOptions = { shouldUploadEvent: true, }; @@ -97,21 +99,22 @@ export default function APIClient( if (mpInstance._Store.webviewBridgeEnabled) { mpInstance._NativeSdkHelpers.sendToNative( Constants.NativeSdkPaths.LogEvent, - JSON.stringify(event) + JSON.stringify(event), ); return; } - let mpid, - currentUser = mpInstance.Identity.getCurrentUser(); + let mpid; + const currentUser = mpInstance.Identity.getCurrentUser(); if (currentUser) { mpid = currentUser.getMPID(); } - mpInstance._Store.requireDelay = mpInstance._Helpers.isDelayedByIntegration( - mpInstance._preInit.integrationDelays, - mpInstance._Store.integrationDelayTimeoutStart, - Date.now() - ); + mpInstance._Store.requireDelay = + mpInstance._Helpers.isDelayedByIntegration( + mpInstance._preInit.integrationDelays, + mpInstance._Store.integrationDelayTimeoutStart, + Date.now(), + ); // We queue events if there is no MPID (MPID is null, or === 0), or there are integrations that that require this to stall because integration attributes // need to be set, or if we are still fetching the config (self hosted only), and so require delaying events if ( @@ -120,7 +123,7 @@ export default function APIClient( !mpInstance._Store.configurationLoaded ) { mpInstance.Logger.verbose( - 'Event was added to eventQueue. eventQueue will be processed once a valid MPID is returned or there is no more integration imposed delay.' + 'Event was added to eventQueue. eventQueue will be processed once a valid MPID is returned or there is no more integration imposed delay.', ); mpInstance._Store.eventQueue.push(event); return; @@ -140,7 +143,10 @@ export default function APIClient( // https://go.mparticle.com/work/SQDSDKS-6935 // While Event Name is 'usually' a string, there are some cases where it is a number // in that it could be a type of MessageType Enum - if (event.EventName as unknown as number !== Types.MessageType.AppStateTransition) { + if ( + (event.EventName as unknown as number) !== + Types.MessageType.AppStateTransition + ) { if (kitBlocker && kitBlocker.kitBlockingEnabled) { event = kitBlocker.createBlockedEvent(event); } @@ -153,13 +159,16 @@ export default function APIClient( } }; - this.sendBatchForwardingStatsToServer = function(forwardingStatsData, xhr) { + this.sendBatchForwardingStatsToServer = function ( + forwardingStatsData, + xhr, + ) { let url; let data; try { url = mpInstance._Helpers.createServiceUrl( mpInstance._Store.SDKConfig.v2SecureServiceUrl, - mpInstance._Store.devToken + mpInstance._Store.devToken, ); data = { uuid: mpInstance._Helpers.generateUniqueId(), @@ -172,18 +181,17 @@ export default function APIClient( } } catch (e) { mpInstance.Logger.error( - 'Error sending forwarding stats to mParticle servers.' + 'Error sending forwarding stats to mParticle servers.', ); } }; this.initializeForwarderStatsUploader = (): AsyncUploader => { - const { - v1SecureServiceUrl: forwardingDomain, - } = mpInstance._Store.SDKConfig; + const { v1SecureServiceUrl: forwardingDomain } = + mpInstance._Store.SDKConfig; const { devToken } = mpInstance._Store; - const uploadUrl: string = `https://${forwardingDomain}${devToken}/Forwarding`; + const uploadUrl = `https://${forwardingDomain}${devToken}/Forwarding`; const uploader: AsyncUploader = window.fetch ? new FetchUploader(uploadUrl) @@ -192,10 +200,10 @@ export default function APIClient( return uploader; }; - this.prepareForwardingStats = function( + this.prepareForwardingStats = function ( forwarder: MPForwarder, - event:SDKEvent, - ) : void { + event: SDKEvent, + ): void { let forwardingStatsData: IForwardingStatsData; const queue = mpInstance._Forwarders.getForwarderStatsQueue(); @@ -213,7 +221,7 @@ export default function APIClient( eec: event.ExpandedEventCount, dp: event.DataPlan, }; - + const { sendSingleForwardingStatsToServer, setForwarderStatsQueue, @@ -221,7 +229,7 @@ export default function APIClient( if ( mpInstance._Helpers.getFeatureFlag( - Constants.FeatureFlags.ReportBatching + Constants.FeatureFlags.ReportBatching, ) ) { queue.push(forwardingStatsData); diff --git a/src/audience.ts b/src/audience.ts index 1765f6072..d088b8af1 100644 --- a/src/audience.ts +++ b/src/audience.ts @@ -1,9 +1,7 @@ export default class Audience { public audience_id: number; - constructor( - audience_id: number, - ) { + constructor(audience_id: number) { this.audience_id = audience_id; } } diff --git a/src/audienceManager.ts b/src/audienceManager.ts index 4771bde49..d52d80006 100644 --- a/src/audienceManager.ts +++ b/src/audienceManager.ts @@ -3,12 +3,12 @@ import { FetchUploader, XHRUploader, AsyncUploader, - IFetchPayload + IFetchPayload, } from './uploaders'; import Audience from './audience'; export interface IAudienceMembershipsServerResponse { - dt: 'cam'; // current audience memberships + dt: 'cam'; // current audience memberships ct: number; // timestamp id: string; audience_memberships: Audience[]; @@ -19,15 +19,11 @@ export interface IAudienceMemberships { } export default class AudienceManager { - public url: string = ''; + public url = ''; public userAudienceAPI: AsyncUploader; public logger: SDKLoggerApi; - constructor( - userAudienceUrl: string, - apiKey: string, - logger: SDKLoggerApi, - ) { + constructor(userAudienceUrl: string, apiKey: string, logger: SDKLoggerApi) { this.logger = logger; this.url = `https://${userAudienceUrl}${apiKey}/audience`; this.userAudienceAPI = window.fetch @@ -35,7 +31,10 @@ export default class AudienceManager { : new XHRUploader(this.url); } - public async sendGetUserAudienceRequest(mpid: string, callback: (userAudiences: IAudienceMemberships) => void) { + public async sendGetUserAudienceRequest( + mpid: string, + callback: (userAudiences: IAudienceMemberships) => void, + ) { this.logger.verbose('Fetching user audiences from server'); const fetchPayload: IFetchPayload = { @@ -47,10 +46,11 @@ export default class AudienceManager { const audienceURLWithMPID = `${this.url}?mpid=${mpid}`; try { - const userAudiencePromise: Response = await this.userAudienceAPI.upload( - fetchPayload, - audienceURLWithMPID - ); + const userAudiencePromise: Response = + await this.userAudienceAPI.upload( + fetchPayload, + audienceURLWithMPID, + ); if ( userAudiencePromise.status >= 200 && @@ -58,31 +58,36 @@ export default class AudienceManager { ) { this.logger.verbose(`User Audiences successfully received`); - const userAudienceMembershipsServerResponse: IAudienceMembershipsServerResponse = await userAudiencePromise.json(); + const userAudienceMembershipsServerResponse: IAudienceMembershipsServerResponse = + await userAudiencePromise.json(); const parsedUserAudienceMemberships: IAudienceMemberships = { - currentAudienceMemberships: userAudienceMembershipsServerResponse?.audience_memberships - } + currentAudienceMemberships: + userAudienceMembershipsServerResponse?.audience_memberships, + }; try { callback(parsedUserAudienceMemberships); - } catch(e) { - throw new Error('Error invoking callback on user audience response.'); + } catch (e) { + throw new Error( + 'Error invoking callback on user audience response.', + ); } - } else if (userAudiencePromise.status === 401) { - throw new Error('`HTTP error status ${userAudiencePromise.status} while retrieving User Audiences - please verify your API key.`'); + throw new Error( + '`HTTP error status ${userAudiencePromise.status} while retrieving User Audiences - please verify your API key.`', + ); } else if (userAudiencePromise.status === 403) { - throw new Error('`HTTP error status ${userAudiencePromise.status} while retrieving User Audiences - please verify your workspace is enabled for audiences.`'); + throw new Error( + '`HTTP error status ${userAudiencePromise.status} while retrieving User Audiences - please verify your workspace is enabled for audiences.`', + ); } else { // In case there is an HTTP error we did not anticipate. throw new Error( - `Uncaught HTTP Error ${userAudiencePromise.status}.` + `Uncaught HTTP Error ${userAudiencePromise.status}.`, ); } } catch (e) { - this.logger.error( - `Error retrieving audiences. ${e}` - ); + this.logger.error(`Error retrieving audiences. ${e}`); } } -} \ No newline at end of file +} diff --git a/src/batchUploader.ts b/src/batchUploader.ts index e9c0598d3..07f289b87 100644 --- a/src/batchUploader.ts +++ b/src/batchUploader.ts @@ -42,9 +42,9 @@ export class BatchUploader { batchingEnabled: boolean; private eventVault: SessionStorageVault; private batchVault: LocalStorageVault; - private offlineStorageEnabled: boolean = false; + private offlineStorageEnabled = false; private uploader: AsyncUploader; - private lastASTEventTime: number = 0; + private lastASTEventTime = 0; private readonly AST_DEBOUNCE_MS: number = 1000; // 1 second debounce /** @@ -78,14 +78,14 @@ export class BatchUploader { `${mpInstance._Store.storageName}-events`, { logger: mpInstance.Logger, - } + }, ); this.batchVault = new LocalStorageVault( `${mpInstance._Store.storageName}-batches`, { logger: mpInstance.Logger, - } + }, ); // Load Events from Session Storage in case we have any in storage @@ -95,7 +95,7 @@ export class BatchUploader { const { SDKConfig, devToken } = this.mpInstance._Store; const baseUrl = this.mpInstance._Helpers.createServiceUrl( SDKConfig.v3SecureServiceUrl, - devToken + devToken, ); this.uploadUrl = `${baseUrl}/events`; @@ -115,12 +115,12 @@ export class BatchUploader { // https://go.mparticle.com/work/SQDSDKS-6317 const offlineStorageFeatureFlagValue: string = getFeatureFlag( - Constants.FeatureFlags.OfflineStorage + Constants.FeatureFlags.OfflineStorage, ) as string; const offlineStoragePercentage: number = parseInt( offlineStorageFeatureFlagValue, - 10 + 10, ); const rampNumber = getRampNumber(deviceId); @@ -145,7 +145,8 @@ export class BatchUploader { // https://go.mparticle.com/work/SQDSDKS-7133 private createBackgroundASTEvent(): SDKEvent { const now = Date.now(); - const { _Store, Identity, _timeOnSiteTimer, _Helpers } = this.mpInstance; + const { _Store, Identity, _timeOnSiteTimer, _Helpers } = + this.mpInstance; const { sessionId, deviceId, sessionStartDate, SDKConfig } = _Store; const { generateUniqueId } = _Helpers; const { getCurrentUser } = Identity; @@ -166,7 +167,7 @@ export class BatchUploader { SessionStartDate: sessionStartDate?.getTime() || now, Debug: SDKConfig.isDevelopmentMode, ActiveTimeOnSite: _timeOnSiteTimer?.getTimeInForeground() || 0, - IsBackgroundAST: true + IsBackgroundAST: true, } as SDKEvent; appendUserInfo(getCurrentUser(), event); @@ -215,8 +216,8 @@ export class BatchUploader { // Triggers a setTimeout for prepareAndUpload private triggerUploadInterval( - triggerFuture: boolean = false, - useBeacon: boolean = false + triggerFuture = false, + useBeacon = false, ): void { setTimeout(() => { this.prepareAndUpload(triggerFuture, useBeacon); @@ -248,14 +249,19 @@ export class BatchUploader { } // https://go.mparticle.com/work/SQDSDKS-3720 - private shouldTriggerImmediateUpload (eventDataType: number): boolean { + private shouldTriggerImmediateUpload(eventDataType: number): boolean { const priorityEvents = [ MessageType.Commerce, MessageType.UserIdentityChange, ] as const; - return !this.batchingEnabled || priorityEvents.includes(eventDataType as typeof priorityEvents[number]); - }; + return ( + !this.batchingEnabled || + priorityEvents.includes( + eventDataType as (typeof priorityEvents)[number], + ) + ); + } /** * This implements crucial logic to: @@ -269,7 +275,7 @@ export class BatchUploader { private static createNewBatches( sdkEvents: SDKEvent[], defaultUser: IMParticleUser, - mpInstance: IMParticleWebSDKInstance + mpInstance: IMParticleWebSDKInstance, ): Batch[] | null { if (!defaultUser || !sdkEvents || !sdkEvents.length) { return null; @@ -308,7 +314,7 @@ export class BatchUploader { let uploadBatchObject = convertEvents( mpid, entry[1], - mpInstance + mpInstance, ); const onCreateBatchCallback = mpInstance._Store.SDKConfig.onCreateBatch; @@ -320,7 +326,7 @@ export class BatchUploader { uploadBatchObject.modified = true; } else { mpInstance.Logger.warning( - 'Skiping batch upload because no batch was returned from onCreateBatch callback' + 'Skiping batch upload because no batch was returned from onCreateBatch callback', ); } } @@ -342,8 +348,8 @@ export class BatchUploader { * @param useBeacon whether to use the beacon API - used when the page is being unloaded */ public async prepareAndUpload( - triggerFuture: boolean = false, - useBeacon: boolean = false, + triggerFuture = false, + useBeacon = false, ): Promise { // Fetch current user so that events can be grouped by MPID const currentUser = this.mpInstance.Identity.getCurrentUser(); @@ -360,14 +366,14 @@ export class BatchUploader { newBatches = BatchUploader.createNewBatches( currentEvents, currentUser, - this.mpInstance + this.mpInstance, ); } // Top Load any older Batches from Offline Storage so they go out first if (this.offlineStorageEnabled && this.batchVault) { this.batchesQueuedForProcessing.unshift( - ...this.batchVault.retrieve() + ...this.batchVault.retrieve(), ); // Remove batches from local storage before transmit to @@ -386,7 +392,7 @@ export class BatchUploader { const batchesThatDidNotUpload = await this.uploadBatches( this.mpInstance.Logger, batchesToUpload, - useBeacon + useBeacon, ); // Batches that do not successfully upload are added back to the process queue @@ -420,7 +426,7 @@ export class BatchUploader { private async uploadBatches( logger: SDKLoggerApi, batches: Batch[], - useBeacon: boolean + useBeacon: boolean, ): Promise { // Filter out any batches that don't have events const uploads = batches.filter((batch) => !isEmpty(batch.events)); @@ -444,7 +450,7 @@ export class BatchUploader { // beacon is only used on onbeforeunload onpagehide events if (useBeacon && this.isBeaconAvailable()) { - let blob = new Blob([fetchPayload.body], { + const blob = new Blob([fetchPayload.body], { type: 'text/plain;charset=UTF-8', }); @@ -455,20 +461,20 @@ export class BatchUploader { if (response.status >= 200 && response.status < 300) { logger.verbose( - `Upload success for request ID: ${uploads[i].source_request_id}` + `Upload success for request ID: ${uploads[i].source_request_id}`, ); } else if ( response.status >= 500 || response.status === 429 ) { logger.error( - `HTTP error status ${response.status} received` + `HTTP error status ${response.status} received`, ); // Server error, add back current batches and try again later return uploads.slice(i, uploads.length); } else if (response.status >= 401) { logger.error( - `HTTP error status ${response.status} while uploading - please verify your API key.` + `HTTP error status ${response.status} while uploading - please verify your API key.`, ); //if we're getting a 401, assume we'll keep getting a 401 and clear the uploads. return null; @@ -476,16 +482,16 @@ export class BatchUploader { // In case there is an HTTP error we did not anticipate. console.error( `HTTP error status ${response.status} while uploading events.`, - response + response, ); throw new Error( - `Uncaught HTTP Error ${response.status}. Batch upload will be re-attempted.` + `Uncaught HTTP Error ${response.status}. Batch upload will be re-attempted.`, ); } } catch (e) { logger.error( - `Error sending event to mParticle servers. ${e}` + `Error sending event to mParticle servers. ${e}`, ); return uploads.slice(i, uploads.length); } @@ -493,4 +499,4 @@ export class BatchUploader { } return null; } -} \ No newline at end of file +} diff --git a/src/configAPIClient.ts b/src/configAPIClient.ts index b551af5f9..a8abeb93c 100644 --- a/src/configAPIClient.ts +++ b/src/configAPIClient.ts @@ -66,7 +66,6 @@ export interface IConsentRuleValue { hasConsented: boolean; } - export interface IConfigResponse { appName: string; dataPlanResult: DataPlanResult; @@ -90,7 +89,7 @@ const buildUrl = ( configUrl: string, apiKey: string, dataPlanConfig?: DataPlanConfig | null, - isDevelopmentMode?: boolean | null + isDevelopmentMode?: boolean | null, ): string => { const url = configUrl + apiKey + '/config'; const env = isDevelopmentMode ? '1' : '0'; @@ -113,7 +112,7 @@ export default function ConfigAPIClient( this: IConfigAPIClient, apiKey: string, config: SDKInitConfig, - mpInstance: IMParticleWebSDKInstance + mpInstance: IMParticleWebSDKInstance, ): void { const baseUrl = 'https://' + mpInstance._Store.SDKConfig.configUrl; const { isDevelopmentMode } = config; @@ -138,7 +137,7 @@ export default function ConfigAPIClient( const response = await uploader.upload(fetchPayload); if (response.status === 200) { mpInstance?.Logger?.verbose( - 'Successfully received configuration from server' + 'Successfully received configuration from server', ); // https://go.mparticle.com/work/SQDSDKS-6568 @@ -157,11 +156,11 @@ export default function ConfigAPIClient( mpInstance?.Logger?.verbose( 'Issue with receiving configuration from server, received HTTP Code of ' + - response.statusText + response.statusText, ); } catch (e) { mpInstance?.Logger?.error( - 'Error getting forwarder configuration from mParticle servers.' + 'Error getting forwarder configuration from mParticle servers.', ); } diff --git a/src/consent.ts b/src/consent.ts index 81ae944cd..7533550a1 100644 --- a/src/consent.ts +++ b/src/consent.ts @@ -25,7 +25,7 @@ export interface ICreatePrivacyConsentFunction { timestamp?: number, consentDocument?: string, location?: string, - hardwareId?: string + hardwareId?: string, ): PrivacyConsentState | null; } @@ -107,22 +107,25 @@ export interface IConsentState extends ConsentState { export interface IConsent { isEnabledForUserConsent: ( consentRules: IConsentRules, - user: IMParticleUser + user: IMParticleUser, ) => boolean; createPrivacyConsent: ICreatePrivacyConsentFunction; createConsentState: (consentState?: ConsentState) => ConsentState; ConsentSerialization: IConsentSerialization; } -export default function Consent(this: IConsent, mpInstance: IMParticleWebSDKInstance) { +export default function Consent( + this: IConsent, + mpInstance: IMParticleWebSDKInstance, +) { const self = this; // this function is called when consent is required to // determine if a cookie sync should happen, or a // forwarder should be initialized - this.isEnabledForUserConsent = function( + this.isEnabledForUserConsent = function ( consentRules: IConsentRules, - user: IMParticleUser + user: IMParticleUser, ): boolean { if ( !consentRules || @@ -150,7 +153,11 @@ export default function Consent(this: IConsent, mpInstance: IMParticleWebSDKInst if (gdprConsentState) { for (const purpose in gdprConsentState) { if (gdprConsentState.hasOwnProperty(purpose)) { - purposeHash = KitFilterHelper.hashConsentPurposeConditionalForwarding(GDPRConsentHashPrefix, purpose); + purposeHash = + KitFilterHelper.hashConsentPurposeConditionalForwarding( + GDPRConsentHashPrefix, + purpose, + ); purposeHashes[purposeHash] = gdprConsentState[purpose].Consented; } @@ -158,11 +165,15 @@ export default function Consent(this: IConsent, mpInstance: IMParticleWebSDKInst } const CCPAConsentState = consentState.getCCPAConsentState(); if (CCPAConsentState) { - purposeHash = KitFilterHelper.hashConsentPurposeConditionalForwarding(CCPAHashPrefix, CCPAPurpose); + purposeHash = + KitFilterHelper.hashConsentPurposeConditionalForwarding( + CCPAHashPrefix, + CCPAPurpose, + ); purposeHashes[purposeHash] = CCPAConsentState.Consented; } } - const isMatch = consentRules.values.some(function(consentRule) { + const isMatch = consentRules.values.some(function (consentRule) { const consentPurposeHash = consentRule.consentPurpose; const hasConsented = consentRule.hasConsented; if (purposeHashes.hasOwnProperty(consentPurposeHash)) { @@ -174,40 +185,40 @@ export default function Consent(this: IConsent, mpInstance: IMParticleWebSDKInst return consentRules.includeOnMatch === isMatch; }; - this.createPrivacyConsent = function( + this.createPrivacyConsent = function ( consented: boolean, timestamp?: number, consentDocument?: string, location?: string, - hardwareId?: string + hardwareId?: string, ): PrivacyConsentState | null { if (typeof consented !== 'boolean') { mpInstance.Logger.error( - 'Consented boolean is required when constructing a Consent object.' + 'Consented boolean is required when constructing a Consent object.', ); return null; } if (timestamp && isNaN(timestamp)) { mpInstance.Logger.error( - 'Timestamp must be a valid number when constructing a Consent object.' + 'Timestamp must be a valid number when constructing a Consent object.', ); return null; } if (consentDocument && typeof consentDocument !== 'string') { mpInstance.Logger.error( - 'Document must be a valid string when constructing a Consent object.' + 'Document must be a valid string when constructing a Consent object.', ); return null; } if (location && typeof location !== 'string') { mpInstance.Logger.error( - 'Location must be a valid string when constructing a Consent object.' + 'Location must be a valid string when constructing a Consent object.', ); return null; } if (hardwareId && typeof hardwareId !== 'string') { mpInstance.Logger.error( - 'Hardware ID must be a valid string when constructing a Consent object.' + 'Hardware ID must be a valid string when constructing a Consent object.', ); return null; } @@ -298,7 +309,7 @@ export default function Consent(this: IConsent, mpInstance: IMParticleWebSDKInst json.gdpr[purpose].ts, json.gdpr[purpose].d, json.gdpr[purpose].l, - json.gdpr[purpose].h + json.gdpr[purpose].h, ); state.addGDPRConsentState(purpose, gdprConsent); } @@ -312,7 +323,7 @@ export default function Consent(this: IConsent, mpInstance: IMParticleWebSDKInst json.ccpa[CCPAPurpose].ts, json.ccpa[CCPAPurpose].d, json.ccpa[CCPAPurpose].l, - json.ccpa[CCPAPurpose].h + json.ccpa[CCPAPurpose].h, ); state.setCCPAConsentState(ccpaConsent); } @@ -322,20 +333,20 @@ export default function Consent(this: IConsent, mpInstance: IMParticleWebSDKInst }; // TODO: Refactor this method into a constructor - this.createConsentState = function( + this.createConsentState = function ( this: ConsentState, - consentState?: ConsentState + consentState?: ConsentState, ): IConsentState { let gdpr = {}; - let ccpa = {}; + const ccpa = {}; if (consentState) { const consentStateCopy = self.createConsentState(); consentStateCopy.setGDPRConsentState( - consentState.getGDPRConsentState() + consentState.getGDPRConsentState(), ); consentStateCopy.setCCPAConsentState( - consentState.getCCPAConsentState() + consentState.getCCPAConsentState(), ); // TODO: Remove casting once `removeCCPAState` is removed; @@ -377,7 +388,7 @@ export default function Consent(this: IConsent, mpInstance: IMParticleWebSDKInst function addGDPRConsentState( this: ConsentState, purpose: string, - gdprConsent: PrivacyConsentState + gdprConsent: PrivacyConsentState, ): ConsentState { const normalizedPurpose = canonicalizeForDeduplication(purpose); if (!normalizedPurpose) { @@ -387,7 +398,7 @@ export default function Consent(this: IConsent, mpInstance: IMParticleWebSDKInst if (!isObject(gdprConsent)) { mpInstance.Logger.error( - 'Invoked with a bad or empty consent object.' + 'Invoked with a bad or empty consent object.', ); return this; } @@ -396,7 +407,7 @@ export default function Consent(this: IConsent, mpInstance: IMParticleWebSDKInst gdprConsent.Timestamp, gdprConsent.ConsentDocument, gdprConsent.Location, - gdprConsent.HardwareId + gdprConsent.HardwareId, ); if (gdprConsentCopy) { gdpr[normalizedPurpose] = gdprConsentCopy; @@ -406,7 +417,7 @@ export default function Consent(this: IConsent, mpInstance: IMParticleWebSDKInst function setGDPRConsentState( this: ConsentState, - gdprConsentState: GDPRConsentState + gdprConsentState: GDPRConsentState, ): ConsentState { if (!gdprConsentState) { gdpr = {}; @@ -416,7 +427,7 @@ export default function Consent(this: IConsent, mpInstance: IMParticleWebSDKInst if (gdprConsentState.hasOwnProperty(purpose)) { this.addGDPRConsentState( purpose, - gdprConsentState[purpose] + gdprConsentState[purpose], ); } } @@ -433,7 +444,7 @@ export default function Consent(this: IConsent, mpInstance: IMParticleWebSDKInst function removeGDPRConsentState( this: ConsentState, - purpose: string + purpose: string, ): ConsentState { const normalizedPurpose = canonicalizeForDeduplication(purpose); if (!normalizedPurpose) { @@ -462,11 +473,11 @@ export default function Consent(this: IConsent, mpInstance: IMParticleWebSDKInst */ function setCCPAConsentState( this: ConsentState, - ccpaConsent: CCPAConsentState + ccpaConsent: CCPAConsentState, ) { if (!isObject(ccpaConsent)) { mpInstance.Logger.error( - 'Invoked with a bad or empty CCPA consent object.' + 'Invoked with a bad or empty CCPA consent object.', ); return this; } @@ -475,7 +486,7 @@ export default function Consent(this: IConsent, mpInstance: IMParticleWebSDKInst ccpaConsent.Timestamp, ccpaConsent.ConsentDocument, ccpaConsent.Location, - ccpaConsent.HardwareId + ccpaConsent.HardwareId, ); if (ccpaConsentCopy) { ccpa[CCPAPurpose] = ccpaConsentCopy; @@ -506,7 +517,7 @@ export default function Consent(this: IConsent, mpInstance: IMParticleWebSDKInst // TODO: Can we remove this? It is deprecated. function removeCCPAState(this: ConsentState) { mpInstance.Logger.warning( - 'removeCCPAState is deprecated and will be removed in a future release; use removeCCPAConsentState instead' + 'removeCCPAState is deprecated and will be removed in a future release; use removeCCPAConsentState instead', ); // @ts-ignore return removeCCPAConsentState(); diff --git a/src/cookieSyncManager.ts b/src/cookieSyncManager.ts index c02f35334..9157d3f29 100644 --- a/src/cookieSyncManager.ts +++ b/src/cookieSyncManager.ts @@ -1,8 +1,4 @@ -import { - Dictionary, - isEmpty, - createCookieSyncUrl, -} from './utils'; +import { Dictionary, isEmpty, createCookieSyncUrl } from './utils'; import Constants from './constants'; import { MPID } from '@mparticle/web-sdk'; import { IConsentRules } from './consent'; @@ -13,7 +9,7 @@ const { InformationMessages } = Messages; export const DAYS_IN_MILLISECONDS = 1000 * 60 * 60 * 24; -export type CookieSyncDates = Dictionary; +export type CookieSyncDates = Dictionary; export interface IPixelConfiguration { name?: string; @@ -28,10 +24,7 @@ export interface IPixelConfiguration { filteringConsentRuleValues?: IConsentRules; } export interface ICookieSyncManager { - attemptCookieSync: ( - mpid: MPID, - mpidIsNotInCookies?: boolean - ) => void; + attemptCookieSync: (mpid: MPID, mpidIsNotInCookies?: boolean) => void; performCookieSync: ( url: string, moduleId: string, @@ -41,20 +34,20 @@ export interface ICookieSyncManager { combineUrlWithRedirect: ( mpid: MPID, pixelUrl: string, - redirectUrl: string + redirectUrl: string, ) => string; } export default function CookieSyncManager( this: ICookieSyncManager, - mpInstance: IMParticleWebSDKInstance + mpInstance: IMParticleWebSDKInstance, ) { const self = this; // Public this.attemptCookieSync = ( mpid: MPID, - mpidIsNotInCookies?: boolean + mpidIsNotInCookies?: boolean, ): void => { const { pixelConfigurations, webviewBridgeEnabled } = mpInstance._Store; @@ -100,25 +93,32 @@ export default function CookieSyncManager( const { isEnabledForUserConsent } = mpInstance._Consent; - if (!isEnabledForUserConsent(filteringConsentRuleValues, mpInstance.Identity.getCurrentUser())) { + if ( + !isEnabledForUserConsent( + filteringConsentRuleValues, + mpInstance.Identity.getCurrentUser(), + ) + ) { return; } - const cookieSyncDates: CookieSyncDates = persistence[mpid]?.csd ?? {}; - const lastSyncDateForModule: number = cookieSyncDates[moduleId] || null; + const cookieSyncDates: CookieSyncDates = + persistence[mpid]?.csd ?? {}; + const lastSyncDateForModule: number = + cookieSyncDates[moduleId] || null; if (!isLastSyncDateExpired(frequencyCap, lastSyncDateForModule)) { return; } // Url for cookie sync pixel - const fullUrl = createCookieSyncUrl(mpid, pixelUrl, redirectUrl) + const fullUrl = createCookieSyncUrl(mpid, pixelUrl, redirectUrl); self.performCookieSync( fullUrl, moduleId.toString(), mpid, - cookieSyncDates + cookieSyncDates, ); }); }; @@ -133,12 +133,12 @@ export default function CookieSyncManager( const img = document.createElement('img'); mpInstance.Logger.verbose(InformationMessages.CookieSync); - img.onload = function() { + img.onload = function () { cookieSyncDates[moduleId] = new Date().getTime(); mpInstance._Persistence.saveUserCookieSyncDatesToPersistence( mpid, - cookieSyncDates + cookieSyncDates, ); }; img.src = url; @@ -147,7 +147,7 @@ export default function CookieSyncManager( export const isLastSyncDateExpired = ( frequencyCap: number, - lastSyncDate?: number + lastSyncDate?: number, ): boolean => { // If there is no lastSyncDate, then there is no previous cookie sync, so we should sync the cookie if (!lastSyncDate) { @@ -159,4 +159,4 @@ export const isLastSyncDateExpired = ( new Date().getTime() > new Date(lastSyncDate).getTime() + frequencyCap * DAYS_IN_MILLISECONDS ); -}; \ No newline at end of file +}; diff --git a/src/ecommerce.interfaces.ts b/src/ecommerce.interfaces.ts index 053f848c0..d70104ef4 100644 --- a/src/ecommerce.interfaces.ts +++ b/src/ecommerce.interfaces.ts @@ -36,14 +36,14 @@ interface IECommerceShared { brand?: string, position?: number, couponCode?: string, - attributes?: SDKEventAttrs + attributes?: SDKEventAttrs, ): SDKProduct | null; createImpression(name: string, product: Product): SDKImpression | null; createPromotion( id: string | number, creative?: string, name?: string, - position?: number + position?: number, ): SDKPromotion | null; createTransactionAttributes( id: string | number, @@ -51,7 +51,7 @@ interface IECommerceShared { couponCode?: string, revenue?: string | number, shipping?: string | number, - tax?: number + tax?: number, ): TransactionAttributes | null; expandCommerceEvent(event: CommerceEvent): SDKEvent[] | null; } @@ -68,13 +68,13 @@ export interface SDKECommerceAPI extends IECommerceShared { step: number, option?: string, attrs?: SDKEventAttrs, - customFlags?: SDKEventCustomFlags + customFlags?: SDKEventCustomFlags, ): void; logImpression( impression: SDKProductImpression, attrs?: SDKEventAttrs, customFlags?: SDKEventCustomFlags, - eventOptions?: SDKEventOptions + eventOptions?: SDKEventOptions, ): void; logProductAction( productActionType: valueof, @@ -82,14 +82,14 @@ export interface SDKECommerceAPI extends IECommerceShared { attrs?: SDKEventAttrs, customFlags?: SDKEventCustomFlags, transactionAttributes?: TransactionAttributes, - eventOptions?: SDKEventOptions + eventOptions?: SDKEventOptions, ): void; logPromotion( type: valueof, promotion: SDKPromotion, attrs?: SDKEventAttrs, customFlags?: SDKEventCustomFlags, - eventOptions?: SDKEventOptions + eventOptions?: SDKEventOptions, ): void; setCurrencyCode(code: string): void; @@ -106,7 +106,7 @@ export interface SDKECommerceAPI extends IECommerceShared { product: SDKProduct | SDKProduct[], clearCart?: boolean, attrs?: SDKEventAttrs, - customFlags?: SDKEventCustomFlags + customFlags?: SDKEventCustomFlags, ): void; /* @@ -117,7 +117,7 @@ export interface SDKECommerceAPI extends IECommerceShared { product: SDKProduct | SDKProduct[], clearCart?: boolean, attrs?: SDKEventAttrs, - customFlags?: SDKEventCustomFlags + customFlags?: SDKEventCustomFlags, ): void; } @@ -157,45 +157,45 @@ interface ExtractedTransactionId { export interface IECommerce extends IECommerceShared { buildProductList(event: SDKEvent, product: Product | Product[]): Product[]; convertProductActionToEventType( - productActionType: valueof + productActionType: valueof, ): // https://go.mparticle.com/work/SQDSDKS-4801 typeof CommerceEventType | typeof EventType | null; convertPromotionActionToEventType( - promotionActionType: valueof + promotionActionType: valueof, ): typeof CommerceEventType | null; convertTransactionAttributesToProductAction( transactionAttributes: TransactionAttributes, - productAction: ProductAction + productAction: ProductAction, ): void; createCommerceEventObject( customFlags: SDKEventCustomFlags, - options?: SDKEventOptions + options?: SDKEventOptions, ): SDKEvent | null; expandProductAction(commerceEvent: CommerceEvent): SDKEvent[]; expandProductImpression(commerceEvent: CommerceEvent): SDKEvent[]; expandPromotionAction(commerceEvent: CommerceEvent): SDKEvent[]; extractActionAttributes( attributes: ExtractedActionAttributes, - productAction: ProductAction + productAction: ProductAction, ): void; extractProductAttributes( attributes: ExtractedProductAttributes, - product: Product + product: Product, ): void; extractPromotionAttributes( attributes: ExtractedPromotionAttributes, - promotion: Promotion + promotion: Promotion, ): void; extractTransactionId( attributes: ExtractedTransactionId, - productAction: ProductAction + productAction: ProductAction, ): void; generateExpandedEcommerceName(eventName: string, plusOne: boolean): string; getProductActionEventName( - productActionType: valueof + productActionType: valueof, ): string; getPromotionActionEventName( - promotionActionType: valueof + promotionActionType: valueof, ): string; sanitizeAmount(amount: string | number, category: string): number; } diff --git a/src/ecommerce.js b/src/ecommerce.js index c492e102e..7451cd5f7 100644 --- a/src/ecommerce.js +++ b/src/ecommerce.js @@ -1,15 +1,15 @@ import Types from './types'; import Constants from './constants'; -var Messages = Constants.Messages; +const Messages = Constants.Messages; export default function Ecommerce(mpInstance) { - var self = this; + const self = this; // https://go.mparticle.com/work/SQDSDKS-4801 - this.convertTransactionAttributesToProductAction = function( + this.convertTransactionAttributesToProductAction = function ( transactionAttributes, - productAction + productAction, ) { if (transactionAttributes.hasOwnProperty('Id')) { productAction.TransactionId = transactionAttributes.Id; @@ -23,19 +23,19 @@ export default function Ecommerce(mpInstance) { if (transactionAttributes.hasOwnProperty('Revenue')) { productAction.TotalAmount = this.sanitizeAmount( transactionAttributes.Revenue, - 'Revenue' + 'Revenue', ); } if (transactionAttributes.hasOwnProperty('Shipping')) { productAction.ShippingAmount = this.sanitizeAmount( transactionAttributes.Shipping, - 'Shipping' + 'Shipping', ); } if (transactionAttributes.hasOwnProperty('Tax')) { productAction.TaxAmount = this.sanitizeAmount( transactionAttributes.Tax, - 'Tax' + 'Tax', ); } if (transactionAttributes.hasOwnProperty('Step')) { @@ -46,7 +46,7 @@ export default function Ecommerce(mpInstance) { } }; - this.getProductActionEventName = function(productActionType) { + this.getProductActionEventName = function (productActionType) { switch (productActionType) { case Types.ProductActionType.AddToCart: return 'AddToCart'; @@ -74,7 +74,7 @@ export default function Ecommerce(mpInstance) { } }; - this.getPromotionActionEventName = function(promotionActionType) { + this.getPromotionActionEventName = function (promotionActionType) { switch (promotionActionType) { case Types.PromotionActionType.PromotionClick: return 'PromotionClick'; @@ -85,7 +85,7 @@ export default function Ecommerce(mpInstance) { } }; - this.convertProductActionToEventType = function(productActionType) { + this.convertProductActionToEventType = function (productActionType) { switch (productActionType) { case Types.ProductActionType.AddToCart: return Types.CommerceEventType.ProductAddToCart; @@ -116,13 +116,13 @@ export default function Ecommerce(mpInstance) { mpInstance.Logger.error( 'Could not convert product action type ' + productActionType + - ' to event type' + ' to event type', ); return null; } }; - this.convertPromotionActionToEventType = function(promotionActionType) { + this.convertPromotionActionToEventType = function (promotionActionType) { switch (promotionActionType) { case Types.PromotionActionType.PromotionClick: return Types.CommerceEventType.PromotionClick; @@ -132,20 +132,20 @@ export default function Ecommerce(mpInstance) { mpInstance.Logger.error( 'Could not convert promotion action type ' + promotionActionType + - ' to event type' + ' to event type', ); return null; } }; - this.generateExpandedEcommerceName = function(eventName, plusOne) { + this.generateExpandedEcommerceName = function (eventName, plusOne) { return ( 'eCommerce - ' + eventName + ' - ' + (plusOne ? 'Total' : 'Item') ); }; // https://go.mparticle.com/work/SQDSDKS-4801 - this.extractProductAttributes = function(attributes, product) { + this.extractProductAttributes = function (attributes, product) { if (product.CouponCode) { attributes['Coupon Code'] = product.CouponCode; } @@ -177,14 +177,14 @@ export default function Ecommerce(mpInstance) { }; // https://go.mparticle.com/work/SQDSDKS-4801 - this.extractTransactionId = function(attributes, productAction) { + this.extractTransactionId = function (attributes, productAction) { if (productAction.TransactionId) { attributes['Transaction Id'] = productAction.TransactionId; } }; // https://go.mparticle.com/work/SQDSDKS-4801 - this.extractActionAttributes = function(attributes, productAction) { + this.extractActionAttributes = function (attributes, productAction) { self.extractTransactionId(attributes, productAction); if (productAction.Affiliation) { @@ -217,7 +217,7 @@ export default function Ecommerce(mpInstance) { }; // https://go.mparticle.com/work/SQDSDKS-4801 - this.extractPromotionAttributes = function(attributes, promotion) { + this.extractPromotionAttributes = function (attributes, promotion) { if (promotion.Id) { attributes['Id'] = promotion.Id; } @@ -235,7 +235,7 @@ export default function Ecommerce(mpInstance) { } }; - this.buildProductList = function(event, product) { + this.buildProductList = function (event, product) { if (product) { if (Array.isArray(product)) { return product; @@ -247,7 +247,7 @@ export default function Ecommerce(mpInstance) { return event.ShoppingCart.ProductList; }; - this.createProduct = function( + this.createProduct = function ( name, sku, price, @@ -257,7 +257,7 @@ export default function Ecommerce(mpInstance) { brand, position, couponCode, - attributes + attributes, ) { attributes = mpInstance._Helpers.sanitizeAttributes(attributes, name); @@ -268,14 +268,14 @@ export default function Ecommerce(mpInstance) { if (!mpInstance._Helpers.Validators.isStringOrNumber(sku)) { mpInstance.Logger.error( - 'SKU is required when creating a product, and must be a string or a number' + 'SKU is required when creating a product, and must be a string or a number', ); return null; } if (!mpInstance._Helpers.Validators.isStringOrNumber(price)) { mpInstance.Logger.error( - 'Price is required when creating a product, and must be a string or a number' + 'Price is required when creating a product, and must be a string or a number', ); return null; } else { @@ -284,7 +284,7 @@ export default function Ecommerce(mpInstance) { if (position && !mpInstance._Helpers.Validators.isNumber(position)) { mpInstance.Logger.error( - 'Position must be a number, it will be set to null.' + 'Position must be a number, it will be set to null.', ); position = null; } @@ -310,7 +310,7 @@ export default function Ecommerce(mpInstance) { }; }; - this.createPromotion = function(id, creative, name, position) { + this.createPromotion = function (id, creative, name, position) { if (!mpInstance._Helpers.Validators.isStringOrNumber(id)) { mpInstance.Logger.error(Messages.ErrorMessages.PromotionIdRequired); return null; @@ -324,17 +324,17 @@ export default function Ecommerce(mpInstance) { }; }; - this.createImpression = function(name, product) { + this.createImpression = function (name, product) { if (typeof name !== 'string') { mpInstance.Logger.error( - 'Name is required when creating an impression.' + 'Name is required when creating an impression.', ); return null; } if (!product) { mpInstance.Logger.error( - 'Product is required when creating an impression.' + 'Product is required when creating an impression.', ); return null; } @@ -345,17 +345,17 @@ export default function Ecommerce(mpInstance) { }; }; - this.createTransactionAttributes = function( + this.createTransactionAttributes = function ( id, affiliation, couponCode, revenue, shipping, - tax + tax, ) { if (!mpInstance._Helpers.Validators.isStringOrNumber(id)) { mpInstance.Logger.error( - Messages.ErrorMessages.TransactionIdRequired + Messages.ErrorMessages.TransactionIdRequired, ); return null; } @@ -370,21 +370,21 @@ export default function Ecommerce(mpInstance) { }; }; - this.expandProductImpression = function(commerceEvent) { - var appEvents = []; + this.expandProductImpression = function (commerceEvent) { + const appEvents = []; if (!commerceEvent.ProductImpressions) { return appEvents; } - commerceEvent.ProductImpressions.forEach(function(productImpression) { + commerceEvent.ProductImpressions.forEach(function (productImpression) { if (productImpression.ProductList) { - productImpression.ProductList.forEach(function(product) { - var attributes = mpInstance._Helpers.extend( + productImpression.ProductList.forEach(function (product) { + const attributes = mpInstance._Helpers.extend( false, {}, - commerceEvent.EventAttributes + commerceEvent.EventAttributes, ); if (product.Attributes) { - for (var attribute in product.Attributes) { + for (const attribute in product.Attributes) { attributes[attribute] = product.Attributes[attribute]; } @@ -394,7 +394,7 @@ export default function Ecommerce(mpInstance) { attributes['Product Impression List'] = productImpression.ProductImpressionList; } - var appEvent = mpInstance._ServerModel.createEventObject({ + const appEvent = mpInstance._ServerModel.createEventObject({ messageType: Types.MessageType.PageEvent, name: self.generateExpandedEcommerceName('Impression'), data: attributes, @@ -408,7 +408,7 @@ export default function Ecommerce(mpInstance) { return appEvents; }; - this.expandCommerceEvent = function(event) { + this.expandCommerceEvent = function (event) { if (!event) { return null; } @@ -418,26 +418,26 @@ export default function Ecommerce(mpInstance) { .concat(self.expandProductImpression(event)); }; - this.expandPromotionAction = function(commerceEvent) { - var appEvents = []; + this.expandPromotionAction = function (commerceEvent) { + const appEvents = []; if (!commerceEvent.PromotionAction) { return appEvents; } - var promotions = commerceEvent.PromotionAction.PromotionList; - promotions.forEach(function(promotion) { - var attributes = mpInstance._Helpers.extend( + const promotions = commerceEvent.PromotionAction.PromotionList; + promotions.forEach(function (promotion) { + const attributes = mpInstance._Helpers.extend( false, {}, - commerceEvent.EventAttributes + commerceEvent.EventAttributes, ); self.extractPromotionAttributes(attributes, promotion); - var appEvent = mpInstance._ServerModel.createEventObject({ + const appEvent = mpInstance._ServerModel.createEventObject({ messageType: Types.MessageType.PageEvent, name: self.generateExpandedEcommerceName( Types.PromotionActionType.getExpansionName( - commerceEvent.PromotionAction.PromotionActionType - ) + commerceEvent.PromotionAction.PromotionActionType, + ), ), data: attributes, eventType: Types.EventType.Transaction, @@ -447,22 +447,22 @@ export default function Ecommerce(mpInstance) { return appEvents; }; - this.expandProductAction = function(commerceEvent) { - var appEvents = []; + this.expandProductAction = function (commerceEvent) { + const appEvents = []; if (!commerceEvent.ProductAction) { return appEvents; } - var shouldExtractActionAttributes = false; + let shouldExtractActionAttributes = false; if ( commerceEvent.ProductAction.ProductActionType === Types.ProductActionType.Purchase || commerceEvent.ProductAction.ProductActionType === Types.ProductActionType.Refund ) { - var attributes = mpInstance._Helpers.extend( + const attributes = mpInstance._Helpers.extend( false, {}, - commerceEvent.EventAttributes + commerceEvent.EventAttributes, ); attributes['Product Count'] = commerceEvent.ProductAction .ProductList @@ -470,18 +470,18 @@ export default function Ecommerce(mpInstance) { : 0; self.extractActionAttributes( attributes, - commerceEvent.ProductAction + commerceEvent.ProductAction, ); if (commerceEvent.CurrencyCode) { attributes['Currency Code'] = commerceEvent.CurrencyCode; } - var plusOneEvent = mpInstance._ServerModel.createEventObject({ + const plusOneEvent = mpInstance._ServerModel.createEventObject({ messageType: Types.MessageType.PageEvent, name: self.generateExpandedEcommerceName( Types.ProductActionType.getExpansionName( - commerceEvent.ProductAction.ProductActionType + commerceEvent.ProductAction.ProductActionType, ), - true + true, ), data: attributes, eventType: Types.EventType.Transaction, @@ -491,37 +491,37 @@ export default function Ecommerce(mpInstance) { shouldExtractActionAttributes = true; } - var products = commerceEvent.ProductAction.ProductList; + const products = commerceEvent.ProductAction.ProductList; if (!products) { return appEvents; } - products.forEach(function(product) { - var attributes = mpInstance._Helpers.extend( + products.forEach(function (product) { + const attributes = mpInstance._Helpers.extend( false, commerceEvent.EventAttributes, - product.Attributes + product.Attributes, ); if (shouldExtractActionAttributes) { self.extractActionAttributes( attributes, - commerceEvent.ProductAction + commerceEvent.ProductAction, ); } else { self.extractTransactionId( attributes, - commerceEvent.ProductAction + commerceEvent.ProductAction, ); } self.extractProductAttributes(attributes, product); - var productEvent = mpInstance._ServerModel.createEventObject({ + const productEvent = mpInstance._ServerModel.createEventObject({ messageType: Types.MessageType.PageEvent, name: self.generateExpandedEcommerceName( Types.ProductActionType.getExpansionName( - commerceEvent.ProductAction.ProductActionType - ) + commerceEvent.ProductAction.ProductActionType, + ), ), data: attributes, eventType: Types.EventType.Transaction, @@ -532,13 +532,13 @@ export default function Ecommerce(mpInstance) { return appEvents; }; - this.createCommerceEventObject = function(customFlags, options) { - var baseEvent; + this.createCommerceEventObject = function (customFlags, options) { + let baseEvent; // https://go.mparticle.com/work/SQDSDKS-4801 - var { extend } = mpInstance._Helpers; + const { extend } = mpInstance._Helpers; mpInstance.Logger.verbose( - Messages.InformationMessages.StartingLogCommerceEvent + Messages.InformationMessages.StartingLogCommerceEvent, ); if (mpInstance._Helpers.canLog()) { @@ -555,7 +555,7 @@ export default function Ecommerce(mpInstance) { return baseEvent; } else { mpInstance.Logger.verbose( - Messages.InformationMessages.AbandonLogEvent + Messages.InformationMessages.AbandonLogEvent, ); } @@ -563,9 +563,9 @@ export default function Ecommerce(mpInstance) { }; // sanitizes any non number, non string value to 0 - this.sanitizeAmount = function(amount, category) { + this.sanitizeAmount = function (amount, category) { if (!mpInstance._Helpers.Validators.isStringOrNumber(amount)) { - var message = [ + const message = [ category, 'must be of type number. A', typeof amount, diff --git a/src/events.interfaces.ts b/src/events.interfaces.ts index 0674e47a8..1402f6688 100644 --- a/src/events.interfaces.ts +++ b/src/events.interfaces.ts @@ -16,7 +16,9 @@ import { valueof } from './utils'; import { EventType, ProductActionType, PromotionActionType } from './types'; // Supports wrapping event handlers functions that will ideally return a specific type -type EventHandlerFunction = (element: HTMLLinkElement | HTMLFormElement) => T; +type EventHandlerFunction = ( + element: HTMLLinkElement | HTMLFormElement, +) => T; export interface IEvents { addEventHandler( @@ -24,7 +26,7 @@ export interface IEvents { selector: string | Node, eventName: EventHandlerFunction | string, data: EventHandlerFunction | SDKEventAttrs, - eventType: valueof + eventType: valueof, ): void; logAST(): void; logCheckoutEvent( @@ -36,19 +38,19 @@ export interface IEvents { option?: string, attrs?: SDKEventAttrs, - customFlags?: SDKEventCustomFlags + customFlags?: SDKEventCustomFlags, ): void; logCommerceEvent( commerceEvent: SDKEvent, attrs?: SDKEventAttrs, - options?: SDKEventOptions + options?: SDKEventOptions, ): void; logEvent(event: BaseEvent, eventOptions?: SDKEventOptions): void; logImpressionEvent( impression: SDKProductImpression, attrs?: SDKEventAttrs, customFlags?: SDKEventCustomFlags, - eventOptions?: SDKEventOptions + eventOptions?: SDKEventOptions, ); logOptOut(): void; logProductActionEvent( @@ -57,26 +59,26 @@ export interface IEvents { attrs?: SDKEventAttrs, customFlags?: SDKEventCustomFlags, transactionAttributes?: TransactionAttributes, - eventOptions?: SDKEventOptions + eventOptions?: SDKEventOptions, ): void; logPromotionEvent( promotionType: valueof, promotion: SDKPromotion, attrs?: SDKEventAttrs, customFlags?: SDKEventCustomFlags, - eventOptions?: SDKEventOptions + eventOptions?: SDKEventOptions, ): void; logPurchaseEvent( transactionAttributes: TransactionAttributes, product: SDKProduct | SDKProduct[], attrs?: SDKEventAttrs, - customFlags?: SDKEventCustomFlags + customFlags?: SDKEventCustomFlags, ): void; logRefundEvent( transactionAttributes: TransactionAttributes, product: SDKProduct | SDKProduct[], attrs?: SDKEventAttrs, - customFlags?: SDKEventCustomFlags + customFlags?: SDKEventCustomFlags, ): void; startTracking(callback: Callback): void; stopTracking(): void; diff --git a/src/events.js b/src/events.js index 73969b5df..830d3dcb6 100644 --- a/src/events.js +++ b/src/events.js @@ -1,34 +1,36 @@ import Types from './types'; import Constants from './constants'; -var Messages = Constants.Messages; +const Messages = Constants.Messages; export default function Events(mpInstance) { - var self = this; - this.logEvent = function(event, options) { + const self = this; + this.logEvent = function (event, options) { mpInstance.Logger.verbose( - Messages.InformationMessages.StartingLogEvent + ': ' + event.name + Messages.InformationMessages.StartingLogEvent + ': ' + event.name, ); if (mpInstance._Helpers.canLog()) { - var uploadObject = mpInstance._ServerModel.createEventObject(event); + const uploadObject = + mpInstance._ServerModel.createEventObject(event); mpInstance._APIClient.sendEventToServer(uploadObject, options); } else { mpInstance.Logger.verbose( - Messages.InformationMessages.AbandonLogEvent + Messages.InformationMessages.AbandonLogEvent, ); } }; - this.startTracking = function(callback) { + this.startTracking = function (callback) { if (!mpInstance._Store.isTracking) { if ('geolocation' in navigator) { - mpInstance._Store.watchPositionId = navigator.geolocation.watchPosition( - successTracking, - errorTracking - ); + mpInstance._Store.watchPositionId = + navigator.geolocation.watchPosition( + successTracking, + errorTracking, + ); } } else { - var position = { + const position = { coords: { latitude: mpInstance._Store.currentPosition.lat, longitude: mpInstance._Store.currentPosition.lng, @@ -67,7 +69,7 @@ export default function Events(mpInstance) { } } catch (e) { mpInstance.Logger.error( - 'Error invoking the callback passed to startTrackingLocation.' + 'Error invoking the callback passed to startTrackingLocation.', ); mpInstance.Logger.error(e); } @@ -75,7 +77,7 @@ export default function Events(mpInstance) { } }; - this.stopTracking = function() { + this.stopTracking = function () { if (mpInstance._Store.isTracking) { navigator.geolocation.clearWatch(mpInstance._Store.watchPositionId); mpInstance._Store.currentPosition = null; @@ -83,30 +85,29 @@ export default function Events(mpInstance) { } }; - this.logOptOut = function() { + this.logOptOut = function () { mpInstance.Logger.verbose( - Messages.InformationMessages.StartingLogOptOut + Messages.InformationMessages.StartingLogOptOut, ); - var event = mpInstance._ServerModel.createEventObject({ + const event = mpInstance._ServerModel.createEventObject({ messageType: Types.MessageType.OptOut, eventType: Types.EventType.Other, }); mpInstance._APIClient.sendEventToServer(event); }; - this.logAST = function() { + this.logAST = function () { self.logEvent({ messageType: Types.MessageType.AppStateTransition }); }; - this.logCheckoutEvent = function(step, option, attrs, customFlags) { - var event = mpInstance._Ecommerce.createCommerceEventObject( - customFlags - ); + this.logCheckoutEvent = function (step, option, attrs, customFlags) { + const event = + mpInstance._Ecommerce.createCommerceEventObject(customFlags); if (event) { event.EventName += mpInstance._Ecommerce.getProductActionEventName( - Types.ProductActionType.Checkout + Types.ProductActionType.Checkout, ); event.EventCategory = Types.CommerceEventType.ProductCheckout; event.ProductAction = { @@ -120,55 +121,57 @@ export default function Events(mpInstance) { } }; - this.logProductActionEvent = function( + this.logProductActionEvent = function ( productActionType, product, customAttrs, customFlags, transactionAttributes, - options + options, ) { - var event = mpInstance._Ecommerce.createCommerceEventObject( + const event = mpInstance._Ecommerce.createCommerceEventObject( customFlags, - options + options, ); - var productList = Array.isArray(product) ? product : [product]; + const productList = Array.isArray(product) ? product : [product]; - productList.forEach(function(product) { + productList.forEach(function (product) { if (product.TotalAmount) { product.TotalAmount = mpInstance._Ecommerce.sanitizeAmount( product.TotalAmount, - 'TotalAmount' + 'TotalAmount', ); } if (product.Position) { product.Position = mpInstance._Ecommerce.sanitizeAmount( product.Position, - 'Position' + 'Position', ); } if (product.Price) { product.Price = mpInstance._Ecommerce.sanitizeAmount( product.Price, - 'Price' + 'Price', ); } if (product.Quantity) { product.Quantity = mpInstance._Ecommerce.sanitizeAmount( product.Quantity, - 'Quantity' + 'Quantity', ); } }); if (event) { - event.EventCategory = mpInstance._Ecommerce.convertProductActionToEventType( - productActionType - ); - event.EventName += mpInstance._Ecommerce.getProductActionEventName( - productActionType - ); + event.EventCategory = + mpInstance._Ecommerce.convertProductActionToEventType( + productActionType, + ); + event.EventName += + mpInstance._Ecommerce.getProductActionEventName( + productActionType, + ); event.ProductAction = { ProductActionType: productActionType, ProductList: productList, @@ -177,7 +180,7 @@ export default function Events(mpInstance) { if (mpInstance._Helpers.isObject(transactionAttributes)) { mpInstance._Ecommerce.convertTransactionAttributesToProductAction( transactionAttributes, - event.ProductAction + event.ProductAction, ); } @@ -185,93 +188,88 @@ export default function Events(mpInstance) { } }; - this.logPurchaseEvent = function( + this.logPurchaseEvent = function ( transactionAttributes, product, attrs, - customFlags + customFlags, ) { - var event = mpInstance._Ecommerce.createCommerceEventObject( - customFlags - ); + const event = + mpInstance._Ecommerce.createCommerceEventObject(customFlags); if (event) { event.EventName += mpInstance._Ecommerce.getProductActionEventName( - Types.ProductActionType.Purchase + Types.ProductActionType.Purchase, ); event.EventCategory = Types.CommerceEventType.ProductPurchase; event.ProductAction = { ProductActionType: Types.ProductActionType.Purchase, }; - event.ProductAction.ProductList = mpInstance._Ecommerce.buildProductList( - event, - product - ); + event.ProductAction.ProductList = + mpInstance._Ecommerce.buildProductList(event, product); mpInstance._Ecommerce.convertTransactionAttributesToProductAction( transactionAttributes, - event.ProductAction + event.ProductAction, ); self.logCommerceEvent(event, attrs); } }; - this.logRefundEvent = function( + this.logRefundEvent = function ( transactionAttributes, product, attrs, - customFlags + customFlags, ) { if (!transactionAttributes) { mpInstance.Logger.error(Messages.ErrorMessages.TransactionRequired); return; } - var event = mpInstance._Ecommerce.createCommerceEventObject( - customFlags - ); + const event = + mpInstance._Ecommerce.createCommerceEventObject(customFlags); if (event) { event.EventName += mpInstance._Ecommerce.getProductActionEventName( - Types.ProductActionType.Refund + Types.ProductActionType.Refund, ); event.EventCategory = Types.CommerceEventType.ProductRefund; event.ProductAction = { ProductActionType: Types.ProductActionType.Refund, }; - event.ProductAction.ProductList = mpInstance._Ecommerce.buildProductList( - event, - product - ); + event.ProductAction.ProductList = + mpInstance._Ecommerce.buildProductList(event, product); mpInstance._Ecommerce.convertTransactionAttributesToProductAction( transactionAttributes, - event.ProductAction + event.ProductAction, ); self.logCommerceEvent(event, attrs); } }; - this.logPromotionEvent = function( + this.logPromotionEvent = function ( promotionType, promotion, attrs, customFlags, - eventOptions + eventOptions, ) { - var event = mpInstance._Ecommerce.createCommerceEventObject( - customFlags - ); + const event = + mpInstance._Ecommerce.createCommerceEventObject(customFlags); if (event) { - event.EventName += mpInstance._Ecommerce.getPromotionActionEventName( - promotionType - ); - event.EventCategory = mpInstance._Ecommerce.convertPromotionActionToEventType( - promotionType - ); + event.EventName += + mpInstance._Ecommerce.getPromotionActionEventName( + promotionType, + ); + event.EventCategory = + mpInstance._Ecommerce.convertPromotionActionToEventType( + promotionType, + ); event.PromotionAction = { PromotionActionType: promotionType, PromotionList: Array.isArray(promotion) @@ -283,15 +281,14 @@ export default function Events(mpInstance) { } }; - this.logImpressionEvent = function( + this.logImpressionEvent = function ( impression, attrs, customFlags, - options + options, ) { - var event = mpInstance._Ecommerce.createCommerceEventObject( - customFlags - ); + const event = + mpInstance._Ecommerce.createCommerceEventObject(customFlags); if (event) { event.EventName += 'Impression'; @@ -302,7 +299,7 @@ export default function Events(mpInstance) { event.ProductImpressions = []; - impression.forEach(function(impression) { + impression.forEach(function (impression) { event.ProductImpressions.push({ ProductImpressionList: impression.Name, ProductList: Array.isArray(impression.Product) @@ -315,9 +312,9 @@ export default function Events(mpInstance) { } }; - this.logCommerceEvent = function(commerceEvent, attrs, options) { + this.logCommerceEvent = function (commerceEvent, attrs, options) { mpInstance.Logger.verbose( - Messages.InformationMessages.StartingLogCommerceEvent + Messages.InformationMessages.StartingLogCommerceEvent, ); // If a developer typos the ProductActionType, the event category will be @@ -329,14 +326,14 @@ export default function Events(mpInstance) { commerceEvent.EventCategory === null ) { mpInstance.Logger.error( - 'Commerce event not sent. The mParticle.ProductActionType you passed was invalid. Re-check your code.' + 'Commerce event not sent. The mParticle.ProductActionType you passed was invalid. Re-check your code.', ); return; } attrs = mpInstance._Helpers.sanitizeAttributes( attrs, - commerceEvent.EventName + commerceEvent.EventName, ); if (mpInstance._Helpers.canLog()) { @@ -355,21 +352,21 @@ export default function Events(mpInstance) { mpInstance._Persistence.update(); } else { mpInstance.Logger.verbose( - Messages.InformationMessages.AbandonLogEvent + Messages.InformationMessages.AbandonLogEvent, ); } }; - this.addEventHandler = function( + this.addEventHandler = function ( domEvent, selector, eventName, data, - eventType + eventType, ) { - var elements = [], - handler = function(e) { - var timeoutHandler = function() { + let elements = [], + handler = function (e) { + const timeoutHandler = function () { if (element.href) { window.location.href = element.href; } else if (element.submit) { @@ -378,7 +375,7 @@ export default function Events(mpInstance) { }; mpInstance.Logger.verbose( - 'DOM event triggered, handling event' + 'DOM event triggered, handling event', ); self.logEvent({ @@ -406,7 +403,7 @@ export default function Events(mpInstance) { setTimeout( timeoutHandler, - mpInstance._Store.SDKConfig.timeout + mpInstance._Store.SDKConfig.timeout, ); } }, @@ -431,7 +428,7 @@ export default function Events(mpInstance) { elements.length + ' element' + (elements.length > 1 ? 's' : '') + - ', attaching event handlers' + ', attaching event handlers', ); for (i = 0; i < elements.length; i++) { diff --git a/src/filteredMparticleUser.js b/src/filteredMparticleUser.js index 640fd356a..0ca759763 100644 --- a/src/filteredMparticleUser.js +++ b/src/filteredMparticleUser.js @@ -4,18 +4,18 @@ export default function filteredMparticleUser( mpid, forwarder, mpInstance, - kitBlocker + kitBlocker, ) { - var self = this; + const self = this; return { - getUserIdentities: function() { - var currentUserIdentities = {}; - var identities = mpInstance._Store.getUserIdentities(mpid); + getUserIdentities: function () { + let currentUserIdentities = {}; + const identities = mpInstance._Store.getUserIdentities(mpid); - for (var identityType in identities) { + for (const identityType in identities) { if (identities.hasOwnProperty(identityType)) { - var identityName = Types.IdentityType.getIdentityName( - mpInstance._Helpers.parseNumber(identityType) + const identityName = Types.IdentityType.getIdentityName( + mpInstance._Helpers.parseNumber(identityType), ); if ( !kitBlocker || @@ -28,24 +28,24 @@ export default function filteredMparticleUser( } } - currentUserIdentities = mpInstance._Helpers.filterUserIdentitiesForForwarders( - currentUserIdentities, - forwarder.userIdentityFilters - ); + currentUserIdentities = + mpInstance._Helpers.filterUserIdentitiesForForwarders( + currentUserIdentities, + forwarder.userIdentityFilters, + ); return { userIdentities: currentUserIdentities, }; }, - getMPID: function() { + getMPID: function () { return mpid; }, - getUserAttributesLists: function(forwarder) { - var userAttributes, - userAttributesLists = {}; + getUserAttributesLists: function (forwarder) { + let userAttributesLists = {}; - userAttributes = self.getAllUserAttributes(); - for (var key in userAttributes) { + const userAttributes = self.getAllUserAttributes(); + for (const key in userAttributes) { if ( userAttributes.hasOwnProperty(key) && Array.isArray(userAttributes[key]) @@ -61,17 +61,17 @@ export default function filteredMparticleUser( userAttributesLists = mpInstance._Helpers.filterUserAttributes( userAttributesLists, - forwarder.userAttributeFilters + forwarder.userAttributeFilters, ); return userAttributesLists; }, - getAllUserAttributes: function() { - var userAttributesCopy = {}; - var userAttributes = mpInstance._Store.getUserAttributes(mpid); + getAllUserAttributes: function () { + let userAttributesCopy = {}; + const userAttributes = mpInstance._Store.getUserAttributes(mpid); if (userAttributes) { - for (var prop in userAttributes) { + for (const prop in userAttributes) { if (userAttributes.hasOwnProperty(prop)) { if ( !kitBlocker || @@ -79,9 +79,8 @@ export default function filteredMparticleUser( !kitBlocker.isAttributeKeyBlocked(prop)) ) { if (Array.isArray(userAttributes[prop])) { - userAttributesCopy[prop] = userAttributes[ - prop - ].slice(); + userAttributesCopy[prop] = + userAttributes[prop].slice(); } else { userAttributesCopy[prop] = userAttributes[prop]; } @@ -92,7 +91,7 @@ export default function filteredMparticleUser( userAttributesCopy = mpInstance._Helpers.filterUserAttributes( userAttributesCopy, - forwarder.userAttributeFilters + forwarder.userAttributeFilters, ); return userAttributesCopy; diff --git a/src/foregroundTimeTracker.ts b/src/foregroundTimeTracker.ts index c64ca3eff..a377a0f03 100644 --- a/src/foregroundTimeTracker.ts +++ b/src/foregroundTimeTracker.ts @@ -2,11 +2,11 @@ import { isNumber } from './utils'; import { LocalStorageVault } from './vault'; export default class ForegroundTimeTracker { - private isTrackerActive: boolean = false; - private localStorageName: string = ''; + private isTrackerActive = false; + private localStorageName = ''; private timerVault: LocalStorageVault; - public startTime: number = 0; - public totalTime: number = 0; + public startTime = 0; + public totalTime = 0; constructor(timerKey: string) { this.localStorageName = `mprtcl-tos-${timerKey}`; @@ -21,17 +21,19 @@ export default class ForegroundTimeTracker { private addHandlers(): void { // when user switches tabs or minimizes the window document.addEventListener('visibilitychange', () => - this.handleVisibilityChange() + this.handleVisibilityChange(), ); // when user switches to another application window.addEventListener('blur', () => this.handleWindowBlur()); // when window gains focus window.addEventListener('focus', () => this.handleWindowFocus()); // this ensures that timers between tabs are in sync - window.addEventListener('storage', event => this.syncAcrossTabs(event)); + window.addEventListener('storage', (event) => + this.syncAcrossTabs(event), + ); // when user closes tab, refreshes, or navigates to another page via link window.addEventListener('beforeunload', () => - this.updateTimeInPersistence() + this.updateTimeInPersistence(), ); } @@ -75,7 +77,6 @@ export default class ForegroundTimeTracker { } } - private startTracking(): void { if (!document.hidden) { this.startTime = Math.floor(performance.now()); @@ -96,7 +97,6 @@ export default class ForegroundTimeTracker { const now = Math.floor(performance.now()); this.totalTime += now - this.startTime; this.startTime = now; - } } @@ -110,4 +110,4 @@ export default class ForegroundTimeTracker { this.totalTime = 0; this.updateTimeInPersistence(); } -} \ No newline at end of file +} diff --git a/src/forwarders.interfaces.ts b/src/forwarders.interfaces.ts index 6516356b5..3baf17c43 100644 --- a/src/forwarders.interfaces.ts +++ b/src/forwarders.interfaces.ts @@ -59,23 +59,23 @@ export interface ConfiguredKit appVersion: string, appName: string, customFlags: SDKEventCustomFlags, - clientId: string + clientId: string, ): string; onIdentifyComplete( user: IMParticleUser, - filteredIdentityRequest: IdentityApiData + filteredIdentityRequest: IdentityApiData, ): string; onLoginComplete( user: IMParticleUser, - filteredIdentityRequest: IdentityApiData + filteredIdentityRequest: IdentityApiData, ): string; onLogoutComplete( user: IMParticleUser, - filteredIdentityRequest: IdentityApiData + filteredIdentityRequest: IdentityApiData, ): string; onModifyComplete( user: IMParticleUser, - filteredIdentityRequest: IdentityApiData + filteredIdentityRequest: IdentityApiData, ): string; onUserIdentified(user: IMParticleUser): string; process(event: SDKEvent): string; @@ -92,9 +92,9 @@ export interface ConfiguredKit export type UserIdentityId = string; export type UserIdentityType = number; export type UserAttributeFilters = number[]; -export type UserIdentityFilters = typeof IdentityType[]; +export type UserIdentityFilters = (typeof IdentityType)[]; export type forwardingStatsCallback = ( forwarder: ConfiguredKit, - event: SDKEvent + event: SDKEvent, ) => void; diff --git a/src/forwarders.js b/src/forwarders.js index be03512b1..5614464bf 100644 --- a/src/forwarders.js +++ b/src/forwarders.js @@ -8,10 +8,10 @@ import APIClient from './apiClient'; const { Modify, Identify, Login, Logout } = Constants.IdentityMethods; export default function Forwarders(mpInstance, kitBlocker) { - var self = this; + const self = this; this.forwarderStatsUploader = new APIClient( mpInstance, - kitBlocker + kitBlocker, ).initializeForwarderStatsUploader(); const UserAttributeActionTypes = { @@ -19,14 +19,14 @@ export default function Forwarders(mpInstance, kitBlocker) { removeUserAttribute: 'removeUserAttribute', }; - this.initForwarders = function(userIdentities, forwardingStatsCallback) { - var user = mpInstance.Identity.getCurrentUser(); + this.initForwarders = function (userIdentities, forwardingStatsCallback) { + const user = mpInstance.Identity.getCurrentUser(); if ( !mpInstance._Store.webviewBridgeEnabled && mpInstance._Store.configuredForwarders ) { // Some js libraries require that they be loaded first, or last, etc - mpInstance._Store.configuredForwarders.sort(function(x, y) { + mpInstance._Store.configuredForwarders.sort(function (x, y) { x.settings.PriorityValue = x.settings.PriorityValue || 0; y.settings.PriorityValue = y.settings.PriorityValue || 0; return ( @@ -34,65 +34,68 @@ export default function Forwarders(mpInstance, kitBlocker) { ); }); - mpInstance._Store.activeForwarders = mpInstance._Store.configuredForwarders.filter( - function(forwarder) { - if ( - !mpInstance._Consent.isEnabledForUserConsent( - forwarder.filteringConsentRuleValues, - user - ) - ) { - return false; - } - if ( - !self.isEnabledForUserAttributes( - forwarder.filteringUserAttributeValue, - user - ) - ) { - return false; - } - if ( - !self.isEnabledForUnknownUser( - forwarder.excludeAnonymousUser, - user - ) - ) { - return false; - } + mpInstance._Store.activeForwarders = + mpInstance._Store.configuredForwarders.filter( + function (forwarder) { + if ( + !mpInstance._Consent.isEnabledForUserConsent( + forwarder.filteringConsentRuleValues, + user, + ) + ) { + return false; + } + if ( + !self.isEnabledForUserAttributes( + forwarder.filteringUserAttributeValue, + user, + ) + ) { + return false; + } + if ( + !self.isEnabledForUnknownUser( + forwarder.excludeAnonymousUser, + user, + ) + ) { + return false; + } - var filteredUserIdentities = mpInstance._Helpers.filterUserIdentities( - userIdentities, - forwarder.userIdentityFilters - ); - var filteredUserAttributes = mpInstance._Helpers.filterUserAttributes( - user ? user.getAllUserAttributes() : {}, - forwarder.userAttributeFilters - ); - if (!forwarder.initialized) { - forwarder.logger = mpInstance.Logger; - forwarder.init( - forwarder.settings, - forwardingStatsCallback, - false, - null, - filteredUserAttributes, - filteredUserIdentities, - mpInstance._Store.SDKConfig.appVersion, - mpInstance._Store.SDKConfig.appName, - mpInstance._Store.SDKConfig.customFlags, - mpInstance._Store.clientId - ); - forwarder.initialized = true; - } + const filteredUserIdentities = + mpInstance._Helpers.filterUserIdentities( + userIdentities, + forwarder.userIdentityFilters, + ); + const filteredUserAttributes = + mpInstance._Helpers.filterUserAttributes( + user ? user.getAllUserAttributes() : {}, + forwarder.userAttributeFilters, + ); + if (!forwarder.initialized) { + forwarder.logger = mpInstance.Logger; + forwarder.init( + forwarder.settings, + forwardingStatsCallback, + false, + null, + filteredUserAttributes, + filteredUserIdentities, + mpInstance._Store.SDKConfig.appVersion, + mpInstance._Store.SDKConfig.appName, + mpInstance._Store.SDKConfig.customFlags, + mpInstance._Store.clientId, + ); + forwarder.initialized = true; + } - return true; - } - ); + return true; + }, + ); } }; - this.isEnabledForUserAttributes = function(filterObject, user) { + this.isEnabledForUserAttributes = function (filterObject, user) { if ( !filterObject || !mpInstance._Helpers.isObject(filterObject) || @@ -101,7 +104,7 @@ export default function Forwarders(mpInstance, kitBlocker) { return true; } - var attrHash, valueHash, userAttributes; + let attrHash, valueHash, userAttributes; if (!user) { return false; @@ -109,7 +112,7 @@ export default function Forwarders(mpInstance, kitBlocker) { userAttributes = user.getAllUserAttributes(); } - var isMatch = false; + let isMatch = false; try { if ( @@ -117,14 +120,16 @@ export default function Forwarders(mpInstance, kitBlocker) { mpInstance._Helpers.isObject(userAttributes) && Object.keys(userAttributes).length ) { - for (var attrName in userAttributes) { + for (const attrName in userAttributes) { if (userAttributes.hasOwnProperty(attrName)) { - attrHash = KitFilterHelper.hashAttributeConditionalForwarding( - attrName - ); - valueHash = KitFilterHelper.hashAttributeConditionalForwarding( - userAttributes[attrName] - ); + attrHash = + KitFilterHelper.hashAttributeConditionalForwarding( + attrName, + ); + valueHash = + KitFilterHelper.hashAttributeConditionalForwarding( + userAttributes[attrName], + ); if ( attrHash === filterObject.userAttributeName && @@ -148,7 +153,10 @@ export default function Forwarders(mpInstance, kitBlocker) { } }; - this.isEnabledForUnknownUser = function(excludeAnonymousUserBoolean, user) { + this.isEnabledForUnknownUser = function ( + excludeAnonymousUserBoolean, + user, + ) { if (!user || !user.isLoggedIn()) { if (excludeAnonymousUserBoolean) { return false; @@ -157,13 +165,13 @@ export default function Forwarders(mpInstance, kitBlocker) { return true; }; - this.applyToForwarders = function(functionName, functionArgs) { + this.applyToForwarders = function (functionName, functionArgs) { if (mpInstance._Store.activeForwarders.length) { - mpInstance._Store.activeForwarders.forEach(function(forwarder) { - var forwarderFunction = forwarder[functionName]; + mpInstance._Store.activeForwarders.forEach(function (forwarder) { + const forwarderFunction = forwarder[functionName]; if (forwarderFunction) { try { - var result = forwarder[functionName](functionArgs); + const result = forwarder[functionName](functionArgs); if (result) { mpInstance.Logger.verbose(result); @@ -176,19 +184,19 @@ export default function Forwarders(mpInstance, kitBlocker) { } }; - this.sendEventToForwarders = function(event) { - var clonedEvent, + this.sendEventToForwarders = function (event) { + let clonedEvent, hashedEventName, hashedEventType, - filterUserIdentities = function(event, filterList) { + filterUserIdentities = function (event, filterList) { if (event.UserIdentities && event.UserIdentities.length) { - event.UserIdentities.forEach(function(userIdentity, i) { + event.UserIdentities.forEach(function (userIdentity, i) { if ( mpInstance._Helpers.inArray( filterList, KitFilterHelper.hashUserIdentity( - userIdentity.Type - ) + userIdentity.Type, + ), ) ) { event.UserIdentities.splice(i, 1); @@ -200,19 +208,19 @@ export default function Forwarders(mpInstance, kitBlocker) { }); } }, - filterAttributes = function(event, filterList) { - var hash; + filterAttributes = function (event, filterList) { + let hash; if (!filterList) { return; } - for (var attrName in event.EventAttributes) { + for (const attrName in event.EventAttributes) { if (event.EventAttributes.hasOwnProperty(attrName)) { hash = KitFilterHelper.hashEventAttributeKey( event.EventCategory, event.EventName, - attrName + attrName, ); if (mpInstance._Helpers.inArray(filterList, hash)) { @@ -221,7 +229,7 @@ export default function Forwarders(mpInstance, kitBlocker) { } } }, - inFilteredList = function(filterList, hash) { + inFilteredList = function (filterList, hash) { if (filterList && filterList.length) { if (mpInstance._Helpers.inArray(filterList, hash)) { return true; @@ -242,14 +250,14 @@ export default function Forwarders(mpInstance, kitBlocker) { ) { hashedEventName = KitFilterHelper.hashEventName( event.EventName, - event.EventCategory + event.EventCategory, ); hashedEventType = KitFilterHelper.hashEventType( - event.EventCategory + event.EventCategory, ); for ( - var i = 0; + let i = 0; i < mpInstance._Store.activeForwarders.length; i++ ) { @@ -269,15 +277,16 @@ export default function Forwarders(mpInstance, kitBlocker) { mpInstance._Store.activeForwarders[i] .filteringEventAttributeValue.eventAttributeValue ) { - var foundProp = null; + let foundProp = null; // Attempt to find the attribute in the collection of event attributes if (event.EventAttributes) { - for (var prop in event.EventAttributes) { + for (const prop in event.EventAttributes) { var hashedEventAttributeName; - hashedEventAttributeName = KitFilterHelper.hashAttributeConditionalForwarding( - prop - ); + hashedEventAttributeName = + KitFilterHelper.hashAttributeConditionalForwarding( + prop, + ); if ( hashedEventAttributeName === @@ -288,7 +297,7 @@ export default function Forwarders(mpInstance, kitBlocker) { foundProp = { name: hashedEventAttributeName, value: KitFilterHelper.hashAttributeConditionalForwarding( - event.EventAttributes[prop] + event.EventAttributes[prop], ), }; } @@ -299,14 +308,14 @@ export default function Forwarders(mpInstance, kitBlocker) { } } - var isMatch = + const isMatch = foundProp !== null && foundProp.value === mpInstance._Store.activeForwarders[i] .filteringEventAttributeValue .eventAttributeValue; - var shouldInclude = + const shouldInclude = mpInstance._Store.activeForwarders[i] .filteringEventAttributeValue.includeOnMatch === true @@ -323,19 +332,19 @@ export default function Forwarders(mpInstance, kitBlocker) { clonedEvent = mpInstance._Helpers.extend( true, clonedEvent, - event + event, ); // Check event filtering rules if ( event.EventDataType === Types.MessageType.PageEvent && (inFilteredList( mpInstance._Store.activeForwarders[i].eventNameFilters, - hashedEventName + hashedEventName, ) || inFilteredList( mpInstance._Store.activeForwarders[i] .eventTypeFilters, - hashedEventType + hashedEventType, )) ) { continue; @@ -343,7 +352,7 @@ export default function Forwarders(mpInstance, kitBlocker) { event.EventDataType === Types.MessageType.Commerce && inFilteredList( mpInstance._Store.activeForwarders[i].eventTypeFilters, - hashedEventType + hashedEventType, ) ) { continue; @@ -351,7 +360,7 @@ export default function Forwarders(mpInstance, kitBlocker) { event.EventDataType === Types.MessageType.PageView && inFilteredList( mpInstance._Store.activeForwarders[i].screenNameFilters, - hashedEventName + hashedEventName, ) ) { continue; @@ -363,7 +372,7 @@ export default function Forwarders(mpInstance, kitBlocker) { filterAttributes( clonedEvent, mpInstance._Store.activeForwarders[i] - .attributeFilters + .attributeFilters, ); } else if ( event.EventDataType === Types.MessageType.PageView @@ -371,7 +380,7 @@ export default function Forwarders(mpInstance, kitBlocker) { filterAttributes( clonedEvent, mpInstance._Store.activeForwarders[i] - .screenAttributeFilters + .screenAttributeFilters, ); } } @@ -379,23 +388,26 @@ export default function Forwarders(mpInstance, kitBlocker) { // Check user identity filtering rules filterUserIdentities( clonedEvent, - mpInstance._Store.activeForwarders[i].userIdentityFilters + mpInstance._Store.activeForwarders[i].userIdentityFilters, ); // Check user attribute filtering rules - clonedEvent.UserAttributes = mpInstance._Helpers.filterUserAttributes( - clonedEvent.UserAttributes, - mpInstance._Store.activeForwarders[i].userAttributeFilters - ); + clonedEvent.UserAttributes = + mpInstance._Helpers.filterUserAttributes( + clonedEvent.UserAttributes, + mpInstance._Store.activeForwarders[i] + .userAttributeFilters, + ); if (mpInstance._Store.activeForwarders[i].process) { mpInstance.Logger.verbose( 'Sending message to forwarder: ' + - mpInstance._Store.activeForwarders[i].name - ); - var result = mpInstance._Store.activeForwarders[i].process( - clonedEvent + mpInstance._Store.activeForwarders[i].name, ); + const result = + mpInstance._Store.activeForwarders[i].process( + clonedEvent, + ); if (result) { mpInstance.Logger.verbose(result); @@ -405,7 +417,11 @@ export default function Forwarders(mpInstance, kitBlocker) { } }; - this.handleForwarderUserAttributes = function(functionNameKey, key, value) { + this.handleForwarderUserAttributes = function ( + functionNameKey, + key, + value, + ) { if ( (kitBlocker && kitBlocker.isAttributeKeyBlocked(key)) || !mpInstance._Store.activeForwarders.length @@ -413,13 +429,13 @@ export default function Forwarders(mpInstance, kitBlocker) { return; } - mpInstance._Store.activeForwarders.forEach(function(forwarder) { + mpInstance._Store.activeForwarders.forEach(function (forwarder) { const forwarderFunction = forwarder[functionNameKey]; if ( !forwarderFunction || KitFilterHelper.isFilteredUserAttribute( key, - forwarder.userAttributeFilters + forwarder.userAttributeFilters, ) ) { return; @@ -449,17 +465,18 @@ export default function Forwarders(mpInstance, kitBlocker) { }; // TODO: https://go.mparticle.com/work/SQDSDKS-6036 - this.setForwarderUserIdentities = function(userIdentities) { - mpInstance._Store.activeForwarders.forEach(function(forwarder) { - var filteredUserIdentities = mpInstance._Helpers.filterUserIdentities( - userIdentities, - forwarder.userIdentityFilters - ); + this.setForwarderUserIdentities = function (userIdentities) { + mpInstance._Store.activeForwarders.forEach(function (forwarder) { + const filteredUserIdentities = + mpInstance._Helpers.filterUserIdentities( + userIdentities, + forwarder.userIdentityFilters, + ); if (forwarder.setUserIdentity) { - filteredUserIdentities.forEach(function(identity) { - var result = forwarder.setUserIdentity( + filteredUserIdentities.forEach(function (identity) { + const result = forwarder.setUserIdentity( identity.Identity, - identity.Type + identity.Type, ); if (result) { mpInstance.Logger.verbose(result); @@ -469,16 +486,16 @@ export default function Forwarders(mpInstance, kitBlocker) { }); }; - this.setForwarderOnUserIdentified = function(user) { - mpInstance._Store.activeForwarders.forEach(function(forwarder) { - var filteredUser = filteredMparticleUser( + this.setForwarderOnUserIdentified = function (user) { + mpInstance._Store.activeForwarders.forEach(function (forwarder) { + const filteredUser = filteredMparticleUser( user.getMPID(), forwarder, mpInstance, - kitBlocker + kitBlocker, ); if (forwarder.onUserIdentified) { - var result = forwarder.onUserIdentified(filteredUser); + const result = forwarder.onUserIdentified(filteredUser); if (result) { mpInstance.Logger.verbose(result); } @@ -486,15 +503,15 @@ export default function Forwarders(mpInstance, kitBlocker) { }); }; - this.setForwarderOnIdentityComplete = function(user, identityMethod) { - var result; + this.setForwarderOnIdentityComplete = function (user, identityMethod) { + let result; - mpInstance._Store.activeForwarders.forEach(function(forwarder) { - var filteredUser = filteredMparticleUser( + mpInstance._Store.activeForwarders.forEach(function (forwarder) { + const filteredUser = filteredMparticleUser( user.getMPID(), forwarder, mpInstance, - kitBlocker + kitBlocker, ); const filteredUserIdentities = filteredUser.getUserIdentities(); @@ -503,7 +520,7 @@ export default function Forwarders(mpInstance, kitBlocker) { if (forwarder.onIdentifyComplete) { result = forwarder.onIdentifyComplete( filteredUser, - filteredUserIdentities + filteredUserIdentities, ); if (result) { mpInstance.Logger.verbose(result); @@ -513,7 +530,7 @@ export default function Forwarders(mpInstance, kitBlocker) { if (forwarder.onLoginComplete) { result = forwarder.onLoginComplete( filteredUser, - filteredUserIdentities + filteredUserIdentities, ); if (result) { mpInstance.Logger.verbose(result); @@ -523,7 +540,7 @@ export default function Forwarders(mpInstance, kitBlocker) { if (forwarder.onLogoutComplete) { result = forwarder.onLogoutComplete( filteredUser, - filteredUserIdentities + filteredUserIdentities, ); if (result) { mpInstance.Logger.verbose(result); @@ -533,7 +550,7 @@ export default function Forwarders(mpInstance, kitBlocker) { if (forwarder.onModifyComplete) { result = forwarder.onModifyComplete( filteredUser, - filteredUserIdentities + filteredUserIdentities, ); if (result) { mpInstance.Logger.verbose(result); @@ -543,13 +560,14 @@ export default function Forwarders(mpInstance, kitBlocker) { }); }; - this.getForwarderStatsQueue = function() { + this.getForwarderStatsQueue = function () { return mpInstance._Persistence.forwardingStatsBatches .forwardingStatsEventQueue; }; - this.setForwarderStatsQueue = function(queue) { - mpInstance._Persistence.forwardingStatsBatches.forwardingStatsEventQueue = queue; + this.setForwarderStatsQueue = function (queue) { + mpInstance._Persistence.forwardingStatsBatches.forwardingStatsEventQueue = + queue; }; // Processing forwarders is a 2 step process: @@ -558,10 +576,10 @@ export default function Forwarders(mpInstance, kitBlocker) { // There are 2 types of kits: // 1. UI-enabled kits // 2. Sideloaded kits. - this.processForwarders = function(config, forwardingStatsCallback) { + this.processForwarders = function (config, forwardingStatsCallback) { if (!config) { mpInstance.Logger.warning( - 'No config was passed. Cannot process forwarders' + 'No config was passed. Cannot process forwarders', ); } else { this.processUIEnabledKits(config); @@ -569,7 +587,7 @@ export default function Forwarders(mpInstance, kitBlocker) { self.initForwarders( mpInstance._Store.SDKConfig.identifyRequest.userIdentities, - forwardingStatsCallback + forwardingStatsCallback, ); } }; @@ -580,56 +598,56 @@ export default function Forwarders(mpInstance, kitBlocker) { // The kit configuration will be compared with the kit constructors to determine // if there is a match before being initialized. // Only kits that are configured properly can be active and used for kit forwarding. - this.processUIEnabledKits = function(config) { - let kits = this.returnKitConstructors(); + this.processUIEnabledKits = function (config) { + const kits = this.returnKitConstructors(); try { if (Array.isArray(config.kitConfigs) && config.kitConfigs.length) { - config.kitConfigs.forEach(function(kitConfig) { + config.kitConfigs.forEach(function (kitConfig) { self.configureUIEnabledKit(kitConfig, kits); }); } } catch (e) { mpInstance.Logger.error( 'MP Kits not configured propertly. Kits may not be initialized. ' + - e + e, ); } }; - this.returnKitConstructors = function() { + this.returnKitConstructors = function () { let kits = {}; // If there are kits inside of mpInstance._Store.SDKConfig.kits, then mParticle is self hosted if (!isEmpty(mpInstance._Store.SDKConfig.kits)) { kits = mpInstance._Store.SDKConfig.kits; // otherwise mParticle is loaded via script tag } else if (!isEmpty(mpInstance._preInit.forwarderConstructors)) { - mpInstance._preInit.forwarderConstructors.forEach(function( - kitConstructor - ) { - // A suffix is added to a kitConstructor and kit config if there are multiple different - // versions of a client kit. This matches the suffix in the DB. As an example - // the GA4 kit has a client kit and a server side kit which has a client side - // component. They share the same name/module ID in the DB, so we include a - // suffix to distinguish them in the kits object. - // If a customer wanted simultaneous GA4 client and server connections, - // a suffix allows the SDK to distinguish the two. - if (kitConstructor.suffix) { - const kitNameWithConstructorSuffix = `${kitConstructor.name}-${kitConstructor.suffix}`; - kits[kitNameWithConstructorSuffix] = kitConstructor; - } else { - kits[kitConstructor.name] = kitConstructor; - } - }); + mpInstance._preInit.forwarderConstructors.forEach( + function (kitConstructor) { + // A suffix is added to a kitConstructor and kit config if there are multiple different + // versions of a client kit. This matches the suffix in the DB. As an example + // the GA4 kit has a client kit and a server side kit which has a client side + // component. They share the same name/module ID in the DB, so we include a + // suffix to distinguish them in the kits object. + // If a customer wanted simultaneous GA4 client and server connections, + // a suffix allows the SDK to distinguish the two. + if (kitConstructor.suffix) { + const kitNameWithConstructorSuffix = `${kitConstructor.name}-${kitConstructor.suffix}`; + kits[kitNameWithConstructorSuffix] = kitConstructor; + } else { + kits[kitConstructor.name] = kitConstructor; + } + }, + ); } return kits; }; - this.configureUIEnabledKit = function(configuration, kits) { + this.configureUIEnabledKit = function (configuration, kits) { let newKit = null; const config = configuration; - for (let name in kits) { + for (const name in kits) { // Configs are returned with suffixes also. We need to consider the // config suffix here to match the constructor suffix let kitNameWithConfigSuffix; @@ -660,18 +678,18 @@ export default function Forwarders(mpInstance, kitBlocker) { // In the future, when all kits are moved to the mpConfig rather than // there being a separate process for MP configured kits and // sideloaded kits, this will need to be refactored. - this.processSideloadedKits = function(mpConfig) { + this.processSideloadedKits = function (mpConfig) { try { if (Array.isArray(mpConfig.sideloadedKits)) { const registeredSideloadedKits = { kits: {} }; const unregisteredSideloadedKits = mpConfig.sideloadedKits; - unregisteredSideloadedKits.forEach(function(unregisteredKit) { + unregisteredSideloadedKits.forEach(function (unregisteredKit) { try { // Register each sideloaded kit, which adds a key of the sideloaded kit name // and a value of the sideloaded kit constructor. unregisteredKit.kitInstance.register( - registeredSideloadedKits + registeredSideloadedKits, ); const kitName = unregisteredKit.kitInstance.name; // Then add the kit filters to each registered kit. @@ -680,7 +698,7 @@ export default function Forwarders(mpInstance, kitBlocker) { } catch (e) { console.error( 'Error registering sideloaded kit ' + - unregisteredKit.kitInstance.name + unregisteredKit.kitInstance.name, ); } }); @@ -702,19 +720,19 @@ export default function Forwarders(mpInstance, kitBlocker) { } catch (e) { mpInstance.Logger.error( 'Sideloaded Kits not configured propertly. Kits may not be initialized. ' + - e + e, ); } }; // kits can be included via mParticle UI, or via sideloaded kit config API - this.configureSideloadedKit = function(kitConstructor) { + this.configureSideloadedKit = function (kitConstructor) { mpInstance._Store.configuredForwarders.push( - this.returnConfiguredKit(kitConstructor, kitConstructor.filters) + this.returnConfiguredKit(kitConstructor, kitConstructor.filters), ); }; - this.returnConfiguredKit = function(forwarder, config = {}) { + this.returnConfiguredKit = function (forwarder, config = {}) { const newForwarder = new forwarder.constructor(); newForwarder.id = config.moduleId; @@ -751,7 +769,7 @@ export default function Forwarders(mpInstance, kitBlocker) { return newForwarder; }; - this.configurePixel = function(settings) { + this.configurePixel = function (settings) { if ( settings.isDebug === mpInstance._Store.SDKConfig.isDevelopmentMode || @@ -762,22 +780,22 @@ export default function Forwarders(mpInstance, kitBlocker) { } }; - this.processPixelConfigs = function(config) { + this.processPixelConfigs = function (config) { try { if (!isEmpty(config.pixelConfigs)) { - config.pixelConfigs.forEach(function(pixelConfig) { + config.pixelConfigs.forEach(function (pixelConfig) { self.configurePixel(pixelConfig); }); } } catch (e) { mpInstance.Logger.error( 'Cookie Sync configs not configured propertly. Cookie Sync may not be initialized. ' + - e + e, ); } }; - this.sendSingleForwardingStatsToServer = async forwardingStatsData => { + this.sendSingleForwardingStatsToServer = async (forwardingStatsData) => { // https://go.mparticle.com/work/SQDSDKS-6568 const fetchPayload = { method: 'post', diff --git a/src/forwardingStatsUploader.js b/src/forwardingStatsUploader.js index ae45d4246..680975f60 100644 --- a/src/forwardingStatsUploader.js +++ b/src/forwardingStatsUploader.js @@ -1,12 +1,12 @@ export default function forwardingStatsUploader(mpInstance) { - this.startForwardingStatsTimer = function() { - mParticle._forwardingStatsTimer = setInterval(function() { + this.startForwardingStatsTimer = function () { + mParticle._forwardingStatsTimer = setInterval(function () { prepareAndSendForwardingStatsBatch(); }, mpInstance._Store.SDKConfig.forwarderStatsTimeout); }; function prepareAndSendForwardingStatsBatch() { - var forwarderQueue = mpInstance._Forwarders.getForwarderStatsQueue(), + const forwarderQueue = mpInstance._Forwarders.getForwarderStatsQueue(), uploadsTable = mpInstance._Persistence.forwardingStatsBatches.uploadsTable, now = Date.now(); @@ -16,17 +16,17 @@ export default function forwardingStatsUploader(mpInstance) { mpInstance._Forwarders.setForwarderStatsQueue([]); } - for (var date in uploadsTable) { - (function(date) { + for (const date in uploadsTable) { + (function (date) { if (uploadsTable.hasOwnProperty(date)) { if (uploadsTable[date].uploading === false) { - var xhrCallback = function() { + const xhrCallback = function () { if (xhr.readyState === 4) { if (xhr.status === 200 || xhr.status === 202) { mpInstance.Logger.verbose( 'Successfully sent ' + xhr.statusText + - ' from server' + ' from server', ); delete uploadsTable[date]; } else if (xhr.status.toString()[0] === '4') { @@ -40,11 +40,11 @@ export default function forwardingStatsUploader(mpInstance) { }; var xhr = mpInstance._Helpers.createXHR(xhrCallback); - var forwardingStatsData = uploadsTable[date].data; + const forwardingStatsData = uploadsTable[date].data; uploadsTable[date].uploading = true; mpInstance._APIClient.sendBatchForwardingStatsToServer( forwardingStatsData, - xhr + xhr, ); } } diff --git a/src/helpers.js b/src/helpers.js index ec234dc55..7aa6e2381 100644 --- a/src/helpers.js +++ b/src/helpers.js @@ -4,11 +4,11 @@ import * as utils from './utils'; import Validators from './validators'; import KitFilterHelper from './kitFilterHelper'; -var StorageNames = Constants.StorageNames; +const StorageNames = Constants.StorageNames; export default function Helpers(mpInstance) { - var self = this; - this.canLog = function() { + const self = this; + this.canLog = function () { if ( mpInstance._Store.isEnabled && (mpInstance._Store.devToken || @@ -20,19 +20,19 @@ export default function Helpers(mpInstance) { return false; }; - this.getFeatureFlag = function(feature) { + this.getFeatureFlag = function (feature) { if (mpInstance._Store.SDKConfig.flags.hasOwnProperty(feature)) { return mpInstance._Store.SDKConfig.flags[feature]; } return null; }; - this.invokeCallback = function( + this.invokeCallback = function ( callback, code, body, mParticleUser, - previousMpid + previousMpid, ) { if (!callback) { mpInstance.Logger.warning('There is no callback provided'); @@ -42,18 +42,18 @@ export default function Helpers(mpInstance) { callback({ httpCode: code, body: body, - getUser: function() { + getUser: function () { if (mParticleUser) { return mParticleUser; } else { return mpInstance.Identity.getCurrentUser(); } }, - getPreviousUser: function() { + getPreviousUser: function () { if (!previousMpid) { - var users = mpInstance.Identity.getUsers(); - var mostRecentUser = users.shift(); - var currentUser = + const users = mpInstance.Identity.getUsers(); + let mostRecentUser = users.shift(); + const currentUser = mParticleUser || mpInstance.Identity.getCurrentUser(); if ( @@ -73,18 +73,18 @@ export default function Helpers(mpInstance) { } } catch (e) { mpInstance.Logger.error( - 'There was an error with your callback: ' + e + 'There was an error with your callback: ' + e, ); } }; - this.invokeAliasCallback = function(callback, code, message) { + this.invokeAliasCallback = function (callback, code, message) { if (!callback) { mpInstance.Logger.warning('There is no callback provided'); } try { if (self.Validators.isFunction(callback)) { - var callbackMessage = { + const callbackMessage = { httpCode: code, }; if (message) { @@ -94,14 +94,14 @@ export default function Helpers(mpInstance) { } } catch (e) { mpInstance.Logger.error( - 'There was an error with your callback: ' + e + 'There was an error with your callback: ' + e, ); } }; // https://go.mparticle.com/work/SQDSDKS-6047 // Standalone version of jQuery.extend, from https://github.com/dansdom/extend - this.extend = function() { + this.extend = function () { var options, name, src, @@ -116,14 +116,14 @@ export default function Helpers(mpInstance) { objectHelper = { hasOwn: Object.prototype.hasOwnProperty, class2type: {}, - type: function(obj) { + type: function (obj) { return obj == null ? String(obj) : objectHelper.class2type[ Object.prototype.toString.call(obj) ] || 'object'; }, - isPlainObject: function(obj) { + isPlainObject: function (obj) { if ( !obj || objectHelper.type(obj) !== 'object' || @@ -139,7 +139,7 @@ export default function Helpers(mpInstance) { !objectHelper.hasOwn.call(obj, 'constructor') && !objectHelper.hasOwn.call( obj.constructor.prototype, - 'isPrototypeOf' + 'isPrototypeOf', ) ) { return false; @@ -148,7 +148,7 @@ export default function Helpers(mpInstance) { return false; } - var key; + let key; for (key in obj) { } // eslint-disable-line no-empty @@ -158,13 +158,13 @@ export default function Helpers(mpInstance) { }, isArray: Array.isArray || - function(obj) { + function (obj) { return objectHelper.type(obj) === 'array'; }, - isFunction: function(obj) { + isFunction: function (obj) { return objectHelper.type(obj) === 'function'; }, - isWindow: function(obj) { + isWindow: function (obj) { return obj != null && obj == obj.window; }, }; // end of objectHelper @@ -233,12 +233,12 @@ export default function Helpers(mpInstance) { return target; }; - this.createServiceUrl = function(secureServiceUrl, devToken) { - var serviceScheme = + this.createServiceUrl = function (secureServiceUrl, devToken) { + const serviceScheme = window.mParticle && mpInstance._Store.SDKConfig.forceHttps ? 'https://' : window.location.protocol + '//'; - var baseUrl; + let baseUrl; if (mpInstance._Store.SDKConfig.forceHttps) { baseUrl = 'https://' + secureServiceUrl; } else { @@ -250,8 +250,8 @@ export default function Helpers(mpInstance) { return baseUrl; }; - this.createXHR = function(cb) { - var xhr; + this.createXHR = function (cb) { + let xhr; try { xhr = new window.XMLHttpRequest(); @@ -275,17 +275,16 @@ export default function Helpers(mpInstance) { return xhr; }; - this.filterUserIdentities = function(userIdentitiesObject, filterList) { - var filteredUserIdentities = []; + this.filterUserIdentities = function (userIdentitiesObject, filterList) { + const filteredUserIdentities = []; if (userIdentitiesObject && Object.keys(userIdentitiesObject).length) { - for (var userIdentityName in userIdentitiesObject) { + for (const userIdentityName in userIdentitiesObject) { if (userIdentitiesObject.hasOwnProperty(userIdentityName)) { - var userIdentityType = Types.IdentityType.getIdentityType( - userIdentityName - ); + const userIdentityType = + Types.IdentityType.getIdentityType(userIdentityName); if (!self.inArray(filterList, userIdentityType)) { - var identity = { + const identity = { Type: userIdentityType, Identity: userIdentitiesObject[userIdentityName], }; @@ -308,8 +307,8 @@ export default function Helpers(mpInstance) { KitFilterHelper.filterUserIdentities; this.filterUserAttributes = KitFilterHelper.filterUserAttributes; - this.isEventType = function(type) { - for (var prop in Types.EventType) { + this.isEventType = function (type) { + for (const prop in Types.EventType) { if (Types.EventType.hasOwnProperty(prop)) { if (Types.EventType[prop] === type) { return true; @@ -319,14 +318,14 @@ export default function Helpers(mpInstance) { return false; }; - this.sanitizeAttributes = function(attrs, name) { + this.sanitizeAttributes = function (attrs, name) { if (!attrs || !self.isObject(attrs)) { return null; } - var sanitizedAttrs = {}; + const sanitizedAttrs = {}; - for (var prop in attrs) { + for (const prop in attrs) { // Make sure that attribute values are not objects or arrays, which are not valid if ( attrs.hasOwnProperty(prop) && @@ -339,7 +338,7 @@ export default function Helpers(mpInstance) { name + "', the corresponding attribute value of '" + prop + - "' must be a string, number, boolean, or null." + "' must be a string, number, boolean, or null.", ); } } @@ -347,10 +346,10 @@ export default function Helpers(mpInstance) { return sanitizedAttrs; }; - this.isDelayedByIntegration = function( + this.isDelayedByIntegration = function ( delayedIntegrations, timeoutStart, - now + now, ) { if ( now - timeoutStart > @@ -358,7 +357,7 @@ export default function Helpers(mpInstance) { ) { return false; } - for (var integration in delayedIntegrations) { + for (const integration in delayedIntegrations) { if (delayedIntegrations[integration] === true) { return true; } else { @@ -368,7 +367,7 @@ export default function Helpers(mpInstance) { return false; }; - this.createMainStorageName = function(workspaceToken) { + this.createMainStorageName = function (workspaceToken) { if (workspaceToken) { return StorageNames.currentStorageName + '_' + workspaceToken; } else { @@ -376,7 +375,7 @@ export default function Helpers(mpInstance) { } }; - this.createProductStorageName = function(workspaceToken) { + this.createProductStorageName = function (workspaceToken) { if (workspaceToken) { return ( StorageNames.currentStorageProductsName + '_' + workspaceToken diff --git a/src/identity-utils.ts b/src/identity-utils.ts index f6f004221..beb677f1e 100644 --- a/src/identity-utils.ts +++ b/src/identity-utils.ts @@ -26,7 +26,7 @@ export type IParseCachedIdentityResponse = ( identityApiData: IdentityApiData, identityMethod: string, knownIdentities: IKnownIdentities, - fromCachedIdentity: boolean + fromCachedIdentity: boolean, ) => void; export interface IKnownIdentities extends UserIdentities { @@ -45,7 +45,7 @@ export const cacheOrClearIdCache = ( knownIdentities: IKnownIdentities, idCache: BaseVault>, identityResponse: IIdentityResponse, - parsingCachedResponse: boolean + parsingCachedResponse: boolean, ): void => { // when parsing a response that has already been cached, simply return instead of attempting another cache if (parsingCachedResponse) { @@ -63,7 +63,7 @@ export const cacheOrClearIdCache = ( knownIdentities, expireTimestamp, idCache, - identityResponse + identityResponse, ); break; case Modify: @@ -78,7 +78,7 @@ export const cacheIdentityRequest = ( identities: IKnownIdentities, expireTimestamp: number, idCache: IdentityCache, - identityResponse: IIdentityResponse + identityResponse: IIdentityResponse, ): void => { const { responseText, status } = identityResponse; const cache: Dictionary = @@ -105,18 +105,18 @@ export const cacheIdentityRequest = ( // we create an array, set the user identity at the index of the user identity type export const concatenateIdentities = ( method: IdentityAPIMethod, - userIdentities: IKnownIdentities + userIdentities: IKnownIdentities, ): string => { const DEVICE_APPLICATION_STAMP = 'device_application_stamp'; // set DAS first since it is not an official identity type - let cacheKey: string = `${method}:${DEVICE_APPLICATION_STAMP}=${userIdentities.device_application_stamp};`; + const cacheKey = `${method}:${DEVICE_APPLICATION_STAMP}=${userIdentities.device_application_stamp};`; const idLength: number = Object.keys(userIdentities).length; - let concatenatedIdentities: string = ''; + let concatenatedIdentities = ''; if (idLength) { - let userIDArray: Array = new Array(); + const userIDArray: Array = []; // create an array where each index is equal to the user identity type - for (let key in userIdentities) { + for (const key in userIdentities) { if (key === DEVICE_APPLICATION_STAMP) { continue; } else { @@ -131,7 +131,7 @@ export const concatenateIdentities = ( Types.IdentityType.getIdentityName(index); return `${prevValue}${idName}=${currentValue};`; }, - cacheKey + cacheKey, ); } @@ -141,7 +141,7 @@ export const concatenateIdentities = ( export const hasValidCachedIdentity = ( method: IdentityAPIMethod, proposedUserIdentities: IKnownIdentities, - idCache?: IdentityCache + idCache?: IdentityCache, ): boolean => { // There is an edge case where multiple identity calls are taking place // before identify fires, so there may not be a cache. See what happens when @@ -157,7 +157,7 @@ export const hasValidCachedIdentity = ( const cacheKey: string = concatenateIdentities( method, - proposedUserIdentities + proposedUserIdentities, ); const hashedKey = generateHash(cacheKey); @@ -181,11 +181,11 @@ export const hasValidCachedIdentity = ( export const getCachedIdentity = ( method: IdentityAPIMethod, proposedUserIdentities: IKnownIdentities, - idCache: IdentityCache + idCache: IdentityCache, ): IIdentityResponse | null => { const cacheKey: string = concatenateIdentities( method, - proposedUserIdentities + proposedUserIdentities, ); const hashedKey = generateHash(cacheKey); @@ -202,12 +202,12 @@ export const getCachedIdentity = ( // https://go.mparticle.com/work/SQDSDKS-6079 export const createKnownIdentities = ( identityApiData: IdentityApiData, - deviceId: string + deviceId: string, ): IKnownIdentities => { const identitiesResult: IKnownIdentities = {}; if (isObject(identityApiData?.userIdentities)) { - for (let identity in identityApiData.userIdentities) { + for (const identity in identityApiData.userIdentities) { identitiesResult[identity] = identityApiData.userIdentities[identity]; } @@ -218,7 +218,7 @@ export const createKnownIdentities = ( }; export const removeExpiredIdentityCacheDates = ( - idCache: BaseVault> + idCache: BaseVault>, ) => { const cache: Dictionary = idCache.retrieve() || ({} as Dictionary); @@ -226,7 +226,7 @@ export const removeExpiredIdentityCacheDates = ( const currentTime: number = new Date().getTime(); // Iterate over the cache and remove any key/value pairs that are expired - for (let key in cache) { + for (const key in cache) { if (cache[key].expireTimestamp < currentTime) { delete cache[key]; } @@ -242,13 +242,13 @@ export const tryCacheIdentity = ( mpid: string, callback: IdentityCallback, identityApiData: IdentityApiData, - identityMethod: IdentityAPIMethod + identityMethod: IdentityAPIMethod, ): boolean => { // https://go.mparticle.com/work/SQDSDKS-6095 const shouldReturnCachedIdentity = hasValidCachedIdentity( identityMethod, knownIdentities, - idCache + idCache, ); // If Identity is cached, then immediately parse the identity response @@ -256,7 +256,7 @@ export const tryCacheIdentity = ( const cachedIdentity = getCachedIdentity( identityMethod, knownIdentities, - idCache + idCache, ); parseIdentityResponse( @@ -266,7 +266,7 @@ export const tryCacheIdentity = ( identityApiData, identityMethod, knownIdentities, - true + true, ); return true; diff --git a/src/identity.interfaces.ts b/src/identity.interfaces.ts index 5b03c6cbf..6e2e0052d 100644 --- a/src/identity.interfaces.ts +++ b/src/identity.interfaces.ts @@ -77,7 +77,7 @@ export interface IIdentityAPIIdentityChangeData { export interface IIdentityRequest { combineUserIdentities( previousUIByName: UserIdentities, - newUIByName: UserIdentities + newUIByName: UserIdentities, ): UserIdentities; createIdentityRequest( identityApiData: IdentityApiData, @@ -86,7 +86,7 @@ export interface IIdentityRequest { sdkVersion: string, deviceId: string, context: string | null, - mpid: MPID + mpid: MPID, ): IIdentityAPIRequestData; createModifyIdentityRequest( currentUserIdentities: UserIdentities, @@ -94,16 +94,16 @@ export interface IIdentityRequest { platform: string, sdkVendor: string, sdkVersion: string, - context: string | null + context: string | null, ): IIdentityAPIModifyRequestData; createIdentityChanges( previousIdentities: UserIdentities, - newIdentitie: UserIdentities + newIdentitie: UserIdentities, ): IIdentityAPIIdentityChangeData; preProcessIdentityRequest( identityApiData: IdentityApiData, callback: IdentityCallback, - method: IdentityAPIMethod + method: IdentityAPIMethod, ): IdentityPreProcessResult; } @@ -128,30 +128,30 @@ export interface SDKIdentityApi { HTTPCodes: typeof HTTPCodes; identify?( identityApiData?: IdentityApiData, - callback?: IdentityCallback + callback?: IdentityCallback, ): void; login?( identityApiData?: IdentityApiData, - callback?: IdentityCallback + callback?: IdentityCallback, ): void; logout?( identityApiData?: IdentityApiData, - callback?: IdentityCallback + callback?: IdentityCallback, ): void; modify?( identityApiData?: IdentityApiData, - callback?: IdentityCallback + callback?: IdentityCallback, ): void; getCurrentUser?(): IMParticleUser; getUser?(mpid: string): IMParticleUser; getUsers?(): IMParticleUser[]; aliasUsers?( aliasRequest?: IAliasRequest, - callback?: IdentityCallback + callback?: IdentityCallback, ): void; createAliasRequest?( sourceUser: IMParticleUser, - destinationUser: IMParticleUser + destinationUser: IMParticleUser, ): IAliasRequest; } @@ -170,14 +170,14 @@ export interface IIdentity { previousUserAttributeValue: string, isNewAttribute: boolean, deleted: boolean, - user: IMParticleUser + user: IMParticleUser, ): IUserAttributeChangeEvent; createUserIdentityChange( identityType: SDKIdentityTypeEnum, newIdentity: string, oldIdentity: string, newCreatedThisBatch: boolean, - userInMemory: IMParticleUser + userInMemory: IMParticleUser, ): IUserIdentityChangeEvent; parseIdentityResponse( identityResponse: IIdentityResponse, @@ -186,7 +186,7 @@ export interface IIdentity { identityApiData: IdentityApiData, method: IdentityAPIMethod, knownIdentities: UserIdentities, - parsingCachedResponse: boolean + parsingCachedResponse: boolean, ): void; sendUserAttributeChangeEvent( attributeKey: string, @@ -194,13 +194,13 @@ export interface IIdentity { previousUserAttributeValue: string, isNewAttribute: boolean, deleted: boolean, - user: IMParticleUser + user: IMParticleUser, ): void; sendUserIdentityChangeEvent( newUserIdentities: UserIdentities, method: IdentityAPIMethod, mpid: MPID, - prevUserIdentities: UserIdentities + prevUserIdentities: UserIdentities, ): void; /** diff --git a/src/identity.js b/src/identity.js index 755a59f4a..222ef70cc 100644 --- a/src/identity.js +++ b/src/identity.js @@ -22,25 +22,30 @@ import { processReadyQueue } from './pre-init-utils'; export default function Identity(mpInstance) { const { getFeatureFlag, extend } = mpInstance._Helpers; - var self = this; + const self = this; this.idCache = null; this.audienceManager = null; // https://go.mparticle.com/work/SQDSDKS-6353 this.IdentityRequest = { - preProcessIdentityRequest: function(identityApiData, callback, method) { + preProcessIdentityRequest: function ( + identityApiData, + callback, + method, + ) { mpInstance.Logger.verbose( - Messages.InformationMessages.StartingLogEvent + ': ' + method + Messages.InformationMessages.StartingLogEvent + ': ' + method, ); - var identityValidationResult = mpInstance._Helpers.Validators.validateIdentities( - identityApiData, - method - ); + const identityValidationResult = + mpInstance._Helpers.Validators.validateIdentities( + identityApiData, + method, + ); if (!identityValidationResult.valid) { mpInstance.Logger.error( - 'ERROR: ' + identityValidationResult.error + 'ERROR: ' + identityValidationResult.error, ); return { valid: false, @@ -52,7 +57,7 @@ export default function Identity(mpInstance) { callback && !mpInstance._Helpers.Validators.isFunction(callback) ) { - var error = + const error = 'The optional callback must be a function. You tried entering a(n) ' + typeof callback; mpInstance.Logger.error(error); @@ -67,16 +72,16 @@ export default function Identity(mpInstance) { }; }, - createIdentityRequest: function( + createIdentityRequest: function ( identityApiData, platform, sdkVendor, sdkVersion, deviceId, context, - mpid + mpid, ) { - var APIRequest = { + const APIRequest = { client_sdk: { platform: platform, sdk_vendor: sdkVendor, @@ -91,20 +96,20 @@ export default function Identity(mpInstance) { previous_mpid: mpid || null, known_identities: createKnownIdentities( identityApiData, - deviceId + deviceId, ), }; return APIRequest; }, - createModifyIdentityRequest: function( + createModifyIdentityRequest: function ( currentUserIdentities, newUserIdentities, platform, sdkVendor, sdkVersion, - context + context, ) { return { client_sdk: { @@ -120,14 +125,14 @@ export default function Identity(mpInstance) { request_timestamp_ms: new Date().getTime(), identity_changes: this.createIdentityChanges( currentUserIdentities, - newUserIdentities + newUserIdentities, ), }; }, - createIdentityChanges: function(previousIdentities, newIdentities) { - var identityChanges = []; - var key; + createIdentityChanges: function (previousIdentities, newIdentities) { + const identityChanges = []; + let key; if ( newIdentities && isObject(newIdentities) && @@ -147,12 +152,12 @@ export default function Identity(mpInstance) { }, // takes 2 UI objects keyed by name, combines them, returns them keyed by type - combineUserIdentities: function(previousUIByName, newUIByName) { - var combinedUIByType = {}; - var combinedUIByName = extend({}, previousUIByName, newUIByName); + combineUserIdentities: function (previousUIByName, newUIByName) { + const combinedUIByType = {}; + const combinedUIByName = extend({}, previousUIByName, newUIByName); - for (var key in combinedUIByName) { - var type = Types.IdentityType.getIdentityType(key); + for (const key in combinedUIByName) { + const type = Types.IdentityType.getIdentityType(key); // this check removes anything that is not whitelisted as an identity type if (type !== false && type >= 0) { combinedUIByType[Types.IdentityType.getIdentityType(key)] = @@ -163,7 +168,7 @@ export default function Identity(mpInstance) { return combinedUIByType; }, - createAliasNetworkRequest: function(aliasRequest) { + createAliasNetworkRequest: function (aliasRequest) { return { request_id: mpInstance._Helpers.generateUniqueId(), request_type: 'alias', @@ -182,7 +187,7 @@ export default function Identity(mpInstance) { }; }, - convertAliasToNative: function(aliasRequest) { + convertAliasToNative: function (aliasRequest) { return { DestinationMpid: aliasRequest.destinationMpid, SourceMpid: aliasRequest.sourceMpid, @@ -191,10 +196,10 @@ export default function Identity(mpInstance) { }; }, - convertToNative: function(identityApiData) { - var nativeIdentityRequest = []; + convertToNative: function (identityApiData) { + const nativeIdentityRequest = []; if (identityApiData && identityApiData.userIdentities) { - for (var key in identityApiData.userIdentities) { + for (const key in identityApiData.userIdentities) { if (identityApiData.userIdentities.hasOwnProperty(key)) { nativeIdentityRequest.push({ Type: Types.IdentityType.getIdentityType(key), @@ -222,32 +227,34 @@ export default function Identity(mpInstance) { * @param {Object} identityApiData The identityApiData object as indicated [here](https://github.com/mParticle/mparticle-sdk-javascript/blob/master-v2/README.md#1-customize-the-sdk) * @param {Function} [callback] A callback function that is called when the identify request completes */ - identify: function(identityApiData, callback) { + identify: function (identityApiData, callback) { // https://go.mparticle.com/work/SQDSDKS-6337 - var mpid, + let mpid, currentUser = mpInstance.Identity.getCurrentUser(), - preProcessResult = mpInstance._Identity.IdentityRequest.preProcessIdentityRequest( - identityApiData, - callback, - Identify - ); + preProcessResult = + mpInstance._Identity.IdentityRequest.preProcessIdentityRequest( + identityApiData, + callback, + Identify, + ); if (currentUser) { mpid = currentUser.getMPID(); } if (preProcessResult.valid) { - var identityApiRequest = mpInstance._Identity.IdentityRequest.createIdentityRequest( - identityApiData, - Constants.platform, - Constants.sdkVendor, - Constants.sdkVersion, - mpInstance._Store.deviceId, - mpInstance._Store.context, - mpid - ); + const identityApiRequest = + mpInstance._Identity.IdentityRequest.createIdentityRequest( + identityApiData, + Constants.platform, + Constants.sdkVendor, + Constants.sdkVersion, + mpInstance._Store.deviceId, + mpInstance._Store.context, + mpid, + ); if ( mpInstance._Helpers.getFeatureFlag( - Constants.FeatureFlags.CacheIdentity + Constants.FeatureFlags.CacheIdentity, ) ) { const successfullyCachedIdentity = tryCacheIdentity( @@ -257,7 +264,7 @@ export default function Identity(mpInstance) { mpid, callback, identityApiData, - Identify + Identify, ); if (successfullyCachedIdentity) { @@ -271,14 +278,14 @@ export default function Identity(mpInstance) { Constants.NativeSdkPaths.Identify, JSON.stringify( mpInstance._Identity.IdentityRequest.convertToNative( - identityApiData - ) - ) + identityApiData, + ), + ), ); mpInstance._Helpers.invokeCallback( callback, HTTPCodes.nativeIdentityRequest, - 'Identify request sent to native sdk' + 'Identify request sent to native sdk', ); } else { mpInstance._IdentityAPIClient.sendIdentityRequest( @@ -288,24 +295,24 @@ export default function Identity(mpInstance) { identityApiData, self.parseIdentityResponse, mpid, - identityApiRequest.known_identities + identityApiRequest.known_identities, ); } } else { mpInstance._Helpers.invokeCallback( callback, HTTPCodes.loggingDisabledOrMissingAPIKey, - Messages.InformationMessages.AbandonLogEvent + Messages.InformationMessages.AbandonLogEvent, ); mpInstance.Logger.verbose( - Messages.InformationMessages.AbandonLogEvent + Messages.InformationMessages.AbandonLogEvent, ); } } else { mpInstance._Helpers.invokeCallback( callback, HTTPCodes.validationIssue, - preProcessResult.error + preProcessResult.error, ); mpInstance.Logger.verbose(preProcessResult); } @@ -316,30 +323,32 @@ export default function Identity(mpInstance) { * @param {Object} identityApiData The identityApiData object as indicated [here](https://github.com/mParticle/mparticle-sdk-javascript/blob/master-v2/README.md#1-customize-the-sdk) * @param {Function} [callback] A callback function that is called when the logout request completes */ - logout: function(identityApiData, callback) { + logout: function (identityApiData, callback) { // https://go.mparticle.com/work/SQDSDKS-6337 - var mpid, + let mpid, currentUser = mpInstance.Identity.getCurrentUser(), - preProcessResult = mpInstance._Identity.IdentityRequest.preProcessIdentityRequest( - identityApiData, - callback, - Logout - ); + preProcessResult = + mpInstance._Identity.IdentityRequest.preProcessIdentityRequest( + identityApiData, + callback, + Logout, + ); if (currentUser) { mpid = currentUser.getMPID(); } if (preProcessResult.valid) { - var evt, - identityApiRequest = mpInstance._Identity.IdentityRequest.createIdentityRequest( - identityApiData, - Constants.platform, - Constants.sdkVendor, - Constants.sdkVersion, - mpInstance._Store.deviceId, - mpInstance._Store.context, - mpid - ); + let evt, + identityApiRequest = + mpInstance._Identity.IdentityRequest.createIdentityRequest( + identityApiData, + Constants.platform, + Constants.sdkVendor, + Constants.sdkVersion, + mpInstance._Store.deviceId, + mpInstance._Store.context, + mpid, + ); if (mpInstance._Helpers.canLog()) { if (mpInstance._Store.webviewBridgeEnabled) { @@ -347,14 +356,14 @@ export default function Identity(mpInstance) { Constants.NativeSdkPaths.Logout, JSON.stringify( mpInstance._Identity.IdentityRequest.convertToNative( - identityApiData - ) - ) + identityApiData, + ), + ), ); mpInstance._Helpers.invokeCallback( callback, HTTPCodes.nativeIdentityRequest, - 'Logout request sent to native sdk' + 'Logout request sent to native sdk', ); } else { mpInstance._IdentityAPIClient.sendIdentityRequest( @@ -363,7 +372,7 @@ export default function Identity(mpInstance) { callback, identityApiData, self.parseIdentityResponse, - mpid + mpid, ); evt = mpInstance._ServerModel.createEventObject({ messageType: Types.MessageType.Profile, @@ -372,30 +381,30 @@ export default function Identity(mpInstance) { evt.ProfileMessageType = Types.ProfileMessageType.Logout; if (mpInstance._Store.activeForwarders.length) { - mpInstance._Store.activeForwarders.forEach(function( - forwarder - ) { - if (forwarder.logOut) { - forwarder.logOut(evt); - } - }); + mpInstance._Store.activeForwarders.forEach( + function (forwarder) { + if (forwarder.logOut) { + forwarder.logOut(evt); + } + }, + ); } } } else { mpInstance._Helpers.invokeCallback( callback, HTTPCodes.loggingDisabledOrMissingAPIKey, - Messages.InformationMessages.AbandonLogEvent + Messages.InformationMessages.AbandonLogEvent, ); mpInstance.Logger.verbose( - Messages.InformationMessages.AbandonLogEvent + Messages.InformationMessages.AbandonLogEvent, ); } } else { mpInstance._Helpers.invokeCallback( callback, HTTPCodes.validationIssue, - preProcessResult.error + preProcessResult.error, ); mpInstance.Logger.verbose(preProcessResult); } @@ -406,34 +415,36 @@ export default function Identity(mpInstance) { * @param {Object} identityApiData The identityApiData object as indicated [here](https://github.com/mParticle/mparticle-sdk-javascript/blob/master-v2/README.md#1-customize-the-sdk) * @param {Function} [callback] A callback function that is called when the login request completes */ - login: function(identityApiData, callback) { + login: function (identityApiData, callback) { // https://go.mparticle.com/work/SQDSDKS-6337 - var mpid, + let mpid, currentUser = mpInstance.Identity.getCurrentUser(), - preProcessResult = mpInstance._Identity.IdentityRequest.preProcessIdentityRequest( - identityApiData, - callback, - Login - ); + preProcessResult = + mpInstance._Identity.IdentityRequest.preProcessIdentityRequest( + identityApiData, + callback, + Login, + ); if (currentUser) { mpid = currentUser.getMPID(); } if (preProcessResult.valid) { - var identityApiRequest = mpInstance._Identity.IdentityRequest.createIdentityRequest( - identityApiData, - Constants.platform, - Constants.sdkVendor, - Constants.sdkVersion, - mpInstance._Store.deviceId, - mpInstance._Store.context, - mpid - ); + const identityApiRequest = + mpInstance._Identity.IdentityRequest.createIdentityRequest( + identityApiData, + Constants.platform, + Constants.sdkVendor, + Constants.sdkVersion, + mpInstance._Store.deviceId, + mpInstance._Store.context, + mpid, + ); if ( mpInstance._Helpers.getFeatureFlag( - Constants.FeatureFlags.CacheIdentity + Constants.FeatureFlags.CacheIdentity, ) ) { const successfullyCachedIdentity = tryCacheIdentity( @@ -443,7 +454,7 @@ export default function Identity(mpInstance) { mpid, callback, identityApiData, - Login + Login, ); if (successfullyCachedIdentity) { @@ -457,14 +468,14 @@ export default function Identity(mpInstance) { Constants.NativeSdkPaths.Login, JSON.stringify( mpInstance._Identity.IdentityRequest.convertToNative( - identityApiData - ) - ) + identityApiData, + ), + ), ); mpInstance._Helpers.invokeCallback( callback, HTTPCodes.nativeIdentityRequest, - 'Login request sent to native sdk' + 'Login request sent to native sdk', ); } else { mpInstance._IdentityAPIClient.sendIdentityRequest( @@ -474,24 +485,24 @@ export default function Identity(mpInstance) { identityApiData, self.parseIdentityResponse, mpid, - identityApiRequest.known_identities + identityApiRequest.known_identities, ); } } else { mpInstance._Helpers.invokeCallback( callback, HTTPCodes.loggingDisabledOrMissingAPIKey, - Messages.InformationMessages.AbandonLogEvent + Messages.InformationMessages.AbandonLogEvent, ); mpInstance.Logger.verbose( - Messages.InformationMessages.AbandonLogEvent + Messages.InformationMessages.AbandonLogEvent, ); } } else { mpInstance._Helpers.invokeCallback( callback, HTTPCodes.validationIssue, - preProcessResult.error + preProcessResult.error, ); mpInstance.Logger.verbose(preProcessResult); } @@ -502,33 +513,35 @@ export default function Identity(mpInstance) { * @param {Object} identityApiData The identityApiData object as indicated [here](https://github.com/mParticle/mparticle-sdk-javascript/blob/master-v2/README.md#1-customize-the-sdk) * @param {Function} [callback] A callback function that is called when the modify request completes */ - modify: function(identityApiData, callback) { + modify: function (identityApiData, callback) { // https://go.mparticle.com/work/SQDSDKS-6337 - var mpid, + let mpid, currentUser = mpInstance.Identity.getCurrentUser(), - preProcessResult = mpInstance._Identity.IdentityRequest.preProcessIdentityRequest( - identityApiData, - callback, - Modify - ); + preProcessResult = + mpInstance._Identity.IdentityRequest.preProcessIdentityRequest( + identityApiData, + callback, + Modify, + ); if (currentUser) { mpid = currentUser.getMPID(); } - var newUserIdentities = + const newUserIdentities = identityApiData && identityApiData.userIdentities ? identityApiData.userIdentities : {}; if (preProcessResult.valid) { - var identityApiRequest = mpInstance._Identity.IdentityRequest.createModifyIdentityRequest( - currentUser - ? currentUser.getUserIdentities().userIdentities - : {}, - newUserIdentities, - Constants.platform, - Constants.sdkVendor, - Constants.sdkVersion, - mpInstance._Store.context - ); + const identityApiRequest = + mpInstance._Identity.IdentityRequest.createModifyIdentityRequest( + currentUser + ? currentUser.getUserIdentities().userIdentities + : {}, + newUserIdentities, + Constants.platform, + Constants.sdkVendor, + Constants.sdkVersion, + mpInstance._Store.context, + ); if (mpInstance._Helpers.canLog()) { if (mpInstance._Store.webviewBridgeEnabled) { @@ -536,14 +549,14 @@ export default function Identity(mpInstance) { Constants.NativeSdkPaths.Modify, JSON.stringify( mpInstance._Identity.IdentityRequest.convertToNative( - identityApiData - ) - ) + identityApiData, + ), + ), ); mpInstance._Helpers.invokeCallback( callback, HTTPCodes.nativeIdentityRequest, - 'Modify request sent to native sdk' + 'Modify request sent to native sdk', ); } else { mpInstance._IdentityAPIClient.sendIdentityRequest( @@ -553,24 +566,24 @@ export default function Identity(mpInstance) { identityApiData, self.parseIdentityResponse, mpid, - identityApiRequest.known_identities + identityApiRequest.known_identities, ); } } else { mpInstance._Helpers.invokeCallback( callback, HTTPCodes.loggingDisabledOrMissingAPIKey, - Messages.InformationMessages.AbandonLogEvent + Messages.InformationMessages.AbandonLogEvent, ); mpInstance.Logger.verbose( - Messages.InformationMessages.AbandonLogEvent + Messages.InformationMessages.AbandonLogEvent, ); } } else { mpInstance._Helpers.invokeCallback( callback, HTTPCodes.validationIssue, - preProcessResult.error + preProcessResult.error, ); mpInstance.Logger.verbose(preProcessResult); } @@ -580,15 +593,15 @@ export default function Identity(mpInstance) { * @method getCurrentUser * @return {Object} the current user object */ - getCurrentUser: function() { - var mpid; + getCurrentUser: function () { + let mpid; if (mpInstance._Store) { mpid = mpInstance._Store.mpid; if (mpid) { mpid = mpInstance._Store.mpid.slice(); return self.mParticleUser( mpid, - mpInstance._Store.isLoggedIn + mpInstance._Store.isLoggedIn, ); } else if (mpInstance._Store.webviewBridgeEnabled) { return self.mParticleUser(); @@ -607,8 +620,8 @@ export default function Identity(mpInstance) { * @param {String} mpid of the desired user * @return {Object} the user for mpid */ - getUser: function(mpid) { - var persistence = mpInstance._Persistence.getPersistence(); + getUser: function (mpid) { + const persistence = mpInstance._Persistence.getPersistence(); if (persistence) { if ( persistence[mpid] && @@ -628,19 +641,19 @@ export default function Identity(mpInstance) { * @method getUsers * @return {Array} array of users */ - getUsers: function() { - var persistence = mpInstance._Persistence.getPersistence(); - var users = []; + getUsers: function () { + const persistence = mpInstance._Persistence.getPersistence(); + const users = []; if (persistence) { - for (var key in persistence) { + for (const key in persistence) { if (!Constants.SDKv2NonMPIDCookieKeys.hasOwnProperty(key)) { users.push(self.mParticleUser(key)); } } } - users.sort(function(a, b) { - var aLastSeen = a.getLastSeenTime() || 0; - var bLastSeen = b.getLastSeenTime() || 0; + users.sort(function (a, b) { + const aLastSeen = a.getLastSeenTime() || 0; + const bLastSeen = b.getLastSeenTime() || 0; if (aLastSeen > bLastSeen) { return -1; } else { @@ -656,8 +669,8 @@ export default function Identity(mpInstance) { * @param {Object} aliasRequest object representing an AliasRequest * @param {Function} [callback] A callback function that is called when the aliasUsers request completes */ - aliasUsers: function(aliasRequest, callback) { - var message; + aliasUsers: function (aliasRequest, callback) { + let message; if (!aliasRequest.destinationMpid || !aliasRequest.sourceMpid) { message = Messages.ValidationMessages.AliasMissingMpid; } @@ -675,7 +688,7 @@ export default function Identity(mpInstance) { mpInstance._Helpers.invokeAliasCallback( callback, HTTPCodes.validationIssue, - message + message, ); return; } @@ -685,14 +698,14 @@ export default function Identity(mpInstance) { Constants.NativeSdkPaths.Alias, JSON.stringify( mpInstance._Identity.IdentityRequest.convertAliasToNative( - aliasRequest - ) - ) + aliasRequest, + ), + ), ); mpInstance._Helpers.invokeAliasCallback( callback, HTTPCodes.nativeIdentityRequest, - 'Alias request sent to native sdk' + 'Alias request sent to native sdk', ); } else { mpInstance.Logger.verbose( @@ -700,24 +713,25 @@ export default function Identity(mpInstance) { ': ' + aliasRequest.sourceMpid + ' -> ' + - aliasRequest.destinationMpid - ); - var aliasRequestMessage = mpInstance._Identity.IdentityRequest.createAliasNetworkRequest( - aliasRequest + aliasRequest.destinationMpid, ); + const aliasRequestMessage = + mpInstance._Identity.IdentityRequest.createAliasNetworkRequest( + aliasRequest, + ); mpInstance._IdentityAPIClient.sendAliasRequest( aliasRequestMessage, - callback + callback, ); } } else { mpInstance._Helpers.invokeAliasCallback( callback, HTTPCodes.loggingDisabledOrMissingAPIKey, - Messages.InformationMessages.AbandonAliasUsers + Messages.InformationMessages.AbandonAliasUsers, ); mpInstance.Logger.verbose( - Messages.InformationMessages.AbandonAliasUsers + Messages.InformationMessages.AbandonAliasUsers, ); } }, @@ -737,17 +751,17 @@ export default function Identity(mpInstance) { after applying this adjustment it will be impossible to create an aliasRequest passes the aliasUsers() validation that the startTime must be less than the endTime */ - createAliasRequest: function(sourceUser, destinationUser) { + createAliasRequest: function (sourceUser, destinationUser) { try { if (!destinationUser || !sourceUser) { mpInstance.Logger.error( - "'destinationUser' and 'sourceUser' must both be present" + "'destinationUser' and 'sourceUser' must both be present", ); return null; } - var startTime = sourceUser.getFirstSeenTime(); + let startTime = sourceUser.getFirstSeenTime(); if (!startTime) { - mpInstance.Identity.getUsers().forEach(function(user) { + mpInstance.Identity.getUsers().forEach(function (user) { if ( user.getFirstSeenTime() && (!startTime || user.getFirstSeenTime() < startTime) @@ -756,14 +770,14 @@ export default function Identity(mpInstance) { } }); } - var minFirstSeenTimeMs = + const minFirstSeenTimeMs = new Date().getTime() - mpInstance._Store.SDKConfig.aliasMaxWindow * 24 * 60 * 60 * 1000; - var endTime = + const endTime = sourceUser.getLastSeenTime() || new Date().getTime(); //if the startTime is greater than $maxAliasWindow ago, adjust the startTime to the earliest allowed if (startTime < minFirstSeenTimeMs) { @@ -772,7 +786,7 @@ export default function Identity(mpInstance) { mpInstance.Logger.warning( 'Source User has not been seen in the last ' + mpInstance._Store.SDKConfig.maxAliasWindow + - ' days, Alias Request will likely fail' + ' days, Alias Request will likely fail', ); } } @@ -784,7 +798,7 @@ export default function Identity(mpInstance) { }; } catch (e) { mpInstance.Logger.error( - 'There was a problem with creating an alias request: ' + e + 'There was a problem with creating an alias request: ' + e, ); return null; } @@ -797,23 +811,23 @@ export default function Identity(mpInstance) { * Example: mParticle.Identity.getCurrentUser().getAllUserAttributes() * @class mParticle.Identity.getCurrentUser() */ - this.mParticleUser = function(mpid, isLoggedIn) { - var self = this; + this.mParticleUser = function (mpid, isLoggedIn) { + const self = this; return { /** * Get user identities for current user * @method getUserIdentities * @return {Object} an object with userIdentities as its key */ - getUserIdentities: function() { + getUserIdentities: function () { const currentUserIdentities = {}; const identities = mpInstance._Store.getUserIdentities(mpid); - for (var identityType in identities) { + for (const identityType in identities) { if (identities.hasOwnProperty(identityType)) { currentUserIdentities[ Types.IdentityType.getIdentityName( - mpInstance._Helpers.parseNumber(identityType) + mpInstance._Helpers.parseNumber(identityType), ) ] = identities[identityType]; } @@ -828,7 +842,7 @@ export default function Identity(mpInstance) { * @method getMPID * @return {String} the current user MPID as a string */ - getMPID: function() { + getMPID: function () { return mpid; }, /** @@ -836,7 +850,7 @@ export default function Identity(mpInstance) { * @method setUserTag * @param {String} tagName */ - setUserTag: function(tagName) { + setUserTag: function (tagName) { if (!mpInstance._Helpers.Validators.isValidKeyValue(tagName)) { mpInstance.Logger.error(Messages.ErrorMessages.BadKey); return; @@ -849,7 +863,7 @@ export default function Identity(mpInstance) { * @method removeUserTag * @param {String} tagName */ - removeUserTag: function(tagName) { + removeUserTag: function (tagName) { if (!mpInstance._Helpers.Validators.isValidKeyValue(tagName)) { mpInstance.Logger.error(Messages.ErrorMessages.BadKey); return; @@ -865,17 +879,17 @@ export default function Identity(mpInstance) { */ // https://go.mparticle.com/work/SQDSDKS-4576 // https://go.mparticle.com/work/SQDSDKS-6373 - setUserAttribute: function(key, newValue) { + setUserAttribute: function (key, newValue) { mpInstance._SessionManager.resetSessionTimer(); if (mpInstance._Helpers.canLog()) { if ( !mpInstance._Helpers.Validators.isValidAttributeValue( - newValue + newValue, ) ) { mpInstance.Logger.error( - Messages.ErrorMessages.BadAttribute + Messages.ErrorMessages.BadAttribute, ); return; } @@ -887,17 +901,18 @@ export default function Identity(mpInstance) { if (mpInstance._Store.webviewBridgeEnabled) { mpInstance._NativeSdkHelpers.sendToNative( Constants.NativeSdkPaths.SetUserAttribute, - JSON.stringify({ key: key, value: newValue }) + JSON.stringify({ key: key, value: newValue }), ); } else { const userAttributes = this.getAllUserAttributes(); let previousUserAttributeValue; let isNewAttribute; - const existingProp = mpInstance._Helpers.findKeyInObject( - userAttributes, - key - ); + const existingProp = + mpInstance._Helpers.findKeyInObject( + userAttributes, + key, + ); if (existingProp) { isNewAttribute = false; @@ -911,7 +926,7 @@ export default function Identity(mpInstance) { userAttributes[key] = newValue; mpInstance._Store.setUserAttributes( mpid, - userAttributes + userAttributes, ); self.sendUserAttributeChangeEvent( @@ -920,17 +935,17 @@ export default function Identity(mpInstance) { previousUserAttributeValue, isNewAttribute, false, - this + this, ); mpInstance._Forwarders.initForwarders( self.IdentityAPI.getCurrentUser().getUserIdentities(), - mpInstance._APIClient.prepareForwardingStats + mpInstance._APIClient.prepareForwardingStats, ); mpInstance._Forwarders.handleForwarderUserAttributes( 'setUserAttribute', key, - newValue + newValue, ); } } @@ -941,11 +956,11 @@ export default function Identity(mpInstance) { * @param {Object} user attribute object with keys of the attribute type, and value of the attribute value */ // https://go.mparticle.com/work/SQDSDKS-6373 - setUserAttributes: function(userAttributes) { + setUserAttributes: function (userAttributes) { mpInstance._SessionManager.resetSessionTimer(); if (isObject(userAttributes)) { if (mpInstance._Helpers.canLog()) { - for (var key in userAttributes) { + for (const key in userAttributes) { if (userAttributes.hasOwnProperty(key)) { this.setUserAttribute(key, userAttributes[key]); } @@ -954,7 +969,7 @@ export default function Identity(mpInstance) { } else { mpInstance.Logger.error( 'Must pass an object into setUserAttributes. You passed a ' + - typeof userAttributes + typeof userAttributes, ); } }, @@ -963,8 +978,8 @@ export default function Identity(mpInstance) { * @method removeUserAttribute * @param {String} key */ - removeUserAttribute: function(key) { - var cookies, userAttributes; + removeUserAttribute: function (key) { + let cookies, userAttributes; mpInstance._SessionManager.resetSessionTimer(); if (!mpInstance._Helpers.Validators.isValidKeyValue(key)) { @@ -975,23 +990,23 @@ export default function Identity(mpInstance) { if (mpInstance._Store.webviewBridgeEnabled) { mpInstance._NativeSdkHelpers.sendToNative( Constants.NativeSdkPaths.RemoveUserAttribute, - JSON.stringify({ key: key, value: null }) + JSON.stringify({ key: key, value: null }), ); } else { cookies = mpInstance._Persistence.getPersistence(); userAttributes = this.getAllUserAttributes(); - var existingProp = mpInstance._Helpers.findKeyInObject( + const existingProp = mpInstance._Helpers.findKeyInObject( userAttributes, - key + key, ); if (existingProp) { key = existingProp; } - var deletedUAKeyCopy = userAttributes[key] + const deletedUAKeyCopy = userAttributes[key] ? userAttributes[key].toString() : null; @@ -1008,17 +1023,17 @@ export default function Identity(mpInstance) { deletedUAKeyCopy, false, true, - this + this, ); mpInstance._Forwarders.initForwarders( self.IdentityAPI.getCurrentUser().getUserIdentities(), - mpInstance._APIClient.prepareForwardingStats + mpInstance._APIClient.prepareForwardingStats, ); mpInstance._Forwarders.handleForwarderUserAttributes( 'removeUserAttribute', key, - null + null, ); } }, @@ -1029,7 +1044,7 @@ export default function Identity(mpInstance) { * @param {Array} value an array of values */ // https://go.mparticle.com/work/SQDSDKS-6373 - setUserAttributeList: function(key, newValue) { + setUserAttributeList: function (key, newValue) { mpInstance._SessionManager.resetSessionTimer(); if (!mpInstance._Helpers.Validators.isValidKeyValue(key)) { @@ -1040,7 +1055,7 @@ export default function Identity(mpInstance) { if (!Array.isArray(newValue)) { mpInstance.Logger.error( 'The value you passed in to setUserAttributeList must be an array. You passed in a ' + - typeof value + typeof value, ); return; } @@ -1050,7 +1065,7 @@ export default function Identity(mpInstance) { if (mpInstance._Store.webviewBridgeEnabled) { mpInstance._NativeSdkHelpers.sendToNative( Constants.NativeSdkPaths.SetUserAttributeList, - JSON.stringify({ key: key, value: arrayCopy }) + JSON.stringify({ key: key, value: arrayCopy }), ); } else { const userAttributes = this.getAllUserAttributes(); @@ -1060,7 +1075,7 @@ export default function Identity(mpInstance) { const existingProp = mpInstance._Helpers.findKeyInObject( userAttributes, - key + key, ); if (existingProp) { @@ -1088,7 +1103,7 @@ export default function Identity(mpInstance) { ) { userAttributeChange = true; } else { - for (var i = 0; i < newValue.length; i++) { + for (let i = 0; i < newValue.length; i++) { if (previousUserAttributeValue[i] !== newValue[i]) { userAttributeChange = true; break; @@ -1103,18 +1118,18 @@ export default function Identity(mpInstance) { previousUserAttributeValue, isNewAttribute, false, - this + this, ); } mpInstance._Forwarders.initForwarders( self.IdentityAPI.getCurrentUser().getUserIdentities(), - mpInstance._APIClient.prepareForwardingStats + mpInstance._APIClient.prepareForwardingStats, ); mpInstance._Forwarders.handleForwarderUserAttributes( 'setUserAttribute', key, - arrayCopy + arrayCopy, ); } }, @@ -1122,29 +1137,29 @@ export default function Identity(mpInstance) { * Removes all user attributes * @method removeAllUserAttributes */ - removeAllUserAttributes: function() { - var userAttributes; + removeAllUserAttributes: function () { + let userAttributes; mpInstance._SessionManager.resetSessionTimer(); if (mpInstance._Store.webviewBridgeEnabled) { mpInstance._NativeSdkHelpers.sendToNative( - Constants.NativeSdkPaths.RemoveAllUserAttributes + Constants.NativeSdkPaths.RemoveAllUserAttributes, ); } else { userAttributes = this.getAllUserAttributes(); mpInstance._Forwarders.initForwarders( self.IdentityAPI.getCurrentUser().getUserIdentities(), - mpInstance._APIClient.prepareForwardingStats + mpInstance._APIClient.prepareForwardingStats, ); if (userAttributes) { - for (var prop in userAttributes) { + for (const prop in userAttributes) { if (userAttributes.hasOwnProperty(prop)) { mpInstance._Forwarders.handleForwarderUserAttributes( 'removeUserAttribute', prop, - null + null, ); } this.removeUserAttribute(prop); @@ -1157,12 +1172,12 @@ export default function Identity(mpInstance) { * @method getUserAttributesLists * @return {Object} an object of only keys with array values. Example: { attr1: [1, 2, 3], attr2: ['a', 'b', 'c'] } */ - getUserAttributesLists: function() { - var userAttributes, + getUserAttributesLists: function () { + let userAttributes, userAttributesLists = {}; userAttributes = this.getAllUserAttributes(); - for (var key in userAttributes) { + for (const key in userAttributes) { if ( userAttributes.hasOwnProperty(key) && Array.isArray(userAttributes[key]) @@ -1178,7 +1193,7 @@ export default function Identity(mpInstance) { * @method getAllUserAttributes * @return {Object} an object of all user attributes. Example: { attr1: 'value1', attr2: ['a', 'b', 'c'] } */ - getAllUserAttributes: function() { + getAllUserAttributes: function () { const { getUserAttributes } = mpInstance._Store; const userAttributesCopy = {}; const userAttributes = getUserAttributes(mpid); @@ -1187,9 +1202,8 @@ export default function Identity(mpInstance) { for (const prop in userAttributes) { if (userAttributes.hasOwnProperty(prop)) { if (Array.isArray(userAttributes[prop])) { - userAttributesCopy[prop] = userAttributes[ - prop - ].slice(); + userAttributesCopy[prop] = + userAttributes[prop].slice(); } else { userAttributesCopy[prop] = userAttributes[prop]; } @@ -1204,9 +1218,9 @@ export default function Identity(mpInstance) { * @method getCart * @return a cart object */ - getCart: function() { + getCart: function () { mpInstance.Logger.warning( - 'Deprecated function Identity.getCurrentUser().getCart() will be removed in future releases' + 'Deprecated function Identity.getCurrentUser().getCart() will be removed in future releases', ); return self.mParticleUserCart(mpid); }, @@ -1216,7 +1230,7 @@ export default function Identity(mpInstance) { * @method getConsentState * @return a ConsentState object */ - getConsentState: function() { + getConsentState: function () { return mpInstance._Store.getConsentState(mpid); }, /** @@ -1224,21 +1238,21 @@ export default function Identity(mpInstance) { * @method setConsentState * @param {Object} consent state */ - setConsentState: function(state) { + setConsentState: function (state) { mpInstance._Store.setConsentState(mpid, state); mpInstance._Forwarders.initForwarders( this.getUserIdentities().userIdentities, - mpInstance._APIClient.prepareForwardingStats + mpInstance._APIClient.prepareForwardingStats, ); mpInstance._CookieSyncManager.attemptCookieSync(this.getMPID()); }, - isLoggedIn: function() { + isLoggedIn: function () { return isLoggedIn; }, - getLastSeenTime: function() { + getLastSeenTime: function () { return mpInstance._Persistence.getLastSeenTime(mpid); }, - getFirstSeenTime: function() { + getFirstSeenTime: function () { return mpInstance._Persistence.getFirstSeenTime(mpid); }, /** @@ -1247,15 +1261,15 @@ export default function Identity(mpInstance) { * @param {Function} [callback] A callback function that is invoked when the user audience request completes */ // https://go.mparticle.com/work/SQDSDKS-6436 - getUserAudiences: function(callback) { + getUserAudiences: function (callback) { // user audience API is feature flagged if ( !mpInstance._Helpers.getFeatureFlag( - FeatureFlags.AudienceAPI + FeatureFlags.AudienceAPI, ) ) { mpInstance.Logger.error( - ErrorMessages.AudienceAPINotEnabled + ErrorMessages.AudienceAPINotEnabled, ); return; } @@ -1264,7 +1278,7 @@ export default function Identity(mpInstance) { mpInstance._Store.SDKConfig.userAudienceUrl, mpInstance._Store.devToken, mpInstance.Logger, - mpid + mpid, ); } @@ -1279,7 +1293,7 @@ export default function Identity(mpInstance) { * @class mParticle.Identity.getCurrentUser().getCart() * @deprecated */ - this.mParticleUserCart = function(mpid) { + this.mParticleUserCart = function (mpid) { return { /** * Adds a cart product to the user cart @@ -1288,43 +1302,42 @@ export default function Identity(mpInstance) { * @param {Boolean} [logEvent] a boolean to log adding of the cart object. If blank, no logging occurs. * @deprecated */ - add: function(product, logEvent) { + add: function (product, logEvent) { mpInstance.Logger.warning( - 'Deprecated function Identity.getCurrentUser().getCart().add() will be removed in future releases' + 'Deprecated function Identity.getCurrentUser().getCart().add() will be removed in future releases', ); - var allProducts, userProducts, arrayCopy; + let allProducts, userProducts, arrayCopy; arrayCopy = Array.isArray(product) ? product.slice() : [product]; - arrayCopy.forEach(function(product) { + arrayCopy.forEach(function (product) { product.Attributes = mpInstance._Helpers.sanitizeAttributes( - product.Attributes + product.Attributes, ); }); if (mpInstance._Store.webviewBridgeEnabled) { mpInstance._NativeSdkHelpers.sendToNative( Constants.NativeSdkPaths.AddToCart, - JSON.stringify(arrayCopy) + JSON.stringify(arrayCopy), ); } else { mpInstance._SessionManager.resetSessionTimer(); - userProducts = mpInstance._Persistence.getUserProductsFromLS( - mpid - ); + userProducts = + mpInstance._Persistence.getUserProductsFromLS(mpid); userProducts = userProducts.concat(arrayCopy); if (logEvent === true) { mpInstance._Events.logProductActionEvent( Types.ProductActionType.AddToCart, - arrayCopy + arrayCopy, ); } - var productsForMemory = {}; + const productsForMemory = {}; productsForMemory[mpid] = { cp: userProducts }; if ( @@ -1336,14 +1349,15 @@ export default function Identity(mpInstance) { userProducts.length + ' items. Only ' + mpInstance._Store.SDKConfig.maxProducts + - ' can currently be saved in cookies.' + ' can currently be saved in cookies.', ); userProducts = userProducts.slice( - -mpInstance._Store.SDKConfig.maxProducts + -mpInstance._Store.SDKConfig.maxProducts, ); } - allProducts = mpInstance._Persistence.getAllUserProductsFromLS(); + allProducts = + mpInstance._Persistence.getAllUserProductsFromLS(); allProducts[mpid].cp = userProducts; mpInstance._Persistence.setCartProducts(allProducts); @@ -1356,11 +1370,11 @@ export default function Identity(mpInstance) { * @param {Boolean} [logEvent] a boolean to log adding of the cart object. If blank, no logging occurs. * @deprecated */ - remove: function(product, logEvent) { + remove: function (product, logEvent) { mpInstance.Logger.warning( - 'Deprecated function Identity.getCurrentUser().getCart().remove() will be removed in future releases' + 'Deprecated function Identity.getCurrentUser().getCart().remove() will be removed in future releases', ); - var allProducts, + let allProducts, userProducts, cartIndex = -1, cartItem = null; @@ -1368,17 +1382,16 @@ export default function Identity(mpInstance) { if (mpInstance._Store.webviewBridgeEnabled) { mpInstance._NativeSdkHelpers.sendToNative( Constants.NativeSdkPaths.RemoveFromCart, - JSON.stringify(product) + JSON.stringify(product), ); } else { mpInstance._SessionManager.resetSessionTimer(); - userProducts = mpInstance._Persistence.getUserProductsFromLS( - mpid - ); + userProducts = + mpInstance._Persistence.getUserProductsFromLS(mpid); if (userProducts) { - userProducts.forEach(function(cartProduct, i) { + userProducts.forEach(function (cartProduct, i) { if (cartProduct.Sku === product.Sku) { cartIndex = i; cartItem = cartProduct; @@ -1391,16 +1404,17 @@ export default function Identity(mpInstance) { if (logEvent === true) { mpInstance._Events.logProductActionEvent( Types.ProductActionType.RemoveFromCart, - cartItem + cartItem, ); } } } - var productsForMemory = {}; + const productsForMemory = {}; productsForMemory[mpid] = { cp: userProducts }; - allProducts = mpInstance._Persistence.getAllUserProductsFromLS(); + allProducts = + mpInstance._Persistence.getAllUserProductsFromLS(); allProducts[mpid].cp = userProducts; @@ -1412,20 +1426,21 @@ export default function Identity(mpInstance) { * @method clear * @deprecated */ - clear: function() { + clear: function () { mpInstance.Logger.warning( - 'Deprecated function Identity.getCurrentUser().getCart().clear() will be removed in future releases' + 'Deprecated function Identity.getCurrentUser().getCart().clear() will be removed in future releases', ); - var allProducts; + let allProducts; if (mpInstance._Store.webviewBridgeEnabled) { mpInstance._NativeSdkHelpers.sendToNative( - Constants.NativeSdkPaths.ClearCart + Constants.NativeSdkPaths.ClearCart, ); } else { mpInstance._SessionManager.resetSessionTimer(); - allProducts = mpInstance._Persistence.getAllUserProductsFromLS(); + allProducts = + mpInstance._Persistence.getAllUserProductsFromLS(); if ( allProducts && @@ -1446,9 +1461,9 @@ export default function Identity(mpInstance) { * @return {Array} array of cart products * @deprecated */ - getCartProducts: function() { + getCartProducts: function () { mpInstance.Logger.warning( - 'Deprecated function Identity.getCurrentUser().getCart().getCartProducts() will be removed in future releases' + 'Deprecated function Identity.getCurrentUser().getCart().getCartProducts() will be removed in future releases', ); return mpInstance._Persistence.getCartProducts(mpid); }, @@ -1456,14 +1471,14 @@ export default function Identity(mpInstance) { }; // https://go.mparticle.com/work/SQDSDKS-6355 - this.parseIdentityResponse = function( + this.parseIdentityResponse = function ( identityResponse, previousMPID, callback, identityApiData, method, knownIdentities, - parsingCachedResponse + parsingCachedResponse, ) { const prevUser = mpInstance.Identity.getUser(previousMPID); const prevUserMPID = prevUser ? prevUser.getMPID() : null; @@ -1480,7 +1495,7 @@ export default function Identity(mpInstance) { try { mpInstance.Logger.verbose( - 'Parsing "' + method + '" identity response from server' + 'Parsing "' + method + '" identity response from server', ); identityApiResult = identityResponse.responseText ?? null; @@ -1499,12 +1514,12 @@ export default function Identity(mpInstance) { } mpidIsNotInCookies = !mpInstance._Persistence.getFirstSeenTime( - identityApiResult.mpid + identityApiResult.mpid, ); // https://go.mparticle.com/work/SQDSDKS-6329 mpInstance._Persistence.setFirstSeenTime( - identityApiResult.mpid + identityApiResult.mpid, ); } @@ -1515,12 +1530,12 @@ export default function Identity(mpInstance) { knownIdentities, self.idCache, identityResponse, - parsingCachedResponse + parsingCachedResponse, ); } const incomingUser = self.IdentityAPI.getUser( - identityApiResult.mpid + identityApiResult.mpid, ); const incomingUIByName = incomingUser @@ -1528,14 +1543,15 @@ export default function Identity(mpInstance) { : {}; if (method === Modify) { - newIdentitiesByType = mpInstance._Identity.IdentityRequest.combineUserIdentities( - previousUIByName, - identityApiData.userIdentities - ); + newIdentitiesByType = + mpInstance._Identity.IdentityRequest.combineUserIdentities( + previousUIByName, + identityApiData.userIdentities, + ); mpInstance._Store.setUserIdentities( previousMPID, - newIdentitiesByType + newIdentitiesByType, ); } else { // https://go.mparticle.com/work/SQDSDKS-6356 @@ -1549,46 +1565,47 @@ export default function Identity(mpInstance) { ) { // https://go.mparticle.com/work/SQDSDKS-6329 mpInstance._Persistence.setFirstSeenTime( - identityApiResult.mpid + identityApiResult.mpid, ); } mpInstance._Store.addMpidToSessionHistory( identityApiResult.mpid, - previousMPID + previousMPID, ); mpInstance._CookieSyncManager.attemptCookieSync( identityApiResult.mpid, - mpidIsNotInCookies + mpidIsNotInCookies, ); mpInstance._Persistence.swapCurrentUser( previousMPID, identityApiResult.mpid, - mpInstance._Store.currentSessionMPIDs + mpInstance._Store.currentSessionMPIDs, ); if ( identityApiData && !isEmpty(identityApiData.userIdentities) ) { - newIdentitiesByType = self.IdentityRequest.combineUserIdentities( - incomingUIByName, - identityApiData.userIdentities - ); + newIdentitiesByType = + self.IdentityRequest.combineUserIdentities( + incomingUIByName, + identityApiData.userIdentities, + ); } // https://go.mparticle.com/work/SQDSDKS-6041 mpInstance._Store.setUserIdentities( identityApiResult.mpid, - newIdentitiesByType + newIdentitiesByType, ); mpInstance._Persistence.update(); mpInstance._Store.syncPersistenceData(); mpInstance._Persistence.findPrevCookiesBasedOnUI( - identityApiData + identityApiData, ); // https://go.mparticle.com/work/SQDSDKS-6357 @@ -1603,7 +1620,7 @@ export default function Identity(mpInstance) { prevUser, newUser, identityApiData, - mpInstance.Logger + mpInstance.Logger, ); const persistence = mpInstance._Persistence.getPersistence(); @@ -1611,16 +1628,15 @@ export default function Identity(mpInstance) { if (newUser) { mpInstance._Persistence.storeDataInMemory( persistence, - newUser.getMPID() + newUser.getMPID(), ); self.reinitForwardersOnUserChange(prevUser, newUser); self.setForwarderCallbacks(newUser, method); } - const newIdentitiesByName = IdentityType.getNewIdentitiesByName( - newIdentitiesByType - ); + const newIdentitiesByName = + IdentityType.getNewIdentitiesByName(newIdentitiesByType); const uiByName = method === Modify ? previousUIByName : incomingUIByName; @@ -1630,7 +1646,7 @@ export default function Identity(mpInstance) { newIdentitiesByName, method, identityApiResult.mpid, - uiByName + uiByName, ); } @@ -1644,7 +1660,7 @@ export default function Identity(mpInstance) { callback, callbackCode, identityApiResult || null, - newUser + newUser, ); } else if ( identityApiResult && @@ -1655,7 +1671,7 @@ export default function Identity(mpInstance) { 'Received HTTP response code of ' + identityResponse.status + ' - ' + - identityApiResult.errors[0].message + identityApiResult.errors[0].message, ); } @@ -1668,32 +1684,33 @@ export default function Identity(mpInstance) { mpInstance._Helpers.invokeCallback( callback, identityResponse.status, - identityApiResult || null + identityApiResult || null, ); } mpInstance.Logger.error( - 'Error parsing JSON response from Identity server: ' + e + 'Error parsing JSON response from Identity server: ' + e, ); } mpInstance._Store.isInitialized = true; if (mpInstance._RoktManager.isReady()) { - mpInstance._RoktManager.currentUser = mpInstance.Identity.getCurrentUser(); + mpInstance._RoktManager.currentUser = + mpInstance.Identity.getCurrentUser(); } mpInstance._preInit.readyQueue = processReadyQueue( - mpInstance._preInit.readyQueue + mpInstance._preInit.readyQueue, ); }; // send a user identity change request on identify, login, logout, modify when any values change. // compare what identities exist vs what is previously was for the specific user if they were in memory before. // if it's the first time the user is logging in, send a user identity change request with - this.sendUserIdentityChangeEvent = function( + this.sendUserIdentityChangeEvent = function ( newUserIdentities, method, mpid, - prevUserIdentities + prevUserIdentities, ) { if (!mpid) { // https://go.mparticle.com/work/SQDSDKS-6501 @@ -1705,7 +1722,7 @@ export default function Identity(mpInstance) { // https://go.mparticle.com/work/SQDSDKS-6354 const currentUserInMemory = this.IdentityAPI.getUser(mpid); - for (var identityType in newUserIdentities) { + for (const identityType in newUserIdentities) { // Verifies a change actually happened if ( prevUserIdentities[identityType] !== @@ -1720,23 +1737,23 @@ export default function Identity(mpInstance) { newUserIdentities[identityType], prevUserIdentities[identityType], isNewUserIdentityType, - currentUserInMemory + currentUserInMemory, ); mpInstance._APIClient?.sendEventToServer( - userIdentityChangeEvent + userIdentityChangeEvent, ); } } }; - this.createUserIdentityChange = function( + this.createUserIdentityChange = function ( identityType, newIdentity, oldIdentity, isIdentityTypeNewToBatch, - userInMemory + userInMemory, ) { - var userIdentityChangeEvent; + let userIdentityChangeEvent; // https://go.mparticle.com/work/SQDSDKS-6439 userIdentityChangeEvent = mpInstance._ServerModel.createEventObject({ @@ -1759,71 +1776,72 @@ export default function Identity(mpInstance) { return userIdentityChangeEvent; }; - this.sendUserAttributeChangeEvent = function( + this.sendUserAttributeChangeEvent = function ( attributeKey, newUserAttributeValue, previousUserAttributeValue, isNewAttribute, deleted, - user + user, ) { - var userAttributeChangeEvent = self.createUserAttributeChange( + const userAttributeChangeEvent = self.createUserAttributeChange( attributeKey, newUserAttributeValue, previousUserAttributeValue, isNewAttribute, deleted, - user + user, ); if (userAttributeChangeEvent) { mpInstance._APIClient?.sendEventToServer(userAttributeChangeEvent); } }; - this.createUserAttributeChange = function( + this.createUserAttributeChange = function ( key, newValue, previousUserAttributeValue, isNewAttribute, deleted, - user + user, ) { if (typeof previousUserAttributeValue === 'undefined') { previousUserAttributeValue = null; } - var userAttributeChangeEvent; + let userAttributeChangeEvent; if (newValue !== previousUserAttributeValue) { // https://go.mparticle.com/work/SQDSDKS-6439 - userAttributeChangeEvent = mpInstance._ServerModel.createEventObject( - { - messageType: Types.MessageType.UserAttributeChange, - userAttributeChanges: { - UserAttributeName: key, - New: newValue, - Old: previousUserAttributeValue, - Deleted: deleted, - IsNewAttribute: isNewAttribute, + userAttributeChangeEvent = + mpInstance._ServerModel.createEventObject( + { + messageType: Types.MessageType.UserAttributeChange, + userAttributeChanges: { + UserAttributeName: key, + New: newValue, + Old: previousUserAttributeValue, + Deleted: deleted, + IsNewAttribute: isNewAttribute, + }, }, - }, - user - ); + user, + ); } return userAttributeChangeEvent; }; - this.reinitForwardersOnUserChange = function(prevUser, newUser) { + this.reinitForwardersOnUserChange = function (prevUser, newUser) { if (hasMPIDAndUserLoginChanged(prevUser, newUser)) { mpInstance._Forwarders?.initForwarders( newUser.getUserIdentities().userIdentities, - mpInstance._APIClient.prepareForwardingStats + mpInstance._APIClient.prepareForwardingStats, ); } }; - this.setForwarderCallbacks = function(user, method) { + this.setForwarderCallbacks = function (user, method) { // https://go.mparticle.com/work/SQDSDKS-6036 mpInstance._Forwarders?.setForwarderUserIdentities( - user.getUserIdentities().userIdentities + user.getUserIdentities().userIdentities, ); mpInstance._Forwarders?.setForwarderOnIdentityComplete(user, method); mpInstance._Forwarders?.setForwarderOnUserIdentified(user); @@ -1842,7 +1860,7 @@ function tryOnUserAlias(previousUser, newUser, identityApiData, logger) { identityApiData.onUserAlias(previousUser, newUser); } catch (e) { logger.error( - 'There was an error with your onUserAlias function - ' + e + 'There was an error with your onUserAlias function - ' + e, ); } } diff --git a/src/identityApiClient.ts b/src/identityApiClient.ts index 2b36a88de..ec2d8995b 100644 --- a/src/identityApiClient.ts +++ b/src/identityApiClient.ts @@ -1,4 +1,8 @@ -import Constants, { HTTP_ACCEPTED, HTTP_BAD_REQUEST, HTTP_OK } from './constants'; +import Constants, { + HTTP_ACCEPTED, + HTTP_BAD_REQUEST, + HTTP_OK, +} from './constants'; import { AsyncUploader, FetchUploader, @@ -14,11 +18,7 @@ import { IIdentity, IIdentityAPIRequestData, } from './identity.interfaces'; -import { - IdentityApiData, - MPID, - UserIdentities, -} from '@mparticle/web-sdk'; +import { IdentityApiData, MPID, UserIdentities } from '@mparticle/web-sdk'; import { IdentityCallback, IdentityResultBody, @@ -33,7 +33,7 @@ const { Modify } = IdentityMethods; export interface IIdentityApiClient { sendAliasRequest: ( aliasRequest: IAliasRequest, - aliasCallback: IAliasCallback + aliasCallback: IAliasCallback, ) => Promise; sendIdentityRequest: ( identityApiRequest: IIdentityAPIRequestData, @@ -42,12 +42,12 @@ export interface IIdentityApiClient { originalIdentityApiData: IdentityApiData, parseIdentityResponse: IIdentity['parseIdentityResponse'], mpid: MPID, - knownIdentities: UserIdentities + knownIdentities: UserIdentities, ) => Promise; getUploadUrl: (method: IdentityAPIMethod, mpid: MPID) => string; getIdentityResponseFromFetch: ( response: Response, - responseBody: IdentityResultBody + responseBody: IdentityResultBody, ) => IIdentityResponse; getIdentityResponseFromXHR: (response: XMLHttpRequest) => IIdentityResponse; } @@ -71,8 +71,8 @@ interface IdentityApiError { } interface IdentityApiErrorResponse { - Errors: IdentityApiError[], - ErrorCode: string, + Errors: IdentityApiError[]; + ErrorCode: string; StatusCode: valueof; RequestId: string; } @@ -82,11 +82,11 @@ interface IAliasErrorResponse extends IdentityApiError {} export default function IdentityAPIClient( this: IIdentityApiClient, - mpInstance: IMParticleWebSDKInstance + mpInstance: IMParticleWebSDKInstance, ) { - this.sendAliasRequest = async function( + this.sendAliasRequest = async function ( aliasRequest: IAliasRequest, - aliasCallback: IAliasCallback + aliasCallback: IAliasCallback, ) { const { verbose, error } = mpInstance.Logger; const { invokeAliasCallback } = mpInstance._Helpers; @@ -123,10 +123,12 @@ export default function IdentityAPIClient( case HTTP_ACCEPTED: case HTTP_OK: // https://go.mparticle.com/work/SQDSDKS-6670 - message = 'Received Alias Response from server: ' + JSON.stringify(response.status); + message = + 'Received Alias Response from server: ' + + JSON.stringify(response.status); break; - // Our Alias Request API will 400 if there is an issue with the request body (ie timestamps are too far + // Our Alias Request API will 400 if there is an issue with the request body (ie timestamps are too far // in the past or MPIDs don't exist). // A 400 will return an error in the response body and will go through the happy path to report the error case HTTP_BAD_REQUEST: @@ -141,14 +143,16 @@ export default function IdentityAPIClient( } else { // https://go.mparticle.com/work/SQDSDKS-6568 // XHRUploader returns the response as a string that we need to parse - const xhrResponse = (response as unknown) as XMLHttpRequest; - + const xhrResponse = + response as unknown as XMLHttpRequest; + aliasResponseBody = xhrResponse.responseText ? JSON.parse(xhrResponse.responseText) : ''; } - const errorResponse: IAliasErrorResponse = aliasResponseBody as unknown as IAliasErrorResponse; + const errorResponse: IAliasErrorResponse = + aliasResponseBody as unknown as IAliasErrorResponse; if (errorResponse?.message) { errorMessage = errorResponse.message; @@ -157,25 +161,27 @@ export default function IdentityAPIClient( message = 'Issue with sending Alias Request to mParticle Servers, received HTTP Code of ' + response.status; - + if (errorResponse?.code) { message += ' - ' + errorResponse.code; } break; - + // Any unhandled errors, such as 500 or 429, will be caught here as well default: { throw new Error('Received HTTP Code of ' + response.status); } - } verbose(message); invokeAliasCallback(aliasCallback, response.status, errorMessage); } catch (e) { const errorMessage = (e as Error).message || e.toString(); - error('Error sending alias request to mParticle servers. ' + errorMessage); + error( + 'Error sending alias request to mParticle servers. ' + + errorMessage, + ); invokeAliasCallback( aliasCallback, HTTPCodes.noHttpCoverage, @@ -184,14 +190,14 @@ export default function IdentityAPIClient( } }; - this.sendIdentityRequest = async function( + this.sendIdentityRequest = async function ( identityApiRequest: IIdentityAPIRequestData, method: IdentityAPIMethod, callback: IdentityCallback, originalIdentityApiData: IdentityApiData, parseIdentityResponse: IIdentity['parseIdentityResponse'], mpid: MPID, - knownIdentities: UserIdentities + knownIdentities: UserIdentities, ) { const { verbose, error } = mpInstance.Logger; const { invokeCallback } = mpInstance._Helpers; @@ -207,7 +213,7 @@ export default function IdentityAPIClient( invokeCallback( callback, HTTPCodes.activeIdentityRequest, - 'There is currently an Identity request processing. Please wait for this to return before requesting again' + 'There is currently an Identity request processing. Please wait for this to return before requesting again', ); return; } @@ -245,39 +251,45 @@ export default function IdentityAPIClient( // such as if the body is empty or one of the attributes is missing or malformed // A 400 will return an error in the response body and will go through the happy path to report the error case HTTP_BAD_REQUEST: - // FetchUploader returns the response as a JSON object that we have to await if (response.json) { // https://go.mparticle.com/work/SQDSDKS-6568 // FetchUploader returns the response as a JSON object that we have to await - const responseBody: IdentityResultBody = await response.json(); + const responseBody: IdentityResultBody = + await response.json(); identityResponse = this.getIdentityResponseFromFetch( response, - responseBody + responseBody, ); } else { identityResponse = this.getIdentityResponseFromXHR( - (response as unknown) as XMLHttpRequest + response as unknown as XMLHttpRequest, ); } if (identityResponse.status === HTTP_BAD_REQUEST) { - const errorResponse: IdentityApiErrorResponse = identityResponse.responseText as unknown as IdentityApiErrorResponse; - message = 'Issue with sending Identity Request to mParticle Servers, received HTTP Code of ' + identityResponse.status; + const errorResponse: IdentityApiErrorResponse = + identityResponse.responseText as unknown as IdentityApiErrorResponse; + message = + 'Issue with sending Identity Request to mParticle Servers, received HTTP Code of ' + + identityResponse.status; if (errorResponse?.Errors) { - const errorMessage = errorResponse.Errors.map((error) => error.message).join(', '); + const errorMessage = errorResponse.Errors.map( + (error) => error.message, + ).join(', '); message += ' - ' + errorMessage; } - } else { message = 'Received Identity Response from server: '; - message += JSON.stringify(identityResponse.responseText); + message += JSON.stringify( + identityResponse.responseText, + ); } break; - + // Our Identity API will return: // - 401 if the `x-mp-key` is incorrect or missing // - 403 if the there is a permission or account issue related to the `x-mp-key` @@ -297,25 +309,25 @@ export default function IdentityAPIClient( originalIdentityApiData, method, knownIdentities, - false + false, ); } catch (err) { mpInstance._Store.identityCallInFlight = false; - + const errorMessage = (err as Error).message || err.toString(); - error('Error sending identity request to servers' + ' - ' + errorMessage); - invokeCallback( - callback, - HTTPCodes.noHttpCoverage, - errorMessage, + error( + 'Error sending identity request to servers' + + ' - ' + + errorMessage, ); + invokeCallback(callback, HTTPCodes.noHttpCoverage, errorMessage); } }; this.getUploadUrl = (method: IdentityAPIMethod, mpid: MPID) => { const uploadServiceUrl: string = mpInstance._Helpers.createServiceUrl( - mpInstance._Store.SDKConfig.identityUrl + mpInstance._Store.SDKConfig.identityUrl, ); const uploadUrl: string = @@ -328,7 +340,7 @@ export default function IdentityAPIClient( this.getIdentityResponseFromFetch = ( response: Response, - responseBody: IdentityResultBody + responseBody: IdentityResultBody, ): IIdentityResponse => ({ status: response.status, responseText: responseBody, @@ -337,14 +349,14 @@ export default function IdentityAPIClient( }); this.getIdentityResponseFromXHR = ( - response: XMLHttpRequest + response: XMLHttpRequest, ): IIdentityResponse => ({ status: response.status, responseText: response.responseText ? JSON.parse(response.responseText) : {}, cacheMaxAge: parseNumber( - response.getResponseHeader(CACHE_HEADER) || '' + response.getResponseHeader(CACHE_HEADER) || '', ), expireTimestamp: 0, }); diff --git a/src/integrationCapture.ts b/src/integrationCapture.ts index 2ac7d8ca2..6e99725d4 100644 --- a/src/integrationCapture.ts +++ b/src/integrationCapture.ts @@ -29,17 +29,17 @@ export const facebookClickIdProcessor: IntegrationCaptureProcessorFunction = ( return ''; } - const urlSegments = url?.split('//') + const urlSegments = url?.split('//'); if (!urlSegments) { return ''; } const urlParts = urlSegments[1].split('/'); const domainParts = urlParts[0].split('.'); - let subdomainIndex: number = 1; + let subdomainIndex = 1; // The rules for subdomainIndex are for parsing the domain portion - // of the URL for cookies, but in this case we are parsing the URL + // of the URL for cookies, but in this case we are parsing the URL // itself, so we can ignore the use of 0 for 'com' if (domainParts.length >= 3) { subdomainIndex = 2; @@ -151,9 +151,15 @@ export default class IntegrationCapture { this.initialTimestamp = Date.now(); // Cache filtered mappings for faster access - this.filteredPartnerIdentityMappings = this.filterMappings(IntegrationOutputs.PARTNER_IDENTITIES); - this.filteredCustomFlagMappings = this.filterMappings(IntegrationOutputs.CUSTOM_FLAGS); - this.filteredIntegrationAttributeMappings = this.filterMappings(IntegrationOutputs.INTEGRATION_ATTRIBUTES); + this.filteredPartnerIdentityMappings = this.filterMappings( + IntegrationOutputs.PARTNER_IDENTITIES, + ); + this.filteredCustomFlagMappings = this.filterMappings( + IntegrationOutputs.CUSTOM_FLAGS, + ); + this.filteredIntegrationAttributeMappings = this.filterMappings( + IntegrationOutputs.INTEGRATION_ATTRIBUTES, + ); } /** @@ -197,7 +203,7 @@ export default class IntegrationCapture { ...this.clickIds, ...queryParams, ...localStorage, - ...cookies + ...cookies, }; } @@ -214,14 +220,18 @@ export default class IntegrationCapture { */ public captureQueryParams(): Dictionary { const queryParams = this.getQueryParams(); - return this.applyProcessors(queryParams, getHref(), this.initialTimestamp); + return this.applyProcessors( + queryParams, + getHref(), + this.initialTimestamp, + ); } /** * Captures local storage based on the integration ID mapping. */ public captureLocalStorage(): Dictionary { - let localStorageItems: Dictionary = {}; + const localStorageItems: Dictionary = {}; for (const key in integrationMapping) { const localStorageItem = localStorage.getItem(key); if (localStorageItem) { @@ -229,7 +239,11 @@ export default class IntegrationCapture { } } - return this.applyProcessors(localStorageItems, getHref(), this.initialTimestamp); + return this.applyProcessors( + localStorageItems, + getHref(), + this.initialTimestamp, + ); } /** @@ -253,7 +267,10 @@ export default class IntegrationCapture { * @returns {Dictionary} The partner identities. */ public getClickIdsAsPartnerIdentities(): Dictionary { - return this.getClickIds(this.clickIds, this.filteredPartnerIdentityMappings); + return this.getClickIds( + this.clickIds, + this.filteredPartnerIdentityMappings, + ); } /** @@ -274,9 +291,12 @@ export default class IntegrationCapture { for (const key in this.clickIds) { if (this.clickIds.hasOwnProperty(key)) { const value = this.clickIds[key]; - const mappingKey = this.filteredIntegrationAttributeMappings[key]?.mappedKey; + const mappingKey = + this.filteredIntegrationAttributeMappings[key]?.mappedKey; if (!isEmpty(mappingKey)) { - const moduleId = this.filteredIntegrationAttributeMappings[key]?.moduleId; + const moduleId = + this.filteredIntegrationAttributeMappings[key] + ?.moduleId; if (moduleId && !mappedClickIds[moduleId]) { mappedClickIds[moduleId] = { [mappingKey]: value }; } @@ -285,11 +305,10 @@ export default class IntegrationCapture { } return mappedClickIds; } - private getClickIds( clickIds: Dictionary, - mappingList: IntegrationIdMapping + mappingList: IntegrationIdMapping, ): Dictionary { const mappedClickIds: Dictionary = {}; @@ -313,7 +332,7 @@ export default class IntegrationCapture { private applyProcessors( clickIds: Dictionary, url?: string, - timestamp?: number + timestamp?: number, ): Dictionary { const processedClickIds: Dictionary = {}; @@ -321,7 +340,9 @@ export default class IntegrationCapture { if (clickIds.hasOwnProperty(key)) { const value = clickIds[key]; const processor = integrationMapping[key]?.processor; - processedClickIds[key] = processor ? processor(value, url, timestamp) : value; + processedClickIds[key] = processor + ? processor(value, url, timestamp) + : value; } } @@ -329,7 +350,7 @@ export default class IntegrationCapture { } private filterMappings( - outputType: valueof + outputType: valueof, ): IntegrationIdMapping { const filteredMappings: IntegrationIdMapping = {}; for (const key in integrationMapping) { diff --git a/src/kitBlocking.ts b/src/kitBlocking.ts index 17622faca..81c5621f5 100644 --- a/src/kitBlocking.ts +++ b/src/kitBlocking.ts @@ -1,7 +1,18 @@ import { convertEvent } from './sdkToEventsApiConverter'; -import { SDKEvent, MParticleWebSDK, KitBlockerDataPlan, SDKProduct } from './sdkRuntimeModels'; -import { BaseEvent, EventTypeEnum, CommerceEvent, ScreenViewEvent, CustomEvent } from '@mparticle/event-models'; -import Types from './types' +import { + SDKEvent, + MParticleWebSDK, + KitBlockerDataPlan, + SDKProduct, +} from './sdkRuntimeModels'; +import { + BaseEvent, + EventTypeEnum, + CommerceEvent, + ScreenViewEvent, + CustomEvent, +} from '@mparticle/event-models'; +import Types from './types'; import { DataPlanPoint } from '@mparticle/data-planning-models'; import { IMParticleWebSDKInstance } from './mp-instance'; @@ -10,15 +21,15 @@ import { IMParticleWebSDKInstance } from './mp-instance'; @mparticle/data-planning-models directly creates a build error. */ const DataPlanMatchType = { - ScreenView: "screen_view", - CustomEvent: "custom_event", - Commerce: "commerce", - UserAttributes: "user_attributes", - UserIdentities: "user_identities", - ProductAction: "product_action", - PromotionAction: "promotion_action", - ProductImpression: "product_impression" -} + ScreenView: 'screen_view', + CustomEvent: 'custom_event', + Commerce: 'commerce', + UserAttributes: 'user_attributes', + UserIdentities: 'user_identities', + ProductAction: 'product_action', + PromotionAction: 'promotion_action', + ProductImpression: 'product_impression', +}; /* inspiration from https://github.com/mParticle/data-planning-node/blob/master/src/data_planning/data_plan_event_validator.ts @@ -44,7 +55,10 @@ export default class KitBlocker { kitBlockingEnabled = false; mpInstance: IMParticleWebSDKInstance; - constructor(dataPlan: KitBlockerDataPlan, mpInstance: IMParticleWebSDKInstance) { + constructor( + dataPlan: KitBlockerDataPlan, + mpInstance: IMParticleWebSDKInstance, + ) { // if data plan is not requested, the data plan is {document: null} if (dataPlan && !dataPlan.document) { this.kitBlockingEnabled = false; @@ -57,40 +71,51 @@ export default class KitBlocker { this.blockUserAttributes = dataPlan?.document?.dtpn?.blok?.ua; this.blockUserIdentities = dataPlan?.document?.dtpn?.blok?.id; - const versionDocument = dataPlan?.document?.dtpn?.vers?.version_document; + const versionDocument = + dataPlan?.document?.dtpn?.vers?.version_document; const dataPoints = versionDocument?.data_points; if (versionDocument) { try { if (dataPoints?.length > 0) { - dataPoints.forEach(point => this.addToMatchLookups(point)); + dataPoints.forEach((point) => + this.addToMatchLookups(point), + ); } - } - catch(e) { - this.mpInstance.Logger.error('There was an issue with the data plan: ' + e); + } catch (e) { + this.mpInstance.Logger.error( + 'There was an issue with the data plan: ' + e, + ); } } } addToMatchLookups(point: DataPlanPoint) { if (!point.match || !point.validator) { - this.mpInstance.Logger.warning(`Data Plan Point is not valid' + ${point}`); + this.mpInstance.Logger.warning( + `Data Plan Point is not valid' + ${point}`, + ); return; } // match keys for non product custom attribute related data points let matchKey: string = this.generateMatchKey(point.match); - let properties: null | boolean | {[key: string]: true} = this.getPlannedProperties(point.match.type, point.validator) - + let properties: null | boolean | { [key: string]: true } = + this.getPlannedProperties(point.match.type, point.validator); + this.dataPlanMatchLookups[matchKey] = properties; // match keys for product custom attribute related data points - if (point?.match?.type === DataPlanMatchType.ProductImpression || + if ( + point?.match?.type === DataPlanMatchType.ProductImpression || point?.match?.type === DataPlanMatchType.ProductAction || - point?.match?.type === DataPlanMatchType.PromotionAction) { - + point?.match?.type === DataPlanMatchType.PromotionAction + ) { matchKey = this.generateProductAttributeMatchKey(point.match); - properties = this.getProductProperties(point.match.type, point.validator) - + properties = this.getProductProperties( + point.match.type, + point.validator, + ); + this.dataPlanMatchLookups[matchKey] = properties; } } @@ -117,15 +142,22 @@ export default class KitBlocker { case DataPlanMatchType.ProductAction: const productActionMatch = criteria; - return [match.type as string, productActionMatch.action].join(':'); + return [match.type as string, productActionMatch.action].join( + ':', + ); case DataPlanMatchType.PromotionAction: const promoActionMatch = criteria; - return [match.type as string, promoActionMatch.action].join(':'); + return [match.type as string, promoActionMatch.action].join( + ':', + ); case DataPlanMatchType.ProductImpression: const productImpressionActionMatch = criteria; - return [match.type as string, productImpressionActionMatch.action].join(':'); + return [ + match.type as string, + productImpressionActionMatch.action, + ].join(':'); case DataPlanMatchType.UserIdentities: case DataPlanMatchType.UserAttributes: @@ -142,11 +174,19 @@ export default class KitBlocker { switch (match.type) { case DataPlanMatchType.ProductAction: const productActionMatch = criteria; - return [match.type as string, productActionMatch.action, 'ProductAttributes'].join(':'); + return [ + match.type as string, + productActionMatch.action, + 'ProductAttributes', + ].join(':'); case DataPlanMatchType.PromotionAction: const promoActionMatch = criteria; - return [match.type as string, promoActionMatch.action, 'ProductAttributes'].join(':'); + return [ + match.type as string, + promoActionMatch.action, + 'ProductAttributes', + ].join(':'); case DataPlanMatchType.ProductImpression: return [match.type as string, 'ProductAttributes'].join(':'); @@ -156,7 +196,10 @@ export default class KitBlocker { } } - getPlannedProperties(type, validator): boolean | {[key: string]: true} | null { + getPlannedProperties( + type, + validator, + ): boolean | { [key: string]: true } | null { let customAttributes; let userAdditionalProperties; switch (type) { @@ -165,19 +208,29 @@ export default class KitBlocker { case DataPlanMatchType.ProductAction: case DataPlanMatchType.PromotionAction: case DataPlanMatchType.ProductImpression: - customAttributes = validator?.definition?.properties?.data?.properties?.custom_attributes; + customAttributes = + validator?.definition?.properties?.data?.properties + ?.custom_attributes; if (customAttributes) { - if (customAttributes.additionalProperties === true || customAttributes.additionalProperties === undefined) { + if ( + customAttributes.additionalProperties === true || + customAttributes.additionalProperties === undefined + ) { return true; } else { const properties = {}; - for (const property of Object.keys(customAttributes.properties)) { + for (const property of Object.keys( + customAttributes.properties, + )) { properties[property] = true; } return properties; } } else { - if (validator?.definition?.properties?.data?.additionalProperties === false) { + if ( + validator?.definition?.properties?.data + ?.additionalProperties === false + ) { return {}; } else { return true; @@ -185,12 +238,16 @@ export default class KitBlocker { } case DataPlanMatchType.UserAttributes: case DataPlanMatchType.UserIdentities: - userAdditionalProperties = validator?.definition?.additionalProperties; - if (userAdditionalProperties === true || userAdditionalProperties === undefined) { + userAdditionalProperties = + validator?.definition?.additionalProperties; + if ( + userAdditionalProperties === true || + userAdditionalProperties === undefined + ) { return true; } else { const properties = {}; - const userProperties = validator.definition.properties + const userProperties = validator.definition.properties; for (const property of Object.keys(userProperties)) { properties[property] = true; } @@ -201,15 +258,23 @@ export default class KitBlocker { } } - getProductProperties(type, validator): boolean | {[key: string]: true} | null { + getProductProperties( + type, + validator, + ): boolean | { [key: string]: true } | null { let productCustomAttributes; switch (type) { case DataPlanMatchType.ProductImpression: - productCustomAttributes = validator?.definition?.properties?.data?.properties?.product_impressions?.items?.properties?.products?.items?.properties?.custom_attributes + productCustomAttributes = + validator?.definition?.properties?.data?.properties + ?.product_impressions?.items?.properties?.products + ?.items?.properties?.custom_attributes; //product item attributes if (productCustomAttributes?.additionalProperties === false) { const properties = {}; - for (const property of Object.keys(productCustomAttributes?.properties)) { + for (const property of Object.keys( + productCustomAttributes?.properties, + )) { properties[property] = true; } return properties; @@ -217,12 +282,19 @@ export default class KitBlocker { return true; case DataPlanMatchType.ProductAction: case DataPlanMatchType.PromotionAction: - productCustomAttributes = validator?.definition?.properties?.data?.properties?.product_action?.properties?.products?.items?.properties?.custom_attributes + productCustomAttributes = + validator?.definition?.properties?.data?.properties + ?.product_action?.properties?.products?.items + ?.properties?.custom_attributes; //product item attributes if (productCustomAttributes) { - if (productCustomAttributes.additionalProperties === false) { + if ( + productCustomAttributes.additionalProperties === false + ) { const properties = {}; - for (const property of Object.keys(productCustomAttributes?.properties)) { + for (const property of Object.keys( + productCustomAttributes?.properties, + )) { properties[property] = true; } return properties; @@ -318,28 +390,28 @@ export default class KitBlocker { then product attributes if applicable, then user attributes, then the user identities */ - try { - if (event) { - event = this.transformEventAndEventAttributes(event) - } - - if (event && event.EventDataType === Types.MessageType.Commerce) { - event = this.transformProductAttributes(event); - } - - if (event) { - event = this.transformUserAttributes(event); - event = this.transformUserIdentities(event); - } - - return event; - } catch(e) { - return event; - } + try { + if (event) { + event = this.transformEventAndEventAttributes(event); + } + + if (event && event.EventDataType === Types.MessageType.Commerce) { + event = this.transformProductAttributes(event); + } + + if (event) { + event = this.transformUserAttributes(event); + event = this.transformUserIdentities(event); + } + + return event; + } catch (e) { + return event; + } } transformEventAndEventAttributes(event: SDKEvent): SDKEvent { - const clonedEvent = {...event}; + const clonedEvent = { ...event }; const baseEvent: BaseEvent = convertEvent(clonedEvent); const matchKey: string = this.getMatchKey(baseEvent); const matchedEvent = this.dataPlanMatchLookups[matchKey]; @@ -379,13 +451,16 @@ export default class KitBlocker { } transformProductAttributes(event: SDKEvent): SDKEvent { - const clonedEvent = {...event}; + const clonedEvent = { ...event }; const baseEvent: BaseEvent = convertEvent(clonedEvent); const matchKey: string = this.getProductAttributeMatchKey(baseEvent); const matchedEvent = this.dataPlanMatchLookups[matchKey]; - function removeAttribute(matchedEvent: { [key: string]: string }, productList: SDKProduct[]): void { - productList.forEach(product => { + function removeAttribute( + matchedEvent: { [key: string]: string }, + productList: SDKProduct[], + ): void { + productList.forEach((product) => { for (const productKey of Object.keys(product.Attributes)) { if (!matchedEvent[productKey]) { delete product.Attributes[productKey]; @@ -416,17 +491,25 @@ export default class KitBlocker { if (matchedEvent) { switch (event.EventCategory) { case Types.CommerceEventType.ProductImpression: - clonedEvent.ProductImpressions.forEach(impression=> { - removeAttribute(matchedEvent, impression?.ProductList) + clonedEvent.ProductImpressions.forEach((impression) => { + removeAttribute( + matchedEvent, + impression?.ProductList, + ); }); break; case Types.CommerceEventType.ProductPurchase: - removeAttribute(matchedEvent, clonedEvent.ProductAction?.ProductList) + removeAttribute( + matchedEvent, + clonedEvent.ProductAction?.ProductList, + ); break; - default: - this.mpInstance.Logger.warning('Product Not Supported ') + default: + this.mpInstance.Logger.warning( + 'Product Not Supported ', + ); } - + return clonedEvent; } else { return clonedEvent; @@ -437,39 +520,40 @@ export default class KitBlocker { } transformUserAttributes(event: SDKEvent) { - const clonedEvent = {...event}; + const clonedEvent = { ...event }; if (this.blockUserAttributes) { /* If the user attribute is not found in the matchedAttributes then remove it from event.UserAttributes as it is blocked */ - const matchedAttributes = this.dataPlanMatchLookups['user_attributes']; + const matchedAttributes = + this.dataPlanMatchLookups['user_attributes']; if (this.mpInstance._Helpers.isObject(matchedAttributes)) { for (const ua of Object.keys(clonedEvent.UserAttributes)) { if (!matchedAttributes[ua]) { - delete clonedEvent.UserAttributes[ua] + delete clonedEvent.UserAttributes[ua]; } } } } - - return clonedEvent + + return clonedEvent; } isAttributeKeyBlocked(key: string) { /* used when an attribute is added to the user */ if (!this.blockUserAttributes) { - return false + return false; } const matchedAttributes = this.dataPlanMatchLookups['user_attributes']; - // When additionalProperties is set to true, matchedAttributes + // When additionalProperties is set to true, matchedAttributes // will be a boolean, otherwise it will return an object if (typeof matchedAttributes === 'boolean' && matchedAttributes) { - return false + return false; } - if (typeof matchedAttributes === "object") { + if (typeof matchedAttributes === 'object') { if (matchedAttributes[key] === true) { return false; } else { @@ -485,42 +569,44 @@ export default class KitBlocker { isIdentityBlocked(key: string) { /* used when an attribute is added to the user */ if (!this.blockUserIdentities) { - return false + return false; } if (this.blockUserIdentities) { - const matchedIdentities = this.dataPlanMatchLookups['user_identities']; + const matchedIdentities = + this.dataPlanMatchLookups['user_identities']; if (matchedIdentities === true) { - return false + return false; } if (!matchedIdentities[key]) { - return true + return true; } } else { - return false + return false; } - return false + return false; } transformUserIdentities(event: SDKEvent) { - /* + /* If the user identity is not found in matchedIdentities then remove it from event.UserIdentities as it is blocked. event.UserIdentities is of type [{Identity: 'id1', Type: 7}, ...] and so to compare properly in matchedIdentities, each Type needs to be converted to an identityName */ - const clonedEvent = {...event}; + const clonedEvent = { ...event }; if (this.blockUserIdentities) { - const matchedIdentities = this.dataPlanMatchLookups['user_identities']; + const matchedIdentities = + this.dataPlanMatchLookups['user_identities']; if (this.mpInstance._Helpers.isObject(matchedIdentities)) { if (clonedEvent?.UserIdentities?.length) { clonedEvent.UserIdentities.forEach((uiByType, i) => { const identityName = Types.IdentityType.getIdentityName( - this.mpInstance._Helpers.parseNumber(uiByType.Type) + this.mpInstance._Helpers.parseNumber(uiByType.Type), ); - + if (!matchedIdentities[identityName]) { clonedEvent.UserIdentities.splice(i, 1); } @@ -530,4 +616,4 @@ export default class KitBlocker { } return clonedEvent; } -} \ No newline at end of file +} diff --git a/src/kitFilterHelper.ts b/src/kitFilterHelper.ts index feaece781..3de478d7a 100644 --- a/src/kitFilterHelper.ts +++ b/src/kitFilterHelper.ts @@ -1,33 +1,47 @@ -import { Dictionary, generateHash, inArray, valueof, filterDictionaryWithHash } from "./utils"; +import { + Dictionary, + generateHash, + inArray, + valueof, + filterDictionaryWithHash, +} from './utils'; // TODO: https://mparticle-eng.atlassian.net/browse/SQDSDKS-5381 -import { EventType, IdentityType } from "./types"; +import { EventType, IdentityType } from './types'; export default class KitFilterHelper { static hashEventType(eventType: valueof): number { return generateHash(eventType as unknown as string); - }; + } - static hashEventName(eventName: string, eventType: valueof): number { + static hashEventName( + eventName: string, + eventType: valueof, + ): number { return generateHash(eventType + eventName); - }; + } - static hashEventAttributeKey(eventType: valueof, eventName: string, customAttributeName: string): number { + static hashEventAttributeKey( + eventType: valueof, + eventName: string, + customAttributeName: string, + ): number { return generateHash(eventType + eventName + customAttributeName); } - + static hashUserAttribute(userAttributeKey: string): number { return generateHash(userAttributeKey); } // User Identities are not actually hashed, this method is named this way to // be consistent with the filter class. UserIdentityType is also a number - static hashUserIdentity(userIdentity: typeof IdentityType): typeof IdentityType { + static hashUserIdentity( + userIdentity: typeof IdentityType, + ): typeof IdentityType { return userIdentity; } - static hashConsentPurpose(prefix: string, purpose: string){ - return generateHash(prefix + purpose) - + static hashConsentPurpose(prefix: string, purpose: string) { + return generateHash(prefix + purpose); } // The methods below are for conditional forwarding, a type of filter @@ -40,23 +54,41 @@ export default class KitFilterHelper { return generateHash(attribute).toString(); } - static hashConsentPurposeConditionalForwarding(prefix: string, purpose: string): string { + static hashConsentPurposeConditionalForwarding( + prefix: string, + purpose: string, + ): string { return this.hashConsentPurpose(prefix, purpose).toString(); } - static readonly filterUserAttributes = (userAttributes: Dictionary, filterList: number[]): Dictionary => { - return filterDictionaryWithHash(userAttributes, filterList, (key: string) => this.hashUserAttribute(key)); - } + static readonly filterUserAttributes = ( + userAttributes: Dictionary, + filterList: number[], + ): Dictionary => { + return filterDictionaryWithHash( + userAttributes, + filterList, + (key: string) => this.hashUserAttribute(key), + ); + }; - static readonly filterUserIdentities = (userIdentities: Dictionary, filterList: number[]): Dictionary => { - return filterDictionaryWithHash(userIdentities, filterList, (key: string) => this.hashUserIdentity( - IdentityType.getIdentityType(key) - )); - } - - static readonly isFilteredUserAttribute = (userAttributeKey: string, filterList: number[]): boolean => { + static readonly filterUserIdentities = ( + userIdentities: Dictionary, + filterList: number[], + ): Dictionary => { + return filterDictionaryWithHash( + userIdentities, + filterList, + (key: string) => + this.hashUserIdentity(IdentityType.getIdentityType(key)), + ); + }; + + static readonly isFilteredUserAttribute = ( + userAttributeKey: string, + filterList: number[], + ): boolean => { const hashedUserAttribute = this.hashUserAttribute(userAttributeKey); return filterList && inArray(filterList, hashedUserAttribute); - } - -} \ No newline at end of file + }; +} diff --git a/src/logger.js b/src/logger.js index a88d13321..3b906f856 100644 --- a/src/logger.js +++ b/src/logger.js @@ -1,13 +1,13 @@ function Logger(config) { - var self = this; - var logLevel = config.logLevel || 'warning'; + const self = this; + let logLevel = config.logLevel || 'warning'; if (config.hasOwnProperty('logger')) { this.logger = config.logger; } else { this.logger = new ConsoleLogger(); } - this.verbose = function(msg) { + this.verbose = function (msg) { if (logLevel !== 'none') { if (self.logger.verbose && logLevel === 'verbose') { self.logger.verbose(msg); @@ -15,7 +15,7 @@ function Logger(config) { } }; - this.warning = function(msg) { + this.warning = function (msg) { if (logLevel !== 'none') { if ( self.logger.warning && @@ -26,7 +26,7 @@ function Logger(config) { } }; - this.error = function(msg) { + this.error = function (msg) { if (logLevel !== 'none') { if (self.logger.error) { self.logger.error(msg); @@ -34,24 +34,24 @@ function Logger(config) { } }; - this.setLogLevel = function(newLogLevel) { + this.setLogLevel = function (newLogLevel) { logLevel = newLogLevel; }; } function ConsoleLogger() { - this.verbose = function(msg) { + this.verbose = function (msg) { if (console && console.info) { console.info(msg); } }; - this.error = function(msg) { + this.error = function (msg) { if (console && console.error) { console.error(msg); } }; - this.warning = function(msg) { + this.warning = function (msg) { if (console && console.warn) { console.warn(msg); } diff --git a/src/mockBatchCreator.ts b/src/mockBatchCreator.ts index d3211843a..5ef2653c5 100644 --- a/src/mockBatchCreator.ts +++ b/src/mockBatchCreator.ts @@ -6,23 +6,26 @@ import { convertEvents } from './sdkToEventsApiConverter'; import { Batch } from '@mparticle/event-models'; import { IMParticleWebSDKInstance } from './mp-instance'; -const mockFunction = function() { +const mockFunction = function () { return null; }; export default class _BatchValidator { private getMPInstance() { - return ({ + return { // Certain Helper, Store, and Identity properties need to be mocked to be used in the `returnBatch` method _Helpers: { - sanitizeAttributes: (window.mParticle.getInstance() as unknown as IMParticleWebSDKInstance)._Helpers - .sanitizeAttributes, - generateHash: function() { + sanitizeAttributes: ( + window.mParticle.getInstance() as unknown as IMParticleWebSDKInstance + )._Helpers.sanitizeAttributes, + generateHash: function () { return 'mockHash'; }, - generateUniqueId: function() { + generateUniqueId: function () { return 'mockId'; }, - extend: (window.mParticle.getInstance() as unknown as IMParticleWebSDKInstance)._Helpers.extend, + extend: ( + window.mParticle.getInstance() as unknown as IMParticleWebSDKInstance + )._Helpers.extend, createServiceUrl: mockFunction, parseNumber: mockFunction, isObject: mockFunction, @@ -31,7 +34,7 @@ export default class _BatchValidator { _resetForTests: mockFunction, _APIClient: null, _timeOnSiteTimer: { - getTimeInForeground: mockFunction + getTimeInForeground: mockFunction, }, MPSideloadedKit: null, _Consent: null, @@ -120,7 +123,7 @@ export default class _BatchValidator { logLevel: 'none', setPosition: mockFunction, upload: mockFunction, - } as unknown) as IMParticleWebSDKInstance; + } as unknown as IMParticleWebSDKInstance; } private createSDKEventFunction(event): SDKEvent { @@ -131,7 +134,7 @@ export default class _BatchValidator { const mpInstance = this.getMPInstance(); const sdkEvents: SDKEvent[] = Array.isArray(events) - ? events.map(event => this.createSDKEventFunction(event)) + ? events.map((event) => this.createSDKEventFunction(event)) : [this.createSDKEventFunction(events)]; const batch: Batch = convertEvents('0', sdkEvents, mpInstance as any); diff --git a/src/mp-instance.ts b/src/mp-instance.ts index cd5ce0ad7..e07fad32b 100644 --- a/src/mp-instance.ts +++ b/src/mp-instance.ts @@ -16,7 +16,14 @@ // Uses portions of code from jQuery // jQuery v1.10.2 | (c) 2005, 2013 jQuery Foundation, Inc. | jquery.org/license -import { EventType, IdentityType, CommerceEventType, PromotionActionType, ProductActionType, MessageType } from './types'; +import { + EventType, + IdentityType, + CommerceEventType, + PromotionActionType, + ProductActionType, + MessageType, +} from './types'; import Constants from './constants'; import APIClient, { IAPIClient } from './apiClient'; import Helpers from './helpers'; @@ -88,7 +95,7 @@ export interface IMParticleWebSDKInstance extends MParticleWebSDK { _Store: IStore; _instanceName: string; _preInit: IPreInit; - _timeOnSiteTimer: ForegroundTimer; + _timeOnSiteTimer: ForegroundTimer; } const { Messages, HTTPCodes, FeatureFlags } = Constants; @@ -108,7 +115,10 @@ const { StartingInitialization } = Messages.InformationMessages; * @class mParticle & mParticleInstance */ -export default function mParticleInstance(this: IMParticleWebSDKInstance, instanceName: string) { +export default function mParticleInstance( + this: IMParticleWebSDKInstance, + instanceName: string, +) { const self = this; // These classes are for internal use only. Not documented for public consumption this._instanceName = instanceName; @@ -138,7 +148,6 @@ export default function mParticleInstance(this: IMParticleWebSDKInstance, instan this.PromotionType = PromotionActionType; this.ProductActionType = ProductActionType; - this._Identity = new Identity(this); this.Identity = this._Identity.IdentityAPI; this.generateHash = this._Helpers.generateHash; @@ -154,10 +163,10 @@ export default function mParticleInstance(this: IMParticleWebSDKInstance, instan } } } - this.init = function(apiKey, config) { + this.init = function (apiKey, config) { if (!config) { console.warn( - 'You did not pass a config object to init(). mParticle will not initialize properly' + 'You did not pass a config object to init(). mParticle will not initialize properly', ); } @@ -174,14 +183,14 @@ export default function mParticleInstance(this: IMParticleWebSDKInstance, instan const configApiClient = new ConfigAPIClient( apiKey, config, - this + this, ); - configApiClient.getSDKConfiguration().then(result => { + configApiClient.getSDKConfiguration().then((result) => { const mergedConfig = this._Helpers.extend( {}, config, - result + result, ); completeSDKInitialization(apiKey, mergedConfig, this); @@ -191,7 +200,7 @@ export default function mParticleInstance(this: IMParticleWebSDKInstance, instan } } else { console.error( - 'No config available on the window, please pass a config object to mParticle.init()' + 'No config available on the window, please pass a config object to mParticle.init()', ); return; } @@ -202,7 +211,7 @@ export default function mParticleInstance(this: IMParticleWebSDKInstance, instan * @method setLogLevel * @param {String} logLevel verbose, warning, or none. By default, `warning` is chosen. */ - this.setLogLevel = function(newLogLevel) { + this.setLogLevel = function (newLogLevel) { self.Logger.setLogLevel(newLogLevel); }; @@ -211,7 +220,7 @@ export default function mParticleInstance(this: IMParticleWebSDKInstance, instan * before any other mParticle methods or the SDK will not function as intended. * @method reset */ - this.reset = function(instance) { + this.reset = function (instance) { try { instance._Persistence.resetPersistence(); if (instance._Store) { @@ -222,20 +231,22 @@ export default function mParticleInstance(this: IMParticleWebSDKInstance, instan } }; - this._resetForTests = function(config, keepPersistence, instance) { + this._resetForTests = function (config, keepPersistence, instance) { if (instance._Store) { delete instance._Store; } instance._Store = new Store(config, instance); - instance._Store.isLocalStorageAvailable = instance._Persistence.determineLocalStorageAvailability( - window.localStorage - ); + instance._Store.isLocalStorageAvailable = + instance._Persistence.determineLocalStorageAvailability( + window.localStorage, + ); instance._Events.stopTracking(); if (!keepPersistence) { instance._Persistence.resetPersistence(); } instance._Persistence.forwardingStatsBatches.uploadsTable = {}; - instance._Persistence.forwardingStatsBatches.forwardingStatsEventQueue = []; + instance._Persistence.forwardingStatsBatches.forwardingStatsEventQueue = + []; instance._preInit = { readyQueue: [], pixelConfigurations: [], @@ -249,7 +260,7 @@ export default function mParticleInstance(this: IMParticleWebSDKInstance, instan * @method ready * @param {Function} function A function to be called after mParticle is initialized */ - this.ready = function(f) { + this.ready = function (f) { if (self.isInitialized() && typeof f === 'function') { f(); } else { @@ -261,7 +272,7 @@ export default function mParticleInstance(this: IMParticleWebSDKInstance, instan * @method getEnvironment * @returns {String} mParticle environment setting */ - this.getEnvironment = function() { + this.getEnvironment = function () { return self._Store.SDKConfig.isDevelopmentMode ? Constants.Environment.Development : Constants.Environment.Production; @@ -271,7 +282,7 @@ export default function mParticleInstance(this: IMParticleWebSDKInstance, instan * @method getVersion * @return {String} mParticle SDK version number */ - this.getVersion = function() { + this.getVersion = function () { return Constants.sdkVersion; }; /** @@ -279,8 +290,8 @@ export default function mParticleInstance(this: IMParticleWebSDKInstance, instan * @method setAppVersion * @param {String} version version number */ - this.setAppVersion = function(version) { - const queued = queueIfNotInitialized(function() { + this.setAppVersion = function (version) { + const queued = queueIfNotInitialized(function () { self.setAppVersion(version); }, self); @@ -294,8 +305,8 @@ export default function mParticleInstance(this: IMParticleWebSDKInstance, instan * @method setDeviceId * @param {String} name device ID (UUIDv4-formatted string) */ - this.setDeviceId = function(guid) { - const queued = queueIfNotInitialized(function() { + this.setDeviceId = function (guid) { + const queued = queueIfNotInitialized(function () { self.setDeviceId(guid); }, self); if (queued) return; @@ -306,7 +317,7 @@ export default function mParticleInstance(this: IMParticleWebSDKInstance, instan * @method isInitialized * @return {Boolean} a boolean for whether or not the SDK has been fully initialized */ - this.isInitialized = function() { + this.isInitialized = function () { return self._Store ? self._Store.isInitialized : false; }; @@ -315,7 +326,7 @@ export default function mParticleInstance(this: IMParticleWebSDKInstance, instan * @method getAppName * @return {String} App name */ - this.getAppName = function() { + this.getAppName = function () { return self._Store.SDKConfig.appName; }; /** @@ -323,8 +334,8 @@ export default function mParticleInstance(this: IMParticleWebSDKInstance, instan * @method setAppName * @param {String} name App Name */ - this.setAppName = function(name) { - const queued = queueIfNotInitialized(function() { + this.setAppName = function (name) { + const queued = queueIfNotInitialized(function () { self.setAppName(name); }, self); @@ -337,14 +348,14 @@ export default function mParticleInstance(this: IMParticleWebSDKInstance, instan * @method getAppVersion * @return {String} App version */ - this.getAppVersion = function() { + this.getAppVersion = function () { return self._Store.SDKConfig.appVersion; }; /** * Stops tracking the location of the user * @method stopTrackingLocation */ - this.stopTrackingLocation = function() { + this.stopTrackingLocation = function () { self._SessionManager.resetSessionTimer(); self._Events.stopTracking(); }; @@ -353,10 +364,10 @@ export default function mParticleInstance(this: IMParticleWebSDKInstance, instan * @method startTrackingLocation * @param {Function} [callback] A callback function that is called when the location is either allowed or rejected by the user. A position object of schema {coords: {latitude: number, longitude: number}} is passed to the callback */ - this.startTrackingLocation = function(callback) { + this.startTrackingLocation = function (callback) { if (!isFunction(callback)) { self.Logger.warning( - 'Warning: Location tracking is triggered, but not including a callback into the `startTrackingLocation` may result in events logged too quickly and not being associated with a location.' + 'Warning: Location tracking is triggered, but not including a callback into the `startTrackingLocation` may result in events logged too quickly and not being associated with a location.', ); } @@ -369,8 +380,8 @@ export default function mParticleInstance(this: IMParticleWebSDKInstance, instan * @param {Number} lattitude lattitude digit * @param {Number} longitude longitude digit */ - this.setPosition = function(lat, lng) { - const queued = queueIfNotInitialized(function() { + this.setPosition = function (lat, lng) { + const queued = queueIfNotInitialized(function () { self.setPosition(lat, lng); }, self); @@ -384,7 +395,7 @@ export default function mParticleInstance(this: IMParticleWebSDKInstance, instan }; } else { self.Logger.error( - 'Position latitude and/or longitude must both be of type number' + 'Position latitude and/or longitude must both be of type number', ); } }; @@ -392,14 +403,14 @@ export default function mParticleInstance(this: IMParticleWebSDKInstance, instan * Starts a new session * @method startNewSession */ - this.startNewSession = function() { + this.startNewSession = function () { self._SessionManager.startNewSession(); }; /** * Ends the current session * @method endSession */ - this.endSession = function() { + this.endSession = function () { // Sends true as an over ride vs when endSession is called from the setInterval self._SessionManager.endSession(true); }; @@ -409,8 +420,8 @@ export default function mParticleInstance(this: IMParticleWebSDKInstance, instan * @param {Object} event Base Event Object * @param {Object} [eventOptions] For Event-level Configuration Options */ - this.logBaseEvent = function(event, eventOptions) { - const queued = queueIfNotInitialized(function() { + this.logBaseEvent = function (event, eventOptions) { + const queued = queueIfNotInitialized(function () { self.logBaseEvent(event, eventOptions); }, self); @@ -442,20 +453,20 @@ export default function mParticleInstance(this: IMParticleWebSDKInstance, instan * @param {Object} [customFlags] Additional customFlags * @param {Object} [eventOptions] For Event-level Configuration Options */ - this.logEvent = function( + this.logEvent = function ( eventName, eventType, eventInfo, customFlags, - eventOptions + eventOptions, ) { - const queued = queueIfNotInitialized(function() { + const queued = queueIfNotInitialized(function () { self.logEvent( eventName, eventType, eventInfo, customFlags, - eventOptions + eventOptions, ); }, self); @@ -476,7 +487,7 @@ export default function mParticleInstance(this: IMParticleWebSDKInstance, instan 'Invalid event type: ' + eventType + ', must be one of: \n' + - JSON.stringify(EventType) + JSON.stringify(EventType), ); return; } @@ -494,7 +505,7 @@ export default function mParticleInstance(this: IMParticleWebSDKInstance, instan eventType: eventType, customFlags: customFlags, } as BaseEvent, - eventOptions + eventOptions, ); }; /** @@ -504,8 +515,8 @@ export default function mParticleInstance(this: IMParticleWebSDKInstance, instan * @param {String or Object} error The name of the error (string), or an object formed as follows {name: 'exampleName', message: 'exampleMessage', stack: 'exampleStack'} * @param {Object} [attrs] Custom attrs to be passed along with the error event; values must be string, number, or boolean */ - this.logError = function(error, attrs) { - const queued = queueIfNotInitialized(function() { + this.logError = function (error, attrs) { + const queued = queueIfNotInitialized(function () { self.logError(error, attrs); }, self); @@ -523,7 +534,7 @@ export default function mParticleInstance(this: IMParticleWebSDKInstance, instan } const data: IErrorLogMessageMinified = { - m: error.message ? error.message : error as string, + m: error.message ? error.message : (error as string), s: 'Error', t: error.stack || null, }; @@ -550,13 +561,13 @@ export default function mParticleInstance(this: IMParticleWebSDKInstance, instan * @param {Number} [eventType] The eventType as seen [here](http://docs.mparticle.com/developers/sdk/web/event-tracking#event-type) * @param {Object} [eventInfo] Attributes for the event */ - this.logLink = function(selector, eventName, eventType, eventInfo) { + this.logLink = function (selector, eventName, eventType, eventInfo) { self._Events.addEventHandler( 'click', selector, eventName, eventInfo, - eventType + eventType, ); }; /** @@ -567,13 +578,13 @@ export default function mParticleInstance(this: IMParticleWebSDKInstance, instan * @param {Number} [eventType] The eventType as seen [here](http://docs.mparticle.com/developers/sdk/web/event-tracking#event-type) * @param {Object} [eventInfo] Attributes for the event */ - this.logForm = function(selector, eventName, eventType, eventInfo) { + this.logForm = function (selector, eventName, eventType, eventInfo) { self._Events.addEventHandler( 'submit', selector, eventName, eventInfo, - eventType + eventType, ); }; /** @@ -584,8 +595,8 @@ export default function mParticleInstance(this: IMParticleWebSDKInstance, instan * @param {Object} [customFlags] Custom flags for the event * @param {Object} [eventOptions] For Event-level Configuration Options */ - this.logPageView = function(eventName, attrs, customFlags, eventOptions) { - const queued = queueIfNotInitialized(function() { + this.logPageView = function (eventName, attrs, customFlags, eventOptions) { + const queued = queueIfNotInitialized(function () { self.logPageView(eventName, attrs, customFlags, eventOptions); }, self); @@ -606,7 +617,7 @@ export default function mParticleInstance(this: IMParticleWebSDKInstance, instan self.Logger.error( 'The attributes argument must be an object. A ' + typeof attrs + - ' was entered. Please correct and retry.' + ' was entered. Please correct and retry.', ); return; } @@ -614,7 +625,7 @@ export default function mParticleInstance(this: IMParticleWebSDKInstance, instan self.Logger.error( 'The customFlags argument must be an object. A ' + typeof customFlags + - ' was entered. Please correct and retry.' + ' was entered. Please correct and retry.', ); return; } @@ -628,18 +639,18 @@ export default function mParticleInstance(this: IMParticleWebSDKInstance, instan eventType: EventType.Unknown, customFlags: customFlags, }, - eventOptions + eventOptions, ); }; /** * Forces an upload of the batch * @method upload */ - this.upload = function() { + this.upload = function () { if (self._Helpers.canLog()) { if (self._Store.webviewBridgeEnabled) { self._NativeSdkHelpers.sendToNative( - Constants.NativeSdkPaths.Upload + Constants.NativeSdkPaths.Upload, ); } else { self._APIClient?.uploader?.prepareAndUpload(false, false); @@ -705,9 +716,9 @@ export default function mParticleInstance(this: IMParticleWebSDKInstance, instan * @param {Boolean} [logEventBoolean] Option to log the event to mParticle's servers. If blank, no logging occurs. * @deprecated */ - add: function(product, logEventBoolean) { + add: function (product, logEventBoolean) { self.Logger.warning( - 'Deprecated function eCommerce.Cart.add() will be removed in future releases' + 'Deprecated function eCommerce.Cart.add() will be removed in future releases', ); let mpid; const currentUser = self.Identity.getCurrentUser(); @@ -725,9 +736,9 @@ export default function mParticleInstance(this: IMParticleWebSDKInstance, instan * @param {Boolean} [logEventBoolean] Option to log the event to mParticle's servers. If blank, no logging occurs. * @deprecated */ - remove: function(product, logEventBoolean) { + remove: function (product, logEventBoolean) { self.Logger.warning( - 'Deprecated function eCommerce.Cart.remove() will be removed in future releases' + 'Deprecated function eCommerce.Cart.remove() will be removed in future releases', ); let mpid; const currentUser = self.Identity.getCurrentUser(); @@ -743,9 +754,9 @@ export default function mParticleInstance(this: IMParticleWebSDKInstance, instan * @method clear * @deprecated */ - clear: function() { + clear: function () { self.Logger.warning( - 'Deprecated function eCommerce.Cart.clear() will be removed in future releases' + 'Deprecated function eCommerce.Cart.clear() will be removed in future releases', ); let mpid; const currentUser = self.Identity.getCurrentUser(); @@ -761,8 +772,8 @@ export default function mParticleInstance(this: IMParticleWebSDKInstance, instan * @method setCurrencyCode * @param {String} code The currency code */ - setCurrencyCode: function(code) { - const queued = queueIfNotInitialized(function() { + setCurrencyCode: function (code) { + const queued = queueIfNotInitialized(function () { self.eCommerce.setCurrencyCode(code); }, self); @@ -790,7 +801,7 @@ export default function mParticleInstance(this: IMParticleWebSDKInstance, instan * @param {String} [coupon] product coupon * @param {Object} [attributes] product attributes */ - createProduct: function( + createProduct: function ( name, sku, price, @@ -800,7 +811,7 @@ export default function mParticleInstance(this: IMParticleWebSDKInstance, instan brand, position, coupon, - attributes + attributes, ) { return self._Ecommerce.createProduct( name, @@ -812,7 +823,7 @@ export default function mParticleInstance(this: IMParticleWebSDKInstance, instan brand, position, coupon, - attributes + attributes, ); }, /** @@ -824,12 +835,12 @@ export default function mParticleInstance(this: IMParticleWebSDKInstance, instan * @param {String} [name] promotion name * @param {Number} [position] promotion position */ - createPromotion: function(id, creative, name, position) { + createPromotion: function (id, creative, name, position) { return self._Ecommerce.createPromotion( id, creative, name, - position + position, ); }, /** @@ -839,7 +850,7 @@ export default function mParticleInstance(this: IMParticleWebSDKInstance, instan * @param {String} name impression name * @param {Object} product the product for which an impression is being created */ - createImpression: function(name, product) { + createImpression: function (name, product) { return self._Ecommerce.createImpression(name, product); }, /** @@ -853,13 +864,13 @@ export default function mParticleInstance(this: IMParticleWebSDKInstance, instan * @param {String} [shipping] the shipping method * @param {Number} [tax] the tax amount */ - createTransactionAttributes: function( + createTransactionAttributes: function ( id, affiliation, couponCode, revenue, shipping, - tax + tax, ) { return self._Ecommerce.createTransactionAttributes( id, @@ -867,7 +878,7 @@ export default function mParticleInstance(this: IMParticleWebSDKInstance, instan couponCode, revenue, shipping, - tax + tax, ); }, /** @@ -880,18 +891,18 @@ export default function mParticleInstance(this: IMParticleWebSDKInstance, instan * @param {Object} [customFlags] Custom flags for the event * @deprecated */ - logCheckout: function(step, option, attrs, customFlags) { + logCheckout: function (step, option, attrs, customFlags) { self.Logger.warning( - 'mParticle.logCheckout is deprecated, please use mParticle.logProductAction instead' + 'mParticle.logCheckout is deprecated, please use mParticle.logProductAction instead', ); if (!self._Store.isInitialized) { - self.ready(function() { + self.ready(function () { self.eCommerce.logCheckout( step, option, attrs, - customFlags + customFlags, ); }); @@ -912,22 +923,22 @@ export default function mParticleInstance(this: IMParticleWebSDKInstance, instan * @param {Object} [transactionAttributes] Transaction Attributes for the event * @param {Object} [eventOptions] For Event-level Configuration Options */ - logProductAction: function( + logProductAction: function ( productActionType, product, attrs, customFlags, transactionAttributes, - eventOptions + eventOptions, ) { - const queued = queueIfNotInitialized(function() { + const queued = queueIfNotInitialized(function () { self.eCommerce.logProductAction( productActionType, product, attrs, customFlags, transactionAttributes, - eventOptions + eventOptions, ); }, self); @@ -940,7 +951,7 @@ export default function mParticleInstance(this: IMParticleWebSDKInstance, instan attrs, customFlags, transactionAttributes, - eventOptions + eventOptions, ); }, /** @@ -954,24 +965,24 @@ export default function mParticleInstance(this: IMParticleWebSDKInstance, instan * @param {Object} [customFlags] Custom flags for the event * @deprecated */ - logPurchase: function( + logPurchase: function ( transactionAttributes, product, clearCart, attrs, - customFlags + customFlags, ) { self.Logger.warning( - 'mParticle.logPurchase is deprecated, please use mParticle.logProductAction instead' + 'mParticle.logPurchase is deprecated, please use mParticle.logProductAction instead', ); if (!self._Store.isInitialized) { - self.ready(function() { + self.ready(function () { self.eCommerce.logPurchase( transactionAttributes, product, clearCart, attrs, - customFlags + customFlags, ); }); return; @@ -985,7 +996,7 @@ export default function mParticleInstance(this: IMParticleWebSDKInstance, instan transactionAttributes, product, attrs, - customFlags + customFlags, ); }, /** @@ -998,20 +1009,20 @@ export default function mParticleInstance(this: IMParticleWebSDKInstance, instan * @param {Object} [customFlags] Custom flags for the event * @param {Object} [eventOptions] For Event-level Configuration Options */ - logPromotion: function( + logPromotion: function ( type, promotion, attrs, customFlags, - eventOptions + eventOptions, ) { - const queued = queueIfNotInitialized(function() { + const queued = queueIfNotInitialized(function () { self.eCommerce.logPromotion( type, promotion, attrs, customFlags, - eventOptions + eventOptions, ); }, self); @@ -1023,7 +1034,7 @@ export default function mParticleInstance(this: IMParticleWebSDKInstance, instan promotion, attrs, customFlags, - eventOptions + eventOptions, ); }, /** @@ -1035,13 +1046,13 @@ export default function mParticleInstance(this: IMParticleWebSDKInstance, instan * @param {Object} [customFlags] Custom flags for the event * @param {Object} [eventOptions] For Event-level Configuration Options */ - logImpression: function(impression, attrs, customFlags, eventOptions) { - const queued = queueIfNotInitialized(function() { + logImpression: function (impression, attrs, customFlags, eventOptions) { + const queued = queueIfNotInitialized(function () { self.eCommerce.logImpression( impression, attrs, customFlags, - eventOptions + eventOptions, ); }, self); @@ -1052,7 +1063,7 @@ export default function mParticleInstance(this: IMParticleWebSDKInstance, instan impression, attrs, customFlags, - eventOptions + eventOptions, ); }, /** @@ -1066,24 +1077,24 @@ export default function mParticleInstance(this: IMParticleWebSDKInstance, instan * @param {Object} [customFlags] Custom flags for the event * @deprecated */ - logRefund: function( + logRefund: function ( transactionAttributes, product, clearCart, attrs, - customFlags + customFlags, ) { self.Logger.warning( - 'mParticle.logRefund is deprecated, please use mParticle.logProductAction instead' + 'mParticle.logRefund is deprecated, please use mParticle.logProductAction instead', ); if (!self._Store.isInitialized) { - self.ready(function() { + self.ready(function () { self.eCommerce.logRefund( transactionAttributes, product, clearCart, attrs, - customFlags + customFlags, ); }); return; @@ -1093,10 +1104,10 @@ export default function mParticleInstance(this: IMParticleWebSDKInstance, instan transactionAttributes, product, attrs, - customFlags + customFlags, ); }, - expandCommerceEvent: function(event) { + expandCommerceEvent: function (event) { return self._Ecommerce.expandCommerceEvent(event); }, }; @@ -1106,8 +1117,8 @@ export default function mParticleInstance(this: IMParticleWebSDKInstance, instan * @param {String} key key for session attribute * @param {String or Number} value value for session attribute */ - this.setSessionAttribute = function(key, value) { - const queued = queueIfNotInitialized(function() { + this.setSessionAttribute = function (key, value) { + const queued = queueIfNotInitialized(function () { self.setSessionAttribute(key, value); }, self); @@ -1130,12 +1141,12 @@ export default function mParticleInstance(this: IMParticleWebSDKInstance, instan if (self._Store.webviewBridgeEnabled) { self._NativeSdkHelpers.sendToNative( Constants.NativeSdkPaths.SetSessionAttribute, - JSON.stringify({ key: key, value: value }) + JSON.stringify({ key: key, value: value }), ); } else { const existingProp = self._Helpers.findKeyInObject( self._Store.sessionAttributes, - key + key, ); if (existingProp) { @@ -1157,8 +1168,8 @@ export default function mParticleInstance(this: IMParticleWebSDKInstance, instan * @method setOptOut * @param {Boolean} isOptingOut boolean to opt out or not. When set to true, opt out of logging. */ - this.setOptOut = function(isOptingOut) { - const queued = queueIfNotInitialized(function() { + this.setOptOut = function (isOptingOut) { + const queued = queueIfNotInitialized(function () { self.setOptOut(isOptingOut); }, self); @@ -1171,7 +1182,7 @@ export default function mParticleInstance(this: IMParticleWebSDKInstance, instan self._Persistence.update(); if (self._Store.activeForwarders.length) { - self._Store.activeForwarders.forEach(function(forwarder) { + self._Store.activeForwarders.forEach(function (forwarder) { if (forwarder.setOptOut) { const result = forwarder.setOptOut(isOptingOut); @@ -1195,8 +1206,8 @@ export default function mParticleInstance(this: IMParticleWebSDKInstance, instan * Please consult with the mParticle docs or your solutions consultant for the correct value. You may * also pass a null or empty map here to remove all of the attributes. */ - this.setIntegrationAttribute = function(integrationId, attrs) { - const queued = queueIfNotInitialized(function() { + this.setIntegrationAttribute = function (integrationId, attrs) { + const queued = queueIfNotInitialized(function () { self.setIntegrationAttribute(integrationId, attrs); }, self); @@ -1219,7 +1230,7 @@ export default function mParticleInstance(this: IMParticleWebSDKInstance, instan self._Helpers.isObject( self._Store.integrationAttributes[ integrationId - ] + ], ) ) { self._Store.integrationAttributes[ @@ -1236,13 +1247,13 @@ export default function mParticleInstance(this: IMParticleWebSDKInstance, instan } else { self.Logger.error( 'Values for integration attributes must be strings. You entered a ' + - typeof attrs[key] + typeof attrs[key], ); continue; } } else { self.Logger.error( - 'Keys must be strings, you entered a ' + typeof key + 'Keys must be strings, you entered a ' + typeof key, ); continue; } @@ -1251,7 +1262,7 @@ export default function mParticleInstance(this: IMParticleWebSDKInstance, instan } else { self.Logger.error( 'Attrs must be an object with keys and values. You entered a ' + - typeof attrs + typeof attrs, ); return; } @@ -1263,7 +1274,7 @@ export default function mParticleInstance(this: IMParticleWebSDKInstance, instan * @param {Number} integrationId mParticle integration ID * @return {Object} an object map of the integrationId's attributes */ - this.getIntegrationAttributes = function(integrationId) { + this.getIntegrationAttributes = function (integrationId) { if (self._Store.integrationAttributes[integrationId]) { return self._Store.integrationAttributes[integrationId]; } else { @@ -1271,16 +1282,16 @@ export default function mParticleInstance(this: IMParticleWebSDKInstance, instan } }; // Used by our forwarders - this.addForwarder = function(forwarder) { + this.addForwarder = function (forwarder) { self._preInit.forwarderConstructors.push(forwarder); }; - this.configurePixel = function(settings) { + this.configurePixel = function (settings) { self._Forwarders.configurePixel(settings); }; - this._getActiveForwarders = function() { + this._getActiveForwarders = function () { return self._Store.activeForwarders; }; - this._getIntegrationDelays = function() { + this._getIntegrationDelays = function () { return self._preInit.integrationDelays; }; /* @@ -1301,7 +1312,7 @@ export default function mParticleInstance(this: IMParticleWebSDKInstance, instan If there is no delay, then the events sent before an integration attribute is included would not be forwarded successfully server side. */ - this._setIntegrationDelay = function(module, shouldDelayIntegration) { + this._setIntegrationDelay = function (module, shouldDelayIntegration) { self._preInit.integrationDelays[module] = shouldDelayIntegration; // If the integration delay is set to true, no further action needed @@ -1312,18 +1323,18 @@ export default function mParticleInstance(this: IMParticleWebSDKInstance, instan // other integration delays set to true. It not, process the queued events/. const integrationDelaysKeys = Object.keys( - self._preInit.integrationDelays + self._preInit.integrationDelays, ); if (integrationDelaysKeys.length === 0) { return; } - const hasIntegrationDelays = integrationDelaysKeys.some(function( - integration - ) { - return self._preInit.integrationDelays[integration] === true; - }); + const hasIntegrationDelays = integrationDelaysKeys.some( + function (integration) { + return self._preInit.integrationDelays[integration] === true; + }, + ); if (!hasIntegrationDelays) { self._APIClient.processQueuedEvents(); @@ -1331,8 +1342,8 @@ export default function mParticleInstance(this: IMParticleWebSDKInstance, instan }; // Internal use only. Used by our wrapper SDKs to identify themselves during initialization. - this._setWrapperSDKInfo = function(name, version) { - const queued = queueIfNotInitialized(function() { + this._setWrapperSDKInfo = function (name, version) { + const queued = queueIfNotInitialized(function () { self._setWrapperSDKInfo(name, version); }, self); @@ -1382,9 +1393,10 @@ function completeSDKInitialization(apiKey, config, mpInstance) { ? currentUser.getUserIdentities().userIdentities : {}; - mpInstance._Store.SDKConfig.identifyRequest = mpInstance._Store.hasInvalidIdentifyRequest() - ? { userIdentities: currentUserIdentities } - : mpInstance._Store.SDKConfig.identifyRequest; + mpInstance._Store.SDKConfig.identifyRequest = + mpInstance._Store.hasInvalidIdentifyRequest() + ? { userIdentities: currentUserIdentities } + : mpInstance._Store.SDKConfig.identifyRequest; if (mpInstance._Helpers.getFeatureFlag(ReportBatching)) { mpInstance._ForwardingStatsUploader.startForwardingStatsTimer(); @@ -1401,7 +1413,7 @@ function completeSDKInitialization(apiKey, config, mpInstance) { const roktFilteredUser = filteredMparticleUser( currentUserMPID, { userAttributeFilters }, - mpInstance + mpInstance, ); const roktOptions: IRoktOptions = { sandbox: config?.isDevelopmentMode, @@ -1413,13 +1425,13 @@ function completeSDKInitialization(apiKey, config, mpInstance) { roktFilteredUser, mpInstance.Identity, mpInstance.Logger, - roktOptions + roktOptions, ); } mpInstance._Forwarders.processForwarders( config, - mpInstance._APIClient.prepareForwardingStats + mpInstance._APIClient.prepareForwardingStats, ); mpInstance._Forwarders.processPixelConfigs(config); @@ -1432,7 +1444,7 @@ function completeSDKInitialization(apiKey, config, mpInstance) { mpInstance, currentUser, currentUserMPID, - currentUserIdentities + currentUserIdentities, ); } @@ -1445,7 +1457,7 @@ function completeSDKInitialization(apiKey, config, mpInstance) { mpInstance._Store.isInitialized = true; mpInstance._preInit.readyQueue = processReadyQueue( - mpInstance._preInit.readyQueue + mpInstance._preInit.readyQueue, ); } @@ -1536,12 +1548,13 @@ function runPreConfigFetchInitialization(mpInstance, apiKey, config) { // since we will need this for the current implementation of user persistence // TODO: Refactor this when we refactor User Identity Persistence try { - mpInstance._Store.isLocalStorageAvailable = mpInstance._Persistence.determineLocalStorageAvailability( - window.localStorage - ); + mpInstance._Store.isLocalStorageAvailable = + mpInstance._Persistence.determineLocalStorageAvailability( + window.localStorage, + ); } catch (e) { mpInstance.Logger.warning( - 'localStorage is not available, using cookies if available' + 'localStorage is not available, using cookies if available', ); mpInstance._Store.isLocalStorageAvailable = false; } @@ -1551,7 +1564,7 @@ function processIdentityCallback( mpInstance, currentUser, currentUserMPID, - currentUserIdentities + currentUserIdentities, ) { // https://go.mparticle.com/work/SQDSDKS-6323 // Call mParticle._Store.SDKConfig.identityCallback when identify was not called @@ -1566,10 +1579,10 @@ function processIdentityCallback( ) { mpInstance._Store.SDKConfig.identityCallback({ httpCode: HTTPCodes.activeSession, - getUser: function() { + getUser: function () { return mpInstance._Identity.mParticleUser(currentUserMPID); }, - getPreviousUser: function() { + getPreviousUser: function () { const users = mpInstance.Identity.getUsers(); let mostRecentUser = users.shift(); const mostRecentUserMPID = mostRecentUser.getMPID(); @@ -1591,11 +1604,10 @@ function processIdentityCallback( function queueIfNotInitialized(func, self) { if (!self.isInitialized()) { - self.ready(function() { + self.ready(function () { func(); }); return true; } return false; } - diff --git a/src/mparticle-instance-manager.ts b/src/mparticle-instance-manager.ts index d69007ec2..a806560da 100644 --- a/src/mparticle-instance-manager.ts +++ b/src/mparticle-instance-manager.ts @@ -1,5 +1,11 @@ import Polyfill from './polyfill'; -import { CommerceEventType, EventType, IdentityType, ProductActionType, PromotionActionType } from './types'; +import { + CommerceEventType, + EventType, + IdentityType, + ProductActionType, + PromotionActionType, +} from './types'; import Constants from './constants'; import mParticleInstance, { IMParticleWebSDKInstance } from './mp-instance.js'; import _BatchValidator from './mockBatchCreator'; @@ -59,17 +65,18 @@ function mParticleInstanceManager(this: IMParticleInstanceManager) { * @param {Object} [config] an options object for additional configuration * @param {String} [instanceName] If you are self hosting the JS SDK and working with multiple instances, you would pass an instanceName to `init`. This instance will be selected when invoking other methods. See the above link to the doc site for more info and examples. */ - this.init = function(apiKey, config, instanceName) { - if (!config && (window.mParticle && window.mParticle.config)) { + this.init = function (apiKey, config, instanceName) { + if (!config && window.mParticle && window.mParticle.config) { console.warn( - 'You did not pass a config object to mParticle.init(). Attempting to use the window.mParticle.config if it exists. Please note that in a future release, this may not work and mParticle will not initialize properly' + 'You did not pass a config object to mParticle.init(). Attempting to use the window.mParticle.config if it exists. Please note that in a future release, this may not work and mParticle will not initialize properly', ); config = window.mParticle ? window.mParticle.config : {}; } - instanceName = (!instanceName || instanceName.length === 0 - ? Constants.DefaultInstance - : instanceName + instanceName = ( + !instanceName || instanceName.length === 0 + ? Constants.DefaultInstance + : instanceName ).toLowerCase(); let client: IMParticleWebSDKInstance = self._instances[instanceName]; if (client === undefined) { @@ -96,7 +103,7 @@ function mParticleInstanceManager(this: IMParticleInstanceManager) { console.log( 'You tried to initialize an instance named ' + instanceName + - '. This instance does not exist. Check your instance name or initialize a new instance with this name before calling it.' + '. This instance does not exist. Check your instance name or initialize a new instance with this name before calling it.', ); return null; } @@ -106,115 +113,115 @@ function mParticleInstanceManager(this: IMParticleInstanceManager) { this.Rokt = self.getInstance()._RoktManager; - this.getDeviceId = function() { + this.getDeviceId = function () { return self.getInstance().getDeviceId(); }; - this.setDeviceId = function(guid) { + this.setDeviceId = function (guid) { return self.getInstance().setDeviceId(guid); }; - this.isInitialized = function() { + this.isInitialized = function () { return self.getInstance().isInitialized(); }; - this.startNewSession = function() { + this.startNewSession = function () { self.getInstance().startNewSession(); }; - this.endSession = function() { + this.endSession = function () { self.getInstance().endSession(); }; - this.setLogLevel = function(newLogLevel) { + this.setLogLevel = function (newLogLevel) { self.getInstance().setLogLevel(newLogLevel); }; - this.ready = function(argument) { + this.ready = function (argument) { self.getInstance().ready(argument); }; - this.setAppVersion = function(version) { + this.setAppVersion = function (version) { self.getInstance().setAppVersion(version); }; - this.getAppName = function() { + this.getAppName = function () { return self.getInstance().getAppName(); }; - this.setAppName = function(name) { + this.setAppName = function (name) { self.getInstance().setAppName(name); }; - this.getAppVersion = function() { + this.getAppVersion = function () { return self.getInstance().getAppVersion(); }; - this.getEnvironment = function() { + this.getEnvironment = function () { return self.getInstance().getEnvironment(); }; - this.stopTrackingLocation = function() { + this.stopTrackingLocation = function () { self.getInstance().stopTrackingLocation(); }; - this.startTrackingLocation = function(callback) { + this.startTrackingLocation = function (callback) { self.getInstance().startTrackingLocation(callback); }; - this.setPosition = function(lat, lng) { + this.setPosition = function (lat, lng) { self.getInstance().setPosition(lat, lng); }; - this.startNewSession = function() { + this.startNewSession = function () { self.getInstance().startNewSession(); }; - this.endSession = function() { + this.endSession = function () { self.getInstance().endSession(); }; - this.logBaseEvent = function(event, eventOptions) { + this.logBaseEvent = function (event, eventOptions) { self.getInstance().logBaseEvent(event, eventOptions); }; - this.logEvent = function( + this.logEvent = function ( eventName, eventType, eventInfo, customFlags, - eventOptions + eventOptions, ) { self.getInstance().logEvent( eventName, eventType, eventInfo, customFlags, - eventOptions + eventOptions, ); }; - this.logError = function(error, attrs) { + this.logError = function (error, attrs) { self.getInstance().logError(error, attrs); }; - this.logLink = function(selector, eventName, eventType, eventInfo) { + this.logLink = function (selector, eventName, eventType, eventInfo) { self.getInstance().logLink(selector, eventName, eventType, eventInfo); }; - this.logForm = function(selector, eventName, eventType, eventInfo) { + this.logForm = function (selector, eventName, eventType, eventInfo) { self.getInstance().logForm(selector, eventName, eventType, eventInfo); }; - this.logPageView = function(eventName, attrs, customFlags, eventOptions) { + this.logPageView = function (eventName, attrs, customFlags, eventOptions) { self.getInstance().logPageView( eventName, attrs, customFlags, - eventOptions + eventOptions, ); }; - this.upload = function() { + this.upload = function () { self.getInstance().upload(); }; this.eCommerce = { Cart: { - add: function(product, logEventBoolean) { + add: function (product, logEventBoolean) { self.getInstance().eCommerce.Cart.add(product, logEventBoolean); }, - remove: function(product, logEventBoolean) { + remove: function (product, logEventBoolean) { self.getInstance().eCommerce.Cart.remove( product, - logEventBoolean + logEventBoolean, ); }, - clear: function() { + clear: function () { self.getInstance().eCommerce.Cart.clear(); }, }, - setCurrencyCode: function(code) { + setCurrencyCode: function (code) { self.getInstance().eCommerce.setCurrencyCode(code); }, - createProduct: function( + createProduct: function ( name, sku, price, @@ -224,7 +231,7 @@ function mParticleInstanceManager(this: IMParticleInstanceManager) { brand, position, coupon, - attributes + attributes, ) { return self .getInstance() @@ -238,24 +245,24 @@ function mParticleInstanceManager(this: IMParticleInstanceManager) { brand, position, coupon, - attributes + attributes, ); }, - createPromotion: function(id, creative, name, position) { + createPromotion: function (id, creative, name, position) { return self .getInstance() .eCommerce.createPromotion(id, creative, name, position); }, - createImpression: function(name, product) { + createImpression: function (name, product) { return self.getInstance().eCommerce.createImpression(name, product); }, - createTransactionAttributes: function( + createTransactionAttributes: function ( id, affiliation, couponCode, revenue, shipping, - tax + tax, ) { return self .getInstance() @@ -265,24 +272,24 @@ function mParticleInstanceManager(this: IMParticleInstanceManager) { couponCode, revenue, shipping, - tax + tax, ); }, - logCheckout: function(step, options, attrs, customFlags) { + logCheckout: function (step, options, attrs, customFlags) { self.getInstance().eCommerce.logCheckout( step, options, attrs, - customFlags + customFlags, ); }, - logProductAction: function( + logProductAction: function ( productActionType, product, attrs, customFlags, transactionAttributes, - eventOptions + eventOptions, ) { self.getInstance().eCommerce.logProductAction( productActionType, @@ -290,128 +297,128 @@ function mParticleInstanceManager(this: IMParticleInstanceManager) { attrs, customFlags, transactionAttributes, - eventOptions + eventOptions, ); }, - logPurchase: function( + logPurchase: function ( transactionAttributes, product, clearCart, attrs, - customFlags + customFlags, ) { self.getInstance().eCommerce.logPurchase( transactionAttributes, product, clearCart, attrs, - customFlags + customFlags, ); }, - logPromotion: function( + logPromotion: function ( type, promotion, attrs, customFlags, - eventOptions + eventOptions, ) { self.getInstance().eCommerce.logPromotion( type, promotion, attrs, customFlags, - eventOptions + eventOptions, ); }, - logImpression: function(impression, attrs, customFlags, eventOptions) { + logImpression: function (impression, attrs, customFlags, eventOptions) { self.getInstance().eCommerce.logImpression( impression, attrs, customFlags, - eventOptions + eventOptions, ); }, - logRefund: function( + logRefund: function ( transactionAttributes, product, clearCart, attrs, - customFlags + customFlags, ) { self.getInstance().eCommerce.logRefund( transactionAttributes, product, clearCart, attrs, - customFlags + customFlags, ); }, - expandCommerceEvent: function(event) { + expandCommerceEvent: function (event) { return self.getInstance().eCommerce.expandCommerceEvent(event); }, }; - this.setSessionAttribute = function(key, value) { + this.setSessionAttribute = function (key, value) { self.getInstance().setSessionAttribute(key, value); }; - this.setOptOut = function(isOptingOut) { + this.setOptOut = function (isOptingOut) { self.getInstance().setOptOut(isOptingOut); }; - this.setIntegrationAttribute = function(integrationId, attrs) { + this.setIntegrationAttribute = function (integrationId, attrs) { self.getInstance().setIntegrationAttribute(integrationId, attrs); }; - this.getIntegrationAttributes = function(moduleId) { + this.getIntegrationAttributes = function (moduleId) { return self.getInstance().getIntegrationAttributes(moduleId); }; this.Identity = { HTTPCodes: Constants.HTTPCodes, - aliasUsers: function(aliasRequest, callback) { + aliasUsers: function (aliasRequest, callback) { self.getInstance().Identity.aliasUsers(aliasRequest, callback); }, - createAliasRequest: function(sourceUser, destinationUser) { + createAliasRequest: function (sourceUser, destinationUser) { return self .getInstance() .Identity.createAliasRequest(sourceUser, destinationUser); }, - getCurrentUser: function() { + getCurrentUser: function () { return self.getInstance().Identity.getCurrentUser(); }, - getUser: function(mpid) { + getUser: function (mpid) { return self.getInstance().Identity.getUser(mpid); }, - getUsers: function() { + getUsers: function () { return self.getInstance().Identity.getUsers(); }, - identify: function(identityApiData, callback) { + identify: function (identityApiData, callback) { self.getInstance().Identity.identify(identityApiData, callback); }, - login: function(identityApiData, callback) { + login: function (identityApiData, callback) { self.getInstance().Identity.login(identityApiData, callback); }, - logout: function(identityApiData, callback) { + logout: function (identityApiData, callback) { self.getInstance().Identity.logout(identityApiData, callback); }, - modify: function(identityApiData, callback) { + modify: function (identityApiData, callback) { self.getInstance().Identity.modify(identityApiData, callback); }, }; this.sessionManager = { - getSession: function() { + getSession: function () { return self.getInstance()._SessionManager.getSession(); }, }; this.Consent = { - createConsentState: function() { + createConsentState: function () { return self.getInstance().Consent.createConsentState(); }, - createGDPRConsent: function( + createGDPRConsent: function ( consented, timestamp, consentDocument, location, - hardwareId + hardwareId, ) { return self .getInstance() @@ -420,15 +427,15 @@ function mParticleInstanceManager(this: IMParticleInstanceManager) { timestamp, consentDocument, location, - hardwareId + hardwareId, ); }, - createCCPAConsent: function( + createCCPAConsent: function ( consented, timestamp, consentDocument, location, - hardwareId + hardwareId, ) { return self .getInstance() @@ -437,54 +444,54 @@ function mParticleInstanceManager(this: IMParticleInstanceManager) { timestamp, consentDocument, location, - hardwareId + hardwareId, ); }, }; - this.reset = function() { + this.reset = function () { self.getInstance().reset(self.getInstance()); }; - this._resetForTests = function(MPConfig, keepPersistence) { + this._resetForTests = function (MPConfig, keepPersistence) { if (typeof keepPersistence === 'boolean') { self.getInstance()._resetForTests( MPConfig, keepPersistence, - self.getInstance() + self.getInstance(), ); } else { self.getInstance()._resetForTests( MPConfig, false, - self.getInstance() + self.getInstance(), ); } }; - this.configurePixel = function(settings) { + this.configurePixel = function (settings) { self.getInstance().configurePixel(settings); }; - this._setIntegrationDelay = function(moduleId, boolean) { + this._setIntegrationDelay = function (moduleId, boolean) { self.getInstance()._setIntegrationDelay(moduleId, boolean); }; - this._getIntegrationDelays = function() { + this._getIntegrationDelays = function () { return self.getInstance()._getIntegrationDelays(); }; - this.getVersion = function() { + this.getVersion = function () { return self.getInstance().getVersion(); }; - this.generateHash = function(string) { + this.generateHash = function (string) { return self.getInstance().generateHash(string); }; - this.addForwarder = function(forwarder) { + this.addForwarder = function (forwarder) { self.getInstance().addForwarder(forwarder); }; - this._getActiveForwarders = function() { + this._getActiveForwarders = function () { return self.getInstance()._getActiveForwarders(); }; - this._setWrapperSDKInfo = function(name, version) { + this._setWrapperSDKInfo = function (name, version) { self.getInstance()._setWrapperSDKInfo(name, version); }; } @@ -494,7 +501,7 @@ const mParticleManager = new mParticleInstanceManager(); if (typeof window !== 'undefined') { // mParticle is the global object used to access the SDK and predates instance manager, // when mParticle was a singleton. We now support multiple instances. Calling methods - // on mParticle directly will access the default instance, but mParticle can also be used + // on mParticle directly will access the default instance, but mParticle can also be used // as the instance manager in self hosted mode. window.mParticle = mParticleManager; @@ -502,4 +509,4 @@ if (typeof window !== 'undefined') { window.mParticle._BatchValidator = new _BatchValidator(); } -export default mParticleManager; \ No newline at end of file +export default mParticleManager; diff --git a/src/nativeSdkHelpers.interfaces.ts b/src/nativeSdkHelpers.interfaces.ts index ae7ba09bc..3ef5c6c9c 100644 --- a/src/nativeSdkHelpers.interfaces.ts +++ b/src/nativeSdkHelpers.interfaces.ts @@ -3,11 +3,15 @@ export interface INativeSdkHelpers { isBridgeV2Available: (bridgeName: string) => boolean; isWebviewEnabled: ( requiredWebviewBridgeName: string, - minWebviewBridgeVersion: number + minWebviewBridgeVersion: number, ) => boolean; isBridgeV1Available: () => boolean; sendToNative: (path: string, value?: string) => void; sendViaBridgeV1: (path: string, value: string) => void; sendViaIframeToIOS: (path: string, value: string) => void; - sendViaBridgeV2: (path: string, value: string, requiredWebviewBridgeName: boolean) => void; + sendViaBridgeV2: ( + path: string, + value: string, + requiredWebviewBridgeName: boolean, + ) => void; } diff --git a/src/nativeSdkHelpers.js b/src/nativeSdkHelpers.js index b8464dd7b..724abcb7c 100644 --- a/src/nativeSdkHelpers.js +++ b/src/nativeSdkHelpers.js @@ -1,13 +1,13 @@ import Constants from './constants'; -var Messages = Constants.Messages; +const Messages = Constants.Messages; -var androidBridgeNameBase = 'mParticleAndroid'; -var iosBridgeNameBase = 'mParticle'; +const androidBridgeNameBase = 'mParticleAndroid'; +const iosBridgeNameBase = 'mParticle'; export default function NativeSdkHelpers(mpInstance) { - var self = this; - this.initializeSessionAttributes = function(apiKey) { + const self = this; + this.initializeSessionAttributes = function (apiKey) { const { SetSessionAttribute } = Constants.NativeSdkPaths; const env = JSON.stringify({ key: '$src_env', @@ -25,13 +25,13 @@ export default function NativeSdkHelpers(mpInstance) { } }; - this.isBridgeV2Available = function(bridgeName) { + this.isBridgeV2Available = function (bridgeName) { if (!bridgeName) { return false; } - var androidBridgeName = + const androidBridgeName = androidBridgeNameBase + '_' + bridgeName + '_v2'; - var iosBridgeName = iosBridgeNameBase + '_' + bridgeName + '_v2'; + const iosBridgeName = iosBridgeNameBase + '_' + bridgeName + '_v2'; // iOS v2 bridge if ( @@ -57,12 +57,12 @@ export default function NativeSdkHelpers(mpInstance) { return false; }; - this.isWebviewEnabled = function( + this.isWebviewEnabled = function ( requiredWebviewBridgeName, - minWebviewBridgeVersion + minWebviewBridgeVersion, ) { mpInstance._Store.bridgeV2Available = self.isBridgeV2Available( - requiredWebviewBridgeName + requiredWebviewBridgeName, ); mpInstance._Store.bridgeV1Available = self.isBridgeV1Available(); @@ -92,7 +92,7 @@ export default function NativeSdkHelpers(mpInstance) { return false; }; - this.isBridgeV1Available = function() { + this.isBridgeV1Available = function () { if ( mpInstance._Store.SDKConfig.useNativeSdk || window.mParticleAndroid || @@ -104,7 +104,7 @@ export default function NativeSdkHelpers(mpInstance) { return false; }; - this.sendToNative = function(path, value) { + this.sendToNative = function (path, value) { if ( mpInstance._Store.bridgeV2Available && mpInstance._Store.SDKConfig.minWebviewBridgeVersion === 2 @@ -112,7 +112,7 @@ export default function NativeSdkHelpers(mpInstance) { self.sendViaBridgeV2( path, value, - mpInstance._Store.SDKConfig.requiredWebviewBridgeName + mpInstance._Store.SDKConfig.requiredWebviewBridgeName, ); return; } @@ -123,7 +123,7 @@ export default function NativeSdkHelpers(mpInstance) { self.sendViaBridgeV2( path, value, - mpInstance._Store.SDKConfig.requiredWebviewBridgeName + mpInstance._Store.SDKConfig.requiredWebviewBridgeName, ); return; } @@ -136,39 +136,39 @@ export default function NativeSdkHelpers(mpInstance) { } }; - this.sendViaBridgeV1 = function(path, value) { + this.sendViaBridgeV1 = function (path, value) { if ( window.mParticleAndroid && window.mParticleAndroid.hasOwnProperty(path) ) { mpInstance.Logger.verbose( - Messages.InformationMessages.SendAndroid + path + Messages.InformationMessages.SendAndroid + path, ); window.mParticleAndroid[path](value); } else if (mpInstance._Store.SDKConfig.isIOS) { mpInstance.Logger.verbose( - Messages.InformationMessages.SendIOS + path + Messages.InformationMessages.SendIOS + path, ); self.sendViaIframeToIOS(path, value); } }; - this.sendViaIframeToIOS = function(path, value) { - var iframe = document.createElement('IFRAME'); + this.sendViaIframeToIOS = function (path, value) { + const iframe = document.createElement('IFRAME'); iframe.setAttribute( 'src', - 'mp-sdk://' + path + '/' + encodeURIComponent(value) + 'mp-sdk://' + path + '/' + encodeURIComponent(value), ); document.documentElement.appendChild(iframe); iframe.parentNode.removeChild(iframe); }; - this.sendViaBridgeV2 = function(path, value, requiredWebviewBridgeName) { + this.sendViaBridgeV2 = function (path, value, requiredWebviewBridgeName) { if (!requiredWebviewBridgeName) { return; } - var androidBridgeName = + let androidBridgeName = androidBridgeNameBase + '_' + requiredWebviewBridgeName + '_v2', androidBridge = window[androidBridgeName], iosBridgeName = @@ -191,24 +191,24 @@ export default function NativeSdkHelpers(mpInstance) { if (androidBridge && androidBridge.hasOwnProperty(path)) { mpInstance.Logger.verbose( - Messages.InformationMessages.SendAndroid + path + Messages.InformationMessages.SendAndroid + path, ); androidBridge[path](value); return; } else if (iOSBridgeMessageHandler) { mpInstance.Logger.verbose( - Messages.InformationMessages.SendIOS + path + Messages.InformationMessages.SendIOS + path, ); iOSBridgeMessageHandler.postMessage( JSON.stringify({ path: path, value: value ? JSON.parse(value) : null, - }) + }), ); } else if (iOSBridgeNonMessageHandler) { mpInstance.Logger.verbose( - Messages.InformationMessages.SendIOS + path + Messages.InformationMessages.SendIOS + path, ); self.sendViaIframeToIOS(path, value); } diff --git a/src/persistence.interfaces.ts b/src/persistence.interfaces.ts index 1fc585336..72c5d7098 100644 --- a/src/persistence.interfaces.ts +++ b/src/persistence.interfaces.ts @@ -111,7 +111,7 @@ export interface IPersistence { persistence: IPersistenceMinified, expires: string, domain: string, - maxCookieSize: number + maxCookieSize: number, ): string; findPrevCookiesBasedOnUI(identityApiData: IdentityApiData): void; encodePersistence(persistence: IPersistenceMinified): string; @@ -120,7 +120,10 @@ export interface IPersistence { getDomain(doc: string, locationHostname: string): string; getCartProducts(mpid: MPID): Product[]; setCartProducts(allProducts: Product[]): void; - saveUserCookieSyncDatesToPersistence(mpid: MPID, csd: CookieSyncDates): void; + saveUserCookieSyncDatesToPersistence( + mpid: MPID, + csd: CookieSyncDates, + ): void; savePersistence(persistance: IPersistenceMinified): void; getPersistence(): IPersistenceMinified; getFirstSeenTime(mpid: MPID): string | null; @@ -133,7 +136,7 @@ export interface IPersistence { swapCurrentUser( previousMPID: MPID, currentMPID: MPID, - currentSessionMPIDs?: MPID[] + currentSessionMPIDs?: MPID[], ): void; forwardingStatsBatches: iForwardingStatsBatches; } diff --git a/src/persistence.js b/src/persistence.js index b1411cdf5..32cddb87e 100644 --- a/src/persistence.js +++ b/src/persistence.js @@ -2,26 +2,26 @@ import Constants from './constants'; import Polyfill from './polyfill'; import * as Utils from './utils'; -var Base64 = Polyfill.Base64, +const Base64 = Polyfill.Base64, Messages = Constants.Messages, Base64CookieKeys = Constants.Base64CookieKeys, SDKv2NonMPIDCookieKeys = Constants.SDKv2NonMPIDCookieKeys, StorageNames = Constants.StorageNames; export default function _Persistence(mpInstance) { - var self = this; + const self = this; // https://go.mparticle.com/work/SQDSDKS-5022 - this.useLocalStorage = function() { + this.useLocalStorage = function () { return ( !mpInstance._Store.SDKConfig.useCookieStorage && mpInstance._Store.isLocalStorageAvailable ); }; - this.initializeStorage = function() { + this.initializeStorage = function () { try { - var storage, + let storage, localStorageData = self.getLocalStorage(), cookies = self.getCookie(), allData; @@ -52,7 +52,7 @@ export default function _Persistence(mpInstance) { allData = mpInstance._Helpers.extend( false, localStorageData, - cookies + cookies, ); } else { allData = localStorageData; @@ -71,7 +71,7 @@ export default function _Persistence(mpInstance) { allData = mpInstance._Helpers.extend( false, localStorageData, - cookies + cookies, ); } else { allData = cookies; @@ -89,19 +89,19 @@ export default function _Persistence(mpInstance) { // https://go.mparticle.com/work/SQDSDKS-6048 try { if (mpInstance._Store.isLocalStorageAvailable) { - var encodedProducts = localStorage.getItem( - mpInstance._Store.prodStorageName + const encodedProducts = localStorage.getItem( + mpInstance._Store.prodStorageName, ); if (encodedProducts) { var decodedProducts = JSON.parse( - Base64.decode(encodedProducts) + Base64.decode(encodedProducts), ); } if (mpInstance._Store.mpid) { self.storeProductsInMemory( decodedProducts, - mpInstance._Store.mpid + mpInstance._Store.mpid, ); } } @@ -111,13 +111,13 @@ export default function _Persistence(mpInstance) { } mpInstance._Store.cartProducts = []; mpInstance.Logger.error( - 'Error loading products in initialization: ' + e + 'Error loading products in initialization: ' + e, ); } // https://go.mparticle.com/work/SQDSDKS-6046 // Stores all non-current user MPID information into the store - for (var key in allData) { + for (const key in allData) { if (allData.hasOwnProperty(key)) { if (!SDKv2NonMPIDCookieKeys[key]) { mpInstance._Store.nonCurrentUserMPIDs[key] = @@ -141,7 +141,7 @@ export default function _Persistence(mpInstance) { } }; - this.update = function() { + this.update = function () { if (!mpInstance._Store.webviewBridgeEnabled) { if (mpInstance._Store.SDKConfig.useCookieStorage) { self.setCookie(); @@ -151,7 +151,7 @@ export default function _Persistence(mpInstance) { } }; - this.storeProductsInMemory = function(products, mpid) { + this.storeProductsInMemory = function (products, mpid) { if (products) { try { mpInstance._Store.cartProducts = @@ -160,18 +160,18 @@ export default function _Persistence(mpInstance) { : []; } catch (e) { mpInstance.Logger.error( - Messages.ErrorMessages.CookieParseError + Messages.ErrorMessages.CookieParseError, ); } } }; // https://go.mparticle.com/work/SQDSDKS-6045 - this.storeDataInMemory = function(obj, currentMPID) { + this.storeDataInMemory = function (obj, currentMPID) { try { if (!obj) { mpInstance.Logger.verbose( - Messages.InformationMessages.CookieNotFound + Messages.InformationMessages.CookieNotFound, ); mpInstance._Store.clientId = mpInstance._Store.clientId || @@ -249,8 +249,8 @@ export default function _Persistence(mpInstance) { }; // https://go.mparticle.com/work/SQDSDKS-5022 - this.determineLocalStorageAvailability = function(storage) { - var result; + this.determineLocalStorageAvailability = function (storage) { + let result; if (window.mParticle && window.mParticle._forceNoLocalStorage) { storage = undefined; @@ -266,16 +266,16 @@ export default function _Persistence(mpInstance) { } }; - this.getUserProductsFromLS = function(mpid) { + this.getUserProductsFromLS = function (mpid) { if (!mpInstance._Store.isLocalStorageAvailable) { return []; } - var decodedProducts, + let decodedProducts, userProducts, parsedProducts, encodedProducts = localStorage.getItem( - mpInstance._Store.prodStorageName + mpInstance._Store.prodStorageName, ); if (encodedProducts) { decodedProducts = Base64.decode(encodedProducts); @@ -305,10 +305,10 @@ export default function _Persistence(mpInstance) { } }; - this.getAllUserProductsFromLS = function() { - var decodedProducts, + this.getAllUserProductsFromLS = function () { + let decodedProducts, encodedProducts = localStorage.getItem( - mpInstance._Store.prodStorageName + mpInstance._Store.prodStorageName, ), parsedDecodedProducts; if (encodedProducts) { @@ -325,12 +325,12 @@ export default function _Persistence(mpInstance) { }; // https://go.mparticle.com/work/SQDSDKS-6021 - this.setLocalStorage = function() { + this.setLocalStorage = function () { if (!mpInstance._Store.isLocalStorageAvailable) { return; } - var key = mpInstance._Store.storageName, + let key = mpInstance._Store.storageName, allLocalStorageProducts = self.getAllUserProductsFromLS(), localStorageData = self.getLocalStorage() || {}, currentUser = mpInstance.Identity.getCurrentUser(), @@ -346,11 +346,11 @@ export default function _Persistence(mpInstance) { try { window.localStorage.setItem( encodeURIComponent(mpInstance._Store.prodStorageName), - Base64.encode(JSON.stringify(allLocalStorageProducts)) + Base64.encode(JSON.stringify(allLocalStorageProducts)), ); } catch (e) { mpInstance.Logger.error( - 'Error with setting products on localStorage.' + 'Error with setting products on localStorage.', ); } } @@ -374,7 +374,7 @@ export default function _Persistence(mpInstance) { localStorageData = mpInstance._Helpers.extend( {}, localStorageData, - mpInstance._Store.nonCurrentUserMPIDs + mpInstance._Store.nonCurrentUserMPIDs, ); mpInstance._Store.nonCurrentUserMPIDs = {}; } @@ -384,18 +384,18 @@ export default function _Persistence(mpInstance) { try { window.localStorage.setItem( encodeURIComponent(key), - self.encodePersistence(JSON.stringify(localStorageData)) + self.encodePersistence(JSON.stringify(localStorageData)), ); } catch (e) { mpInstance.Logger.error( - 'Error with setting localStorage item.' + 'Error with setting localStorage item.', ); } } }; function setGlobalStorageAttributes(data) { - var store = mpInstance._Store; + const store = mpInstance._Store; data.gs.sid = store.sessionId; data.gs.ie = store.isEnabled; data.gs.sa = store.sessionAttributes; @@ -416,14 +416,14 @@ export default function _Persistence(mpInstance) { return data; } - this.getLocalStorage = function() { + this.getLocalStorage = function () { if (!mpInstance._Store.isLocalStorageAvailable) { return null; } - var key = mpInstance._Store.storageName, + let key = mpInstance._Store.storageName, localStorageData = self.decodePersistence( - window.localStorage.getItem(key) + window.localStorage.getItem(key), ), obj = {}, j; @@ -447,8 +447,8 @@ export default function _Persistence(mpInstance) { localStorage.removeItem(localStorageName); } - this.expireCookies = function(cookieName) { - var date = new Date(), + this.expireCookies = function (cookieName) { + let date = new Date(), expires, domain, cookieDomain; @@ -466,8 +466,8 @@ export default function _Persistence(mpInstance) { document.cookie = cookieName + '=' + '' + expires + '; path=/' + domain; }; - this.getCookie = function() { - var cookies, + this.getCookie = function () { + let cookies, key = mpInstance._Store.storageName, i, l, @@ -492,7 +492,7 @@ export default function _Persistence(mpInstance) { cookie = parts.join('='); } catch (e) { mpInstance.Logger.verbose( - 'Unable to parse cookie: ' + name + '. Skipping.' + 'Unable to parse cookie: ' + name + '. Skipping.', ); } @@ -516,13 +516,13 @@ export default function _Persistence(mpInstance) { // https://go.mparticle.com/work/SQDSDKS-5022 // https://go.mparticle.com/work/SQDSDKS-6021 - this.setCookie = function() { - var mpid, + this.setCookie = function () { + let mpid, currentUser = mpInstance.Identity.getCurrentUser(); if (currentUser) { mpid = currentUser.getMPID(); } - var date = new Date(), + let date = new Date(), key = mpInstance._Store.storageName, cookies = self.getCookie() || {}, expires = new Date( @@ -531,7 +531,7 @@ export default function _Persistence(mpInstance) { 24 * 60 * 60 * - 1000 + 1000, ).toGMTString(), cookieDomain, domain, @@ -563,7 +563,7 @@ export default function _Persistence(mpInstance) { cookies = mpInstance._Helpers.extend( {}, cookies, - mpInstance._Store.nonCurrentUserMPIDs + mpInstance._Store.nonCurrentUserMPIDs, ); mpInstance._Store.nonCurrentUserMPIDs = {}; } @@ -572,7 +572,7 @@ export default function _Persistence(mpInstance) { cookies, expires, domain, - mpInstance._Store.SDKConfig.maxCookieSize + mpInstance._Store.SDKConfig.maxCookieSize, ); mpInstance.Logger.verbose(Messages.InformationMessages.CookieSet); @@ -593,23 +593,20 @@ export default function _Persistence(mpInstance) { b. Then remove MPIDs based on order in currentSessionMPIDs array, which stores MPIDs based on earliest login. */ - this.reduceAndEncodePersistence = function( + this.reduceAndEncodePersistence = function ( persistence, expires, domain, - maxCookieSize + maxCookieSize, ) { - var encodedCookiesWithExpirationAndPath, + let encodedCookiesWithExpirationAndPath, currentSessionMPIDs = persistence.gs.csm ? persistence.gs.csm : []; // Comment 1 above if (!currentSessionMPIDs.length) { - for (var key in persistence) { + for (const key in persistence) { if (persistence.hasOwnProperty(key)) { - encodedCookiesWithExpirationAndPath = createFullEncodedCookie( - persistence, - expires, - domain - ); + encodedCookiesWithExpirationAndPath = + createFullEncodedCookie(persistence, expires, domain); if ( encodedCookiesWithExpirationAndPath.length > maxCookieSize @@ -625,8 +622,8 @@ export default function _Persistence(mpInstance) { } } else { // Comment 2 above - First create an object of all MPIDs on the cookie - var MPIDsOnCookie = {}; - for (var potentialMPID in persistence) { + const MPIDsOnCookie = {}; + for (const potentialMPID in persistence) { if (persistence.hasOwnProperty(potentialMPID)) { if ( !SDKv2NonMPIDCookieKeys[potentialMPID] && @@ -638,12 +635,9 @@ export default function _Persistence(mpInstance) { } // Comment 2a above if (Object.keys(MPIDsOnCookie).length) { - for (var mpid in MPIDsOnCookie) { - encodedCookiesWithExpirationAndPath = createFullEncodedCookie( - persistence, - expires, - domain - ); + for (const mpid in MPIDsOnCookie) { + encodedCookiesWithExpirationAndPath = + createFullEncodedCookie(persistence, expires, domain); if ( encodedCookiesWithExpirationAndPath.length > maxCookieSize @@ -657,29 +651,29 @@ export default function _Persistence(mpInstance) { } } // Comment 2b above - for (var i = 0; i < currentSessionMPIDs.length; i++) { + for (let i = 0; i < currentSessionMPIDs.length; i++) { encodedCookiesWithExpirationAndPath = createFullEncodedCookie( persistence, expires, - domain + domain, ); if ( encodedCookiesWithExpirationAndPath.length > maxCookieSize ) { - var MPIDtoRemove = currentSessionMPIDs[i]; + const MPIDtoRemove = currentSessionMPIDs[i]; if (persistence[MPIDtoRemove]) { mpInstance.Logger.verbose( 'Size of new encoded cookie is larger than maxCookieSize setting of ' + maxCookieSize + '. Removing from cookie the earliest logged in MPID containing: ' + - JSON.stringify(persistence[MPIDtoRemove], 0, 2) + JSON.stringify(persistence[MPIDtoRemove], 0, 2), ); delete persistence[MPIDtoRemove]; } else { mpInstance.Logger.error( 'Unable to save MPID data to cookies because the resulting encoded cookie is larger than the maxCookieSize setting of ' + maxCookieSize + - '. We recommend using a maxCookieSize of 1500.' + '. We recommend using a maxCookieSize of 1500.', ); } } else { @@ -701,19 +695,19 @@ export default function _Persistence(mpInstance) { ); } - this.findPrevCookiesBasedOnUI = function(identityApiData) { - var persistence = mpInstance._Persistence.getPersistence(); - var matchedUser; + this.findPrevCookiesBasedOnUI = function (identityApiData) { + const persistence = mpInstance._Persistence.getPersistence(); + let matchedUser; if (identityApiData) { - for (var requestedIdentityType in identityApiData.userIdentities) { + for (const requestedIdentityType in identityApiData.userIdentities) { if (persistence && Object.keys(persistence).length) { - for (var key in persistence) { + for (const key in persistence) { // any value in persistence that has an MPID key will be an MPID to search through // other keys on the cookie are currentSessionMPIDs and currentMPID which should not be searched if (persistence[key].mpid) { - var cookieUIs = persistence[key].ui; - for (var cookieUIType in cookieUIs) { + const cookieUIs = persistence[key].ui; + for (const cookieUIType in cookieUIs) { if ( requestedIdentityType === cookieUIType && identityApiData.userIdentities[ @@ -735,7 +729,7 @@ export default function _Persistence(mpInstance) { } }; - this.encodePersistence = function(persistence) { + this.encodePersistence = function (persistence) { persistence = JSON.parse(persistence); for (var key in persistence.gs) { if (persistence.gs.hasOwnProperty(key)) { @@ -746,12 +740,12 @@ export default function _Persistence(mpInstance) { (Array.isArray(persistence.gs[key]) && persistence.gs[key].length) || (mpInstance._Helpers.isObject( - persistence.gs[key] + persistence.gs[key], ) && Object.keys(persistence.gs[key]).length) ) { persistence.gs[key] = Base64.encode( - JSON.stringify(persistence.gs[key]) + JSON.stringify(persistence.gs[key]), ); } else { delete persistence.gs[key]; @@ -767,7 +761,7 @@ export default function _Persistence(mpInstance) { } } - for (var mpid in persistence) { + for (const mpid in persistence) { if (persistence.hasOwnProperty(mpid)) { if (!SDKv2NonMPIDCookieKeys[mpid]) { for (key in persistence[mpid]) { @@ -775,12 +769,12 @@ export default function _Persistence(mpInstance) { if (Base64CookieKeys[key]) { if ( mpInstance._Helpers.isObject( - persistence[mpid][key] + persistence[mpid][key], ) && Object.keys(persistence[mpid][key]).length ) { persistence[mpid][key] = Base64.encode( - JSON.stringify(persistence[mpid][key]) + JSON.stringify(persistence[mpid][key]), ); } else { delete persistence[mpid][key]; @@ -797,7 +791,7 @@ export default function _Persistence(mpInstance) { // TODO: This should actually be decodePersistenceString or // we should refactor this to take a string and return an object - this.decodePersistence = function(persistence) { + this.decodePersistence = function (persistence) { try { if (persistence) { persistence = JSON.parse(Utils.revertCookieString(persistence)); @@ -809,30 +803,31 @@ export default function _Persistence(mpInstance) { if (persistence.gs.hasOwnProperty(key)) { if (Base64CookieKeys[key]) { persistence.gs[key] = JSON.parse( - Base64.decode(persistence.gs[key]) + Base64.decode(persistence.gs[key]), ); } else if (key === 'ie') { persistence.gs[key] = Boolean( - persistence.gs[key] + persistence.gs[key], ); } } } - for (var mpid in persistence) { + for (const mpid in persistence) { if (persistence.hasOwnProperty(mpid)) { if (!SDKv2NonMPIDCookieKeys[mpid]) { for (key in persistence[mpid]) { if (persistence[mpid].hasOwnProperty(key)) { if (Base64CookieKeys[key]) { if (persistence[mpid][key].length) { - persistence[mpid][ - key - ] = JSON.parse( - Base64.decode( - persistence[mpid][key] - ) - ); + persistence[mpid][key] = + JSON.parse( + Base64.decode( + persistence[mpid][ + key + ], + ), + ); } } } @@ -851,11 +846,11 @@ export default function _Persistence(mpInstance) { } }; - this.getCookieDomain = function() { + this.getCookieDomain = function () { if (mpInstance._Store.SDKConfig.cookieDomain) { return mpInstance._Store.SDKConfig.cookieDomain; } else { - var rootDomain = self.getDomain(document, location.hostname); + const rootDomain = self.getDomain(document, location.hostname); if (rootDomain === '') { return ''; } else { @@ -869,8 +864,8 @@ export default function _Persistence(mpInstance) { // "co.uk" -> fail // "domain.co.uk" -> success, return // "subdomain.domain.co.uk" -> skipped, because already found - this.getDomain = function(doc, locationHostname) { - var i, + this.getDomain = function (doc, locationHostname) { + let i, testParts, mpTest = 'mptest=cookie', hostname = locationHostname.split('.'); @@ -889,10 +884,10 @@ export default function _Persistence(mpInstance) { return ''; }; - this.getCartProducts = function(mpid) { - var allCartProducts, + this.getCartProducts = function (mpid) { + let allCartProducts, cartProductsString = localStorage.getItem( - mpInstance._Store.prodStorageName + mpInstance._Store.prodStorageName, ); if (cartProductsString) { allCartProducts = JSON.parse(Base64.decode(cartProductsString)); @@ -908,7 +903,7 @@ export default function _Persistence(mpInstance) { return []; }; - this.setCartProducts = function(allProducts) { + this.setCartProducts = function (allProducts) { if (!mpInstance._Store.isLocalStorageAvailable) { return; } @@ -916,18 +911,18 @@ export default function _Persistence(mpInstance) { try { window.localStorage.setItem( encodeURIComponent(mpInstance._Store.prodStorageName), - Base64.encode(JSON.stringify(allProducts)) + Base64.encode(JSON.stringify(allProducts)), ); } catch (e) { mpInstance.Logger.error( - 'Error with setting products on localStorage.' + 'Error with setting products on localStorage.', ); } }; - this.saveUserCookieSyncDatesToPersistence = function(mpid, csd) { + this.saveUserCookieSyncDatesToPersistence = function (mpid, csd) { if (csd) { - var persistence = self.getPersistence(); + const persistence = self.getPersistence(); if (persistence) { if (persistence[mpid]) { persistence[mpid].csd = csd; @@ -941,13 +936,13 @@ export default function _Persistence(mpInstance) { } }; - this.swapCurrentUser = function( + this.swapCurrentUser = function ( previousMPID, currentMPID, - currentSessionMPIDs + currentSessionMPIDs, ) { if (previousMPID && currentMPID && previousMPID !== currentMPID) { - var persistence = self.getPersistence(); + const persistence = self.getPersistence(); if (persistence) { persistence.cu = currentMPID; persistence.gs.csm = currentSessionMPIDs; @@ -957,9 +952,9 @@ export default function _Persistence(mpInstance) { }; // https://go.mparticle.com/work/SQDSDKS-6021 - this.savePersistence = function(persistence) { - var encodedPersistence = self.encodePersistence( - JSON.stringify(persistence) + this.savePersistence = function (persistence) { + let encodedPersistence = self.encodePersistence( + JSON.stringify(persistence), ), date = new Date(), key = mpInstance._Store.storageName, @@ -969,7 +964,7 @@ export default function _Persistence(mpInstance) { 24 * 60 * 60 * - 1000 + 1000, ).toGMTString(), cookieDomain = self.getCookieDomain(), domain; @@ -981,12 +976,13 @@ export default function _Persistence(mpInstance) { } if (mpInstance._Store.SDKConfig.useCookieStorage) { - var encodedCookiesWithExpirationAndPath = self.reduceAndEncodePersistence( - persistence, - expires, - domain, - mpInstance._Store.SDKConfig.maxCookieSize - ); + const encodedCookiesWithExpirationAndPath = + self.reduceAndEncodePersistence( + persistence, + expires, + domain, + mpInstance._Store.SDKConfig.maxCookieSize, + ); window.document.cookie = encodeURIComponent(key) + '=' + @@ -995,25 +991,25 @@ export default function _Persistence(mpInstance) { if (mpInstance._Store.isLocalStorageAvailable) { localStorage.setItem( mpInstance._Store.storageName, - encodedPersistence + encodedPersistence, ); } } }; - this.getPersistence = function() { - var persistence = this.useLocalStorage() + this.getPersistence = function () { + const persistence = this.useLocalStorage() ? this.getLocalStorage() : this.getCookie(); return persistence; }; - this.getFirstSeenTime = function(mpid) { + this.getFirstSeenTime = function (mpid) { if (!mpid) { return null; } - var persistence = self.getPersistence(); + const persistence = self.getPersistence(); if (persistence && persistence[mpid] && persistence[mpid].fst) { return persistence[mpid].fst; } else { @@ -1025,7 +1021,7 @@ export default function _Persistence(mpInstance) { * set the "first seen" time for a user. the time will only be set once for a given * mpid after which subsequent calls will be ignored */ - this.setFirstSeenTime = function(mpid, time) { + this.setFirstSeenTime = function (mpid, time) { if (!mpid) { return; } @@ -1033,7 +1029,7 @@ export default function _Persistence(mpInstance) { if (!time) { time = new Date().getTime(); } - var persistence = self.getPersistence(); + const persistence = self.getPersistence(); if (persistence) { if (!persistence[mpid]) { persistence[mpid] = {}; @@ -1050,7 +1046,7 @@ export default function _Persistence(mpInstance) { * return value will always be the current time, otherwise it will be to stored "last seen" * time */ - this.getLastSeenTime = function(mpid) { + this.getLastSeenTime = function (mpid) { if (!mpid) { return null; } @@ -1058,7 +1054,7 @@ export default function _Persistence(mpInstance) { //if the mpid is the current user, its last seen time is the current time return new Date().getTime(); } else { - var persistence = self.getPersistence(); + const persistence = self.getPersistence(); if (persistence && persistence[mpid] && persistence[mpid].lst) { return persistence[mpid].lst; } @@ -1066,7 +1062,7 @@ export default function _Persistence(mpInstance) { } }; - this.setLastSeenTime = function(mpid, time) { + this.setLastSeenTime = function (mpid, time) { if (!mpid) { return; } @@ -1074,23 +1070,23 @@ export default function _Persistence(mpInstance) { if (!time) { time = new Date().getTime(); } - var persistence = self.getPersistence(); + const persistence = self.getPersistence(); if (persistence && persistence[mpid]) { persistence[mpid].lst = time; self.savePersistence(persistence); } }; - this.getDeviceId = function() { + this.getDeviceId = function () { return mpInstance._Store.deviceId; }; - this.setDeviceId = function(guid) { + this.setDeviceId = function (guid) { mpInstance._Store.deviceId = guid; self.update(); }; - this.resetPersistence = function() { + this.resetPersistence = function () { removeLocalStorage(StorageNames.localStorageName); removeLocalStorage(StorageNames.localStorageNameV3); removeLocalStorage(StorageNames.localStorageNameV4); @@ -1106,15 +1102,17 @@ export default function _Persistence(mpInstance) { self.expireCookies(mpInstance._Store.storageName); if (mParticle._isTestEnv) { - var testWorkspaceToken = 'abcdef'; + const testWorkspaceToken = 'abcdef'; removeLocalStorage( - mpInstance._Helpers.createMainStorageName(testWorkspaceToken) + mpInstance._Helpers.createMainStorageName(testWorkspaceToken), ); self.expireCookies( - mpInstance._Helpers.createMainStorageName(testWorkspaceToken) + mpInstance._Helpers.createMainStorageName(testWorkspaceToken), ); removeLocalStorage( - mpInstance._Helpers.createProductStorageName(testWorkspaceToken) + mpInstance._Helpers.createProductStorageName( + testWorkspaceToken, + ), ); } }; diff --git a/src/polyfill.js b/src/polyfill.js index 318d3b7c0..417ac38ad 100644 --- a/src/polyfill.js +++ b/src/polyfill.js @@ -16,9 +16,9 @@ var Base64 = { }, _encode: function _encode(input) { - var output = ''; - var chr1, chr2, chr3, enc1, enc2, enc3, enc4; - var i = 0; + let output = ''; + let chr1, chr2, chr3, enc1, enc2, enc3, enc4; + let i = 0; input = UTF8.encode(input); @@ -60,10 +60,10 @@ var Base64 = { }, _decode: function _decode(input) { - var output = ''; - var chr1, chr2, chr3; - var enc1, enc2, enc3, enc4; - var i = 0; + let output = ''; + let chr1, chr2, chr3; + let enc1, enc2, enc3, enc4; + let i = 0; input = input.replace(/[^A-Za-z0-9\+\/\=]/g, ''); @@ -93,10 +93,10 @@ var Base64 = { var UTF8 = { encode: function encode(s) { - var utftext = ''; + let utftext = ''; - for (var n = 0; n < s.length; n++) { - var c = s.charCodeAt(n); + for (let n = 0; n < s.length; n++) { + const c = s.charCodeAt(n); if (c < 128) { utftext += String.fromCharCode(c); @@ -113,9 +113,9 @@ var UTF8 = { }, decode: function decode(utftext) { - var s = ''; - var i = 0; - var c = 0, + let s = ''; + let i = 0; + let c = 0, c1 = 0, c2 = 0; @@ -132,7 +132,7 @@ var UTF8 = { c1 = utftext.charCodeAt(i + 1); c2 = utftext.charCodeAt(i + 2); s += String.fromCharCode( - ((c & 15) << 12) | ((c1 & 63) << 6) | (c2 & 63) + ((c & 15) << 12) | ((c1 & 63) << 6) | (c2 & 63), ); i += 3; } @@ -145,15 +145,15 @@ export default { // forEach polyfill // Production steps of ECMA-262, Edition 5, 15.4.4.18 // Reference: http://es5.github.io/#x15.4.4.18 - forEach: function(callback, thisArg) { - var T, k; + forEach: function (callback, thisArg) { + let T, k; if (this == null) { throw new TypeError(' this is null or not defined'); } - var O = Object(this); - var len = O.length >>> 0; + const O = Object(this); + const len = O.length >>> 0; if (typeof callback !== 'function') { throw new TypeError(callback + ' is not a function'); @@ -178,15 +178,15 @@ export default { // map polyfill // Production steps of ECMA-262, Edition 5, 15.4.4.19 // Reference: http://es5.github.io/#x15.4.4.19 - map: function(callback, thisArg) { - var T, A, k; + map: function (callback, thisArg) { + let T, A, k; if (this === null) { throw new TypeError(' this is null or not defined'); } - var O = Object(this); - var len = O.length >>> 0; + const O = Object(this); + const len = O.length >>> 0; if (typeof callback !== 'function') { throw new TypeError(callback + ' is not a function'); @@ -216,24 +216,24 @@ export default { // filter polyfill // Prodcution steps of ECMA-262, Edition 5 // Reference: http://es5.github.io/#x15.4.4.20 - filter: function(fun /*, thisArg*/) { + filter: function (fun /*, thisArg*/) { 'use strict'; if (this === void 0 || this === null) { throw new TypeError(); } - var t = Object(this); - var len = t.length >>> 0; + const t = Object(this); + const len = t.length >>> 0; if (typeof fun !== 'function') { throw new TypeError(); } - var res = []; - var thisArg = arguments.length >= 2 ? arguments[1] : void 0; - for (var i = 0; i < len; i++) { + const res = []; + const thisArg = arguments.length >= 2 ? arguments[1] : void 0; + for (let i = 0; i < len; i++) { if (i in t) { - var val = t[i]; + const val = t[i]; if (fun.call(thisArg, val, i, t)) { res.push(val); } @@ -244,7 +244,7 @@ export default { }, // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/isArray - isArray: function(arg) { + isArray: function (arg) { return Object.prototype.toString.call(arg) === '[object Array]'; }, diff --git a/src/pre-init-utils.ts b/src/pre-init-utils.ts index c734457e1..4e02bc06c 100644 --- a/src/pre-init-utils.ts +++ b/src/pre-init-utils.ts @@ -13,7 +13,7 @@ export interface IPreInit { export const processReadyQueue = (readyQueue): Function[] => { if (!isEmpty(readyQueue)) { - readyQueue.forEach(readyQueueItem => { + readyQueue.forEach((readyQueueItem) => { if (isFunction(readyQueueItem)) { readyQueueItem(); } else if (Array.isArray(readyQueueItem)) { @@ -29,7 +29,11 @@ const processPreloadedItem = (readyQueueItem): void => { const method = args.splice(0, 1)[0]; // if the first argument is a method on the base mParticle object, run it - if (typeof window !== 'undefined' && window.mParticle && window.mParticle[args[0]]) { + if ( + typeof window !== 'undefined' && + window.mParticle && + window.mParticle[args[0]] + ) { window.mParticle[method].apply(window.mParticle, args); // otherwise, the method is on either eCommerce or Identity objects, ie. "eCommerce.setCurrencyCode", "Identity.login" } else { @@ -37,15 +41,15 @@ const processPreloadedItem = (readyQueueItem): void => { try { let computedMPFunction = window.mParticle; let context = window.mParticle; - + // Track both the function and its context for (const currentMethod of methodArray) { - context = computedMPFunction; // Keep track of the parent object + context = computedMPFunction; // Keep track of the parent object computedMPFunction = computedMPFunction[currentMethod]; } - + // Apply the function with its proper context - ((computedMPFunction as unknown) as Function).apply(context, args); + (computedMPFunction as unknown as Function).apply(context, args); } catch (e) { throw new Error('Unable to compute proper mParticle function ' + e); } diff --git a/src/roktManager.ts b/src/roktManager.ts index 43f3a219d..a4b6d5d14 100644 --- a/src/roktManager.ts +++ b/src/roktManager.ts @@ -1,10 +1,10 @@ -import { IKitConfigs } from "./configAPIClient"; -import { UserAttributeFilters } from "./forwarders.interfaces"; -import { IMParticleUser } from "./identity-user-interfaces"; -import KitFilterHelper from "./kitFilterHelper"; -import { Dictionary, parseSettingsString } from "./utils"; -import { SDKIdentityApi } from "./identity.interfaces"; -import { SDKLoggerApi } from "./sdkRuntimeModels"; +import { IKitConfigs } from './configAPIClient'; +import { UserAttributeFilters } from './forwarders.interfaces'; +import { IMParticleUser } from './identity-user-interfaces'; +import KitFilterHelper from './kitFilterHelper'; +import { Dictionary, parseSettingsString } from './utils'; +import { SDKIdentityApi } from './identity.interfaces'; +import { SDKLoggerApi } from './sdkRuntimeModels'; // https://docs.rokt.com/developers/integration-guides/web/library/attributes export interface IRoktPartnerAttributes { @@ -29,8 +29,12 @@ export interface IRoktSelection { } export interface IRoktLauncher { - selectPlacements: (options: IRoktSelectPlacementsOptions) => Promise; - hashAttributes: (attributes: IRoktPartnerAttributes) => Promise>; + selectPlacements: ( + options: IRoktSelectPlacementsOptions, + ) => Promise; + hashAttributes: ( + attributes: IRoktPartnerAttributes, + ) => Promise>; } export interface IRoktMessage { @@ -40,7 +44,10 @@ export interface IRoktMessage { export interface RoktKitFilterSettings { userAttributeFilters?: UserAttributeFilters; - filterUserAttributes?: (userAttributes: Dictionary, filterList: number[]) => Dictionary; + filterUserAttributes?: ( + userAttributes: Dictionary, + filterList: number[], + ) => Dictionary; filteredUser?: IMParticleUser | null; } @@ -49,8 +56,12 @@ export interface IRoktKit { filteredUser: IMParticleUser | null; launcher: IRoktLauncher | null; userAttributes: Dictionary; - hashAttributes: (attributes: IRoktPartnerAttributes) => Promise>; - selectPlacements: (options: IRoktSelectPlacementsOptions) => Promise; + hashAttributes: ( + attributes: IRoktPartnerAttributes, + ) => Promise>; + selectPlacements: ( + options: IRoktSelectPlacementsOptions, + ) => Promise; setExtensionData(extensionData: IRoktPartnerExtensionData): void; launcherOptions?: Dictionary; } @@ -83,29 +94,34 @@ export default class RoktManager { private logger: SDKLoggerApi; /** * Initializes the RoktManager with configuration settings and user data. - * + * * @param {IKitConfigs} roktConfig - Configuration object containing user attribute filters and settings * @param {IMParticleUser} filteredUser - User object with filtered attributes * @param {SDKIdentityApi} identityService - The mParticle Identity instance * @param {SDKLoggerApi} logger - The mParticle Logger instance * @param {IRoktOptions} options - Options for the RoktManager - * + * * @throws Logs error to console if placementAttributesMapping parsing fails */ public init( - roktConfig: IKitConfigs, - filteredUser: IMParticleUser, + roktConfig: IKitConfigs, + filteredUser: IMParticleUser, identityService: SDKIdentityApi, logger?: SDKLoggerApi, - options?: IRoktOptions + options?: IRoktOptions, ): void { const { userAttributeFilters, settings } = roktConfig || {}; const { placementAttributesMapping } = settings || {}; try { - this.placementAttributesMapping = parseSettingsString(placementAttributesMapping); + this.placementAttributesMapping = parseSettingsString( + placementAttributesMapping, + ); } catch (error) { - console.error('Error parsing placement attributes mapping from config', error); + console.error( + 'Error parsing placement attributes mapping from config', + error, + ); } this.identityService = identityService; @@ -135,10 +151,10 @@ export default class RoktManager { /** * Renders ads based on the options provided - * + * * @param {IRoktSelectPlacementsOptions} options - The options for selecting placements, including attributes and optional identifier * @returns {Promise} A promise that resolves to the selection - * + * * @example * // Correct usage with await * await window.mParticle.Rokt.selectPlacements({ @@ -148,7 +164,9 @@ export default class RoktManager { * } * }); */ - public async selectPlacements(options: IRoktSelectPlacementsOptions): Promise { + public async selectPlacements( + options: IRoktSelectPlacementsOptions, + ): Promise { if (!this.isReady()) { this.queueMessage({ methodName: 'selectPlacements', @@ -160,11 +178,15 @@ export default class RoktManager { try { const { attributes } = options; const sandboxValue = attributes?.sandbox || null; - const mappedAttributes = this.mapPlacementAttributes(attributes, this.placementAttributesMapping); + const mappedAttributes = this.mapPlacementAttributes( + attributes, + this.placementAttributesMapping, + ); // Get current user identities this.currentUser = this.identityService.getCurrentUser(); - const currentUserIdentities = this.currentUser?.getUserIdentities()?.userIdentities || {}; + const currentUserIdentities = + this.currentUser?.getUserIdentities()?.userIdentities || {}; const currentEmail = currentUserIdentities.email; const newEmail = mappedAttributes.email as string; @@ -172,23 +194,31 @@ export default class RoktManager { // Check if email exists and differs if (newEmail && (!currentEmail || currentEmail !== newEmail)) { if (currentEmail && currentEmail !== newEmail) { - this.logger.warning(`Email mismatch detected. Current email, ${currentEmail} differs from email passed to selectPlacements call, ${newEmail}. Proceeding to call identify with ${newEmail}. Please verify your implementation.`); + this.logger.warning( + `Email mismatch detected. Current email, ${currentEmail} differs from email passed to selectPlacements call, ${newEmail}. Proceeding to call identify with ${newEmail}. Please verify your implementation.`, + ); } // Call identify with the new user identities try { await new Promise((resolve, reject) => { - this.identityService.identify({ - userIdentities: { - ...currentUserIdentities, - email: newEmail - } - }, () => { - resolve(); - }); + this.identityService.identify( + { + userIdentities: { + ...currentUserIdentities, + email: newEmail, + }, + }, + () => { + resolve(); + }, + ); }); } catch (error) { - this.logger.error('Failed to identify user with new email: ' + JSON.stringify(error)); + this.logger.error( + 'Failed to identify user with new email: ' + + JSON.stringify(error), + ); } } @@ -206,11 +236,17 @@ export default class RoktManager { return this.kit.selectPlacements(enrichedOptions); } catch (error) { - return Promise.reject(error instanceof Error ? error : new Error('Unknown error occurred')); + return Promise.reject( + error instanceof Error + ? error + : new Error('Unknown error occurred'), + ); } } - public hashAttributes(attributes: IRoktPartnerAttributes): Promise> { + public hashAttributes( + attributes: IRoktPartnerAttributes, + ): Promise> { if (!this.isReady()) { this.queueMessage({ methodName: 'hashAttributes', @@ -222,11 +258,17 @@ export default class RoktManager { try { return this.kit.hashAttributes(attributes); } catch (error) { - return Promise.reject(error instanceof Error ? error : new Error('Unknown error occurred')); + return Promise.reject( + error instanceof Error + ? error + : new Error('Unknown error occurred'), + ); } } - public setExtensionData(extensionData: IRoktPartnerExtensionData): void { + public setExtensionData( + extensionData: IRoktPartnerExtensionData, + ): void { if (!this.isReady()) { this.queueMessage({ methodName: 'setExtensionData', @@ -238,7 +280,8 @@ export default class RoktManager { try { this.kit.setExtensionData(extensionData); } catch (error) { - const errorMessage = error instanceof Error ? error.message : String(error); + const errorMessage = + error instanceof Error ? error.message : String(error); throw new Error('Error setting extension data: ' + errorMessage); } } @@ -251,9 +294,12 @@ export default class RoktManager { private setUserAttributes(attributes: IRoktPartnerAttributes): void { const reservedAttributes = ['sandbox']; const filteredAttributes = {}; - + for (const key in attributes) { - if (attributes.hasOwnProperty(key) && reservedAttributes.indexOf(key) === -1) { + if ( + attributes.hasOwnProperty(key) && + reservedAttributes.indexOf(key) === -1 + ) { filteredAttributes[key] = attributes[key]; } } @@ -265,12 +311,15 @@ export default class RoktManager { } } - private mapPlacementAttributes(attributes: IRoktPartnerAttributes, placementAttributesMapping: Dictionary[]): IRoktPartnerAttributes { + private mapPlacementAttributes( + attributes: IRoktPartnerAttributes, + placementAttributesMapping: Dictionary[], + ): IRoktPartnerAttributes { const mappingLookup: { [key: string]: string } = {}; for (const mapping of placementAttributesMapping) { mappingLookup[mapping.map] = mapping.value; } - + const mappedAttributes: IRoktPartnerAttributes = {}; for (const key in attributes) { if (attributes.hasOwnProperty(key)) { @@ -285,7 +334,9 @@ export default class RoktManager { if (this.messageQueue.length > 0 && this.isReady()) { this.messageQueue.forEach(async (message) => { if (this.kit && message.methodName in this.kit) { - await (this.kit[message.methodName] as Function)(message.payload); + await (this.kit[message.methodName] as Function)( + message.payload, + ); } }); this.messageQueue = []; diff --git a/src/sdkRuntimeModels.ts b/src/sdkRuntimeModels.ts index eb1eb3d2e..f4cecf4f4 100644 --- a/src/sdkRuntimeModels.ts +++ b/src/sdkRuntimeModels.ts @@ -7,18 +7,24 @@ import { SDKEventAttrs, Callback, } from '@mparticle/web-sdk'; -import { IntegrationAttribute, IntegrationAttributes, IStore, WrapperSDKTypes } from './store'; +import { + IntegrationAttribute, + IntegrationAttributes, + IStore, + WrapperSDKTypes, +} from './store'; import Validators from './validators'; import { Dictionary, valueof } from './utils'; import { IKitConfigs } from './configAPIClient'; import { SDKConsentApi, SDKConsentState } from './consent'; import MPSideloadedKit from './sideloadedKit'; import { ISessionManager } from './sessionManager'; -import { ConfiguredKit, MPForwarder, UnregisteredKit } from './forwarders.interfaces'; import { - SDKIdentityApi, - IAliasCallback, -} from './identity.interfaces'; + ConfiguredKit, + MPForwarder, + UnregisteredKit, +} from './forwarders.interfaces'; +import { SDKIdentityApi, IAliasCallback } from './identity.interfaces'; import { ISDKUserAttributeChangeData, ISDKUserIdentityChanges, @@ -36,8 +42,12 @@ import { } from './types'; import { IPixelConfiguration } from './cookieSyncManager'; import _BatchValidator from './mockBatchCreator'; -import { SDKECommerceAPI } from './ecommerce.interfaces'; -import { IErrorLogMessage, IMParticleWebSDKInstance, IntegrationDelays } from './mp-instance'; +import { SDKECommerceAPI } from './ecommerce.interfaces'; +import { + IErrorLogMessage, + IMParticleWebSDKInstance, + IntegrationDelays, +} from './mp-instance'; import Constants from './constants'; import RoktManager, { IRoktLauncherOptions } from './roktManager'; @@ -202,13 +212,28 @@ export interface MParticleWebSDK { eventType?: valueof, attrs?: SDKEventAttrs, customFlags?: SDKEventCustomFlags, - eventOptions?: SDKEventOptions + eventOptions?: SDKEventOptions, ): void; logBaseEvent(event: BaseEvent, eventOptions?: SDKEventOptions): void; logError(error: IErrorLogMessage, attrs?: SDKEventAttrs): void; - logLink(selector: string, eventName: string, eventType: valueof, eventInfo: SDKEventAttrs): void; - logForm(selector: string, eventName: string, eventType: valueof, eventInfo: SDKEventAttrs): void; - logPageView(eventName?: string, attrs?: SDKEventAttrs, customFlags?: SDKEventCustomFlags, eventOptions?: SDKEventOptions): void; + logLink( + selector: string, + eventName: string, + eventType: valueof, + eventInfo: SDKEventAttrs, + ): void; + logForm( + selector: string, + eventName: string, + eventType: valueof, + eventInfo: SDKEventAttrs, + ): void; + logPageView( + eventName?: string, + attrs?: SDKEventAttrs, + customFlags?: SDKEventCustomFlags, + eventOptions?: SDKEventOptions, + ): void; setOptOut(isOptingOut: boolean): void; eCommerce: SDKECommerceAPI; isInitialized(): boolean; @@ -226,7 +251,10 @@ export interface MParticleWebSDK { stopTrackingLocation(): void; generateHash(value: string): string; - setIntegrationAttribute(integrationModuleId: number, attrs: IntegrationAttribute): void; + setIntegrationAttribute( + integrationModuleId: number, + attrs: IntegrationAttribute, + ): void; getIntegrationAttributes(integrationModuleId: number): IntegrationAttribute; } @@ -246,14 +274,13 @@ export interface IMParticleInstanceManager extends MParticleWebSDK { MPSideloadedKit: typeof MPSideloadedKit; Rokt: RoktManager; // https://go.mparticle.com/work/SQDSDKS-7060 - sessionManager: Pick; + sessionManager: Pick; Store: IStore; // Public Methods getInstance(instanceName?: string): IMParticleWebSDKInstance; } - // Used in cases where server requires booleans as strings export type BooleanStringLowerCase = 'false' | 'true'; export type BooleanStringTitleCase = 'False' | 'True'; @@ -329,12 +356,12 @@ export interface SDKHelpersApi { invokeAliasCallback( aliasCallback: IAliasCallback, number: number, - errorMessage: string + errorMessage: string, ): void; isDelayedByIntegration?( delayedIntegrations: Dictionary, timeoutStart: number, - now: number + now: number, ): boolean; isEventType?(type: valueof): boolean; isObject?(item: any); @@ -343,11 +370,11 @@ export interface SDKHelpersApi { code: number, body: string, mParticleUser?: IMParticleUser, - previousMpid?: MPID + previousMpid?: MPID, ): void; sanitizeAttributes?( attrs: SDKEventAttrs, - name: string + name: string, ): Dictionary | null; Validators: typeof Validators; } diff --git a/src/sdkToEventsApiConverter.ts b/src/sdkToEventsApiConverter.ts index 1bfe59d1e..85fad9379 100644 --- a/src/sdkToEventsApiConverter.ts +++ b/src/sdkToEventsApiConverter.ts @@ -18,12 +18,8 @@ import { SDKIdentityTypeEnum } from './identity.interfaces'; import Constants from './constants'; import { IMParticleWebSDKInstance } from './mp-instance'; -const { - FeatureFlags -} = Constants; -const { - CaptureIntegrationSpecificIds -} = FeatureFlags; +const { FeatureFlags } = Constants; +const { CaptureIntegrationSpecificIds } = FeatureFlags; type PartnerIdentities = Dictionary; @@ -35,7 +31,7 @@ interface Batch extends EventsApi.Batch { export function convertEvents( mpid: string, sdkEvents: SDKEvent[], - mpInstance: IMParticleWebSDKInstance + mpInstance: IMParticleWebSDKInstance, ): Batch | null { if (!mpid) { return null; @@ -44,15 +40,9 @@ export function convertEvents( return null; } - const { - _IntegrationCapture, - _Helpers, - } = mpInstance - - const { - getFeatureFlag, - } = _Helpers; + const { _IntegrationCapture, _Helpers } = mpInstance; + const { getFeatureFlag } = _Helpers; const user = mpInstance.Identity.getCurrentUser(); @@ -128,9 +118,12 @@ export function convertEvents( }; } - const isIntegrationCaptureEnabled: boolean = getFeatureFlag && Boolean(getFeatureFlag(CaptureIntegrationSpecificIds)); + const isIntegrationCaptureEnabled: boolean = + getFeatureFlag && + Boolean(getFeatureFlag(CaptureIntegrationSpecificIds)); if (isIntegrationCaptureEnabled) { - const capturedPartnerIdentities: PartnerIdentities = _IntegrationCapture?.getClickIdsAsPartnerIdentities(); + const capturedPartnerIdentities: PartnerIdentities = + _IntegrationCapture?.getClickIdsAsPartnerIdentities(); if (!isEmpty(capturedPartnerIdentities)) { upload.partner_identities = capturedPartnerIdentities; } @@ -140,7 +133,7 @@ export function convertEvents( } export function convertConsentState( - sdkConsentState?: SDKConsentState + sdkConsentState?: SDKConsentState, ): EventsApi.ConsentState | null { if (isEmpty(sdkConsentState)) { return null; @@ -153,7 +146,7 @@ export function convertConsentState( } export function convertGdprConsentState( - sdkGdprConsentState: SDKGDPRConsentState + sdkGdprConsentState: SDKGDPRConsentState, ): { [key: string]: EventsApi.GDPRConsentState | null } { if (!sdkGdprConsentState) { return null; @@ -174,7 +167,7 @@ export function convertGdprConsentState( } export function convertCcpaConsentState( - sdkCcpaConsentState: SDKCCPAConsentState + sdkCcpaConsentState: SDKCCPAConsentState, ): { data_sale_opt_out: EventsApi.CCPAConsentState } { if (!sdkCcpaConsentState) { return null; @@ -193,7 +186,7 @@ export function convertCcpaConsentState( } export function convertUserIdentities( - sdkUserIdentities?: ISDKUserIdentity[] + sdkUserIdentities?: ISDKUserIdentity[], ): EventsApi.BatchUserIdentities | null { if (!sdkUserIdentities || !sdkUserIdentities.length) { return null; @@ -300,7 +293,7 @@ export function convertEvent(sdkEvent: SDKEvent): EventsApi.BaseEvent | null { } export function convertProductActionType( - actionType: SDKProductActionType + actionType: SDKProductActionType, ): EventsApi.ProductActionActionEnum { if (!actionType) { return EventsApi.ProductActionActionEnum.unknown; @@ -332,14 +325,14 @@ export function convertProductActionType( } export function convertProductAction( - sdkEvent: SDKEvent + sdkEvent: SDKEvent, ): EventsApi.ProductAction | null { if (!sdkEvent.ProductAction) { return null; } const productAction: EventsApi.ProductAction = { action: convertProductActionType( - sdkEvent.ProductAction.ProductActionType + sdkEvent.ProductAction.ProductActionType, ), checkout_step: sdkEvent.ProductAction.CheckoutStep, checkout_options: sdkEvent.ProductAction.CheckoutOptions, @@ -355,7 +348,7 @@ export function convertProductAction( } export function convertProducts( - sdkProducts: SDKProduct[] + sdkProducts: SDKProduct[], ): EventsApi.Product[] | null { if (!sdkProducts || !sdkProducts.length) { return null; @@ -381,7 +374,7 @@ export function convertProducts( } export function convertPromotionAction( - sdkEvent: SDKEvent + sdkEvent: SDKEvent, ): EventsApi.PromotionAction | null { if (!sdkEvent.PromotionAction) { return null; @@ -395,7 +388,7 @@ export function convertPromotionAction( } export function convertPromotions( - sdkPromotions: SDKPromotion[] + sdkPromotions: SDKPromotion[], ): EventsApi.Promotion[] | null { if (!sdkPromotions || !sdkPromotions.length) { return null; @@ -414,7 +407,7 @@ export function convertPromotions( } export function convertImpressions( - sdkEvent: SDKEvent + sdkEvent: SDKEvent, ): EventsApi.ProductImpression[] | null { if (!sdkEvent.ProductImpressions) { return null; @@ -431,7 +424,7 @@ export function convertImpressions( } export function convertShoppingCart( - sdkEvent: SDKEvent + sdkEvent: SDKEvent, ): EventsApi.ShoppingCart | null { if ( !sdkEvent.ShoppingCart || @@ -447,11 +440,10 @@ export function convertShoppingCart( } export function convertCommerceEvent( - sdkEvent: SDKEvent + sdkEvent: SDKEvent, ): EventsApi.CommerceEvent { - const commonEventData: EventsApi.CommonEventData = convertBaseEventData( - sdkEvent - ); + const commonEventData: EventsApi.CommonEventData = + convertBaseEventData(sdkEvent); let commerceEventData: EventsApi.CommerceEventData = { custom_flags: sdkEvent.CustomFlags, product_action: convertProductAction(sdkEvent), @@ -468,11 +460,10 @@ export function convertCommerceEvent( }; } export function convertCrashReportEvent( - sdkEvent: SDKEvent + sdkEvent: SDKEvent, ): EventsApi.CrashReportEvent { - const commonEventData: EventsApi.CommonEventData = convertBaseEventData( - sdkEvent - ); + const commonEventData: EventsApi.CommonEventData = + convertBaseEventData(sdkEvent); let crashReportEventData: EventsApi.CrashReportEventData = { message: sdkEvent.EventName, }; @@ -484,15 +475,17 @@ export function convertCrashReportEvent( } export function convertAST( - sdkEvent: SDKEvent + sdkEvent: SDKEvent, ): EventsApi.ApplicationStateTransitionEvent { - const commonEventData: EventsApi.CommonEventData = convertBaseEventData( - sdkEvent - ); + const commonEventData: EventsApi.CommonEventData = + convertBaseEventData(sdkEvent); // Determine the transition type based on IsBackgroundAST flag - const { applicationBackground, applicationInitialized } = EventsApi.ApplicationStateTransitionEventDataApplicationTransitionTypeEnum; - const transitionType = sdkEvent.IsBackgroundAST ? applicationBackground : applicationInitialized; + const { applicationBackground, applicationInitialized } = + EventsApi.ApplicationStateTransitionEventDataApplicationTransitionTypeEnum; + const transitionType = sdkEvent.IsBackgroundAST + ? applicationBackground + : applicationInitialized; let astEventData: EventsApi.ApplicationStateTransitionEventData = { application_transition_type: transitionType, @@ -508,11 +501,10 @@ export function convertAST( } export function convertSessionEndEvent( - sdkEvent: SDKEvent + sdkEvent: SDKEvent, ): EventsApi.SessionEndEvent { - const commonEventData: EventsApi.CommonEventData = convertBaseEventData( - sdkEvent - ); + const commonEventData: EventsApi.CommonEventData = + convertBaseEventData(sdkEvent); let sessionEndEventData: EventsApi.SessionEndEventData = { session_duration_ms: sdkEvent.SessionLength, //note: External Events DTO does not support the session mpids array as of this time. @@ -526,15 +518,14 @@ export function convertSessionEndEvent( } export function convertSessionStartEvent( - sdkEvent: SDKEvent + sdkEvent: SDKEvent, ): EventsApi.SessionStartEvent { - const commonEventData: EventsApi.CommonEventData = convertBaseEventData( - sdkEvent - ); + const commonEventData: EventsApi.CommonEventData = + convertBaseEventData(sdkEvent); let sessionStartEventData: EventsApi.SessionStartEventData = {}; sessionStartEventData = Object.assign( sessionStartEventData, - commonEventData + commonEventData, ); return { event_type: EventsApi.EventTypeEnum.sessionStart, @@ -543,11 +534,10 @@ export function convertSessionStartEvent( } export function convertPageViewEvent( - sdkEvent: SDKEvent + sdkEvent: SDKEvent, ): EventsApi.ScreenViewEvent { - const commonEventData: EventsApi.CommonEventData = convertBaseEventData( - sdkEvent - ); + const commonEventData: EventsApi.CommonEventData = + convertBaseEventData(sdkEvent); let screenViewEventData: EventsApi.ScreenViewEventData = { custom_flags: sdkEvent.CustomFlags, screen_name: sdkEvent.EventName, @@ -560,9 +550,8 @@ export function convertPageViewEvent( } export function convertOptOutEvent(sdkEvent: SDKEvent): EventsApi.OptOutEvent { - const commonEventData: EventsApi.CommonEventData = convertBaseEventData( - sdkEvent - ); + const commonEventData: EventsApi.CommonEventData = + convertBaseEventData(sdkEvent); let optOutEventData: EventsApi.OptOutEventData = { is_opted_out: sdkEvent.OptOut, }; @@ -574,12 +563,11 @@ export function convertOptOutEvent(sdkEvent: SDKEvent): EventsApi.OptOutEvent { } export function convertCustomEvent(sdkEvent: SDKEvent): EventsApi.CustomEvent { - const commonEventData: EventsApi.CommonEventData = convertBaseEventData( - sdkEvent - ); + const commonEventData: EventsApi.CommonEventData = + convertBaseEventData(sdkEvent); let customEventData: EventsApi.CustomEventData = { custom_event_type: convertSdkEventType( - sdkEvent.EventCategory + sdkEvent.EventCategory, ) as EventsApi.CustomEventDataCustomEventTypeEnum, custom_flags: sdkEvent.CustomFlags, event_name: sdkEvent.EventName, @@ -592,7 +580,7 @@ export function convertCustomEvent(sdkEvent: SDKEvent): EventsApi.CustomEvent { } export function convertSdkEventType( - sdkEventType: number + sdkEventType: number, ): | EventsApi.CustomEventDataCustomEventTypeEnum | EventsApi.CommerceEventDataCustomEventTypeEnum { @@ -651,7 +639,7 @@ export function convertSdkEventType( } } export function convertBaseEventData( - sdkEvent: SDKEvent + sdkEvent: SDKEvent, ): EventsApi.CommonEventData { const commonEventData: EventsApi.CommonEventData = { timestamp_unixtime_ms: sdkEvent.Timestamp, @@ -660,14 +648,14 @@ export function convertBaseEventData( custom_attributes: sdkEvent.EventAttributes, location: convertSDKLocation(sdkEvent.Location), source_message_id: sdkEvent.SourceMessageId, - active_time_on_site_ms: sdkEvent.ActiveTimeOnSite + active_time_on_site_ms: sdkEvent.ActiveTimeOnSite, }; return commonEventData; } export function convertSDKLocation( - sdkEventLocation: SDKGeoLocation + sdkEventLocation: SDKGeoLocation, ): EventsApi.GeoLocation { if (sdkEventLocation && Object.keys(sdkEventLocation).length) { return { @@ -679,11 +667,10 @@ export function convertSDKLocation( } export function convertUserAttributeChangeEvent( - sdkEvent: SDKEvent + sdkEvent: SDKEvent, ): EventsApi.UserAttributeChangeEvent | null { - const commonEventData: EventsApi.CommonEventData = convertBaseEventData( - sdkEvent - ); + const commonEventData: EventsApi.CommonEventData = + convertBaseEventData(sdkEvent); let userAttributeChangeEvent: EventsApi.UserAttributeChangeEventData = { user_attribute_name: sdkEvent.UserAttributeChanges.UserAttributeName, new: sdkEvent.UserAttributeChanges.New, @@ -704,16 +691,15 @@ export function convertUserAttributeChangeEvent( } export function convertUserIdentityChangeEvent( - sdkEvent: SDKEvent + sdkEvent: SDKEvent, ): EventsApi.UserIdentityChangeEvent | null { - const commonEventData: EventsApi.CommonEventData = convertBaseEventData( - sdkEvent - ); + const commonEventData: EventsApi.CommonEventData = + convertBaseEventData(sdkEvent); let userIdentityChangeEvent: EventsApi.UserIdentityChangeEventData = { new: { identity_type: convertUserIdentityTypeToServerIdentityType( - sdkEvent.UserIdentityChanges.New.IdentityType + sdkEvent.UserIdentityChanges.New.IdentityType, ), identity: sdkEvent.UserIdentityChanges.New.Identity || null, timestamp_unixtime_ms: sdkEvent.Timestamp, @@ -722,7 +708,7 @@ export function convertUserIdentityChangeEvent( }, old: { identity_type: convertUserIdentityTypeToServerIdentityType( - sdkEvent.UserIdentityChanges.Old.IdentityType + sdkEvent.UserIdentityChanges.Old.IdentityType, ), identity: sdkEvent.UserIdentityChanges.Old.Identity || null, timestamp_unixtime_ms: sdkEvent.Timestamp, @@ -733,7 +719,7 @@ export function convertUserIdentityChangeEvent( userIdentityChangeEvent = Object.assign( userIdentityChangeEvent, - commonEventData + commonEventData, ); return { @@ -743,7 +729,7 @@ export function convertUserIdentityChangeEvent( } export function convertUserIdentityTypeToServerIdentityType( - identityType: SDKIdentityTypeEnum + identityType: SDKIdentityTypeEnum, ): EventsApi.IdentityType { switch (identityType) { case SDKIdentityTypeEnum.other: diff --git a/src/serverModel.ts b/src/serverModel.ts index c7cd2c9bd..131e749f9 100644 --- a/src/serverModel.ts +++ b/src/serverModel.ts @@ -145,15 +145,15 @@ export interface IServerModel { // TODO: Make this a pure function that returns a new object function convertCustomFlags(event: SDKEvent, dto: IServerV2DTO) { - var valueArray: string[] = []; + let valueArray: string[] = []; dto.flags = {}; - for (var prop in event.CustomFlags) { + for (const prop in event.CustomFlags) { valueArray = []; if (event.CustomFlags.hasOwnProperty(prop)) { if (Array.isArray(event.CustomFlags[prop])) { - event.CustomFlags[prop].forEach(customFlagProperty => { + event.CustomFlags[prop].forEach((customFlagProperty) => { if (isValidCustomFlagProperty(customFlagProperty)) { valueArray.push(customFlagProperty.toString()); } @@ -190,31 +190,31 @@ function convertProductListToV2DTO(productList: SDKProduct[]): IProductV2DTO[] { return []; } - return productList.map(function(product) { + return productList.map(function (product) { return convertProductToV2DTO(product); }); } export default function ServerModel( this: IServerModel, - mpInstance: IMParticleWebSDKInstance + mpInstance: IMParticleWebSDKInstance, ) { - var self = this; + const self = this; - this.convertToConsentStateV2DTO = function( - state: SDKConsentState + this.convertToConsentStateV2DTO = function ( + state: SDKConsentState, ): IConsentStateV2DTO { if (!state) { return null; } - var jsonObject: IConsentStateV2DTO = {}; - var gdprConsentState = state.getGDPRConsentState(); + const jsonObject: IConsentStateV2DTO = {}; + const gdprConsentState = state.getGDPRConsentState(); if (gdprConsentState) { - var gdpr: IGDPRConsentStateV2DTO = {}; + const gdpr: IGDPRConsentStateV2DTO = {}; jsonObject.gdpr = gdpr; - for (var purpose in gdprConsentState) { + for (const purpose in gdprConsentState) { if (gdprConsentState.hasOwnProperty(purpose)) { - var gdprConsent = gdprConsentState[purpose]; + const gdprConsent = gdprConsentState[purpose]; jsonObject.gdpr[purpose] = {} as IPrivacyV2DTO; if (typeof gdprConsent.Consented === 'boolean') { gdpr[purpose].c = gdprConsent.Consented; @@ -235,7 +235,7 @@ export default function ServerModel( } } - var ccpaConsentState = state.getCCPAConsentState(); + const ccpaConsentState = state.getCCPAConsentState(); if (ccpaConsentState) { jsonObject.ccpa = { data_sale_opt_out: { @@ -251,18 +251,18 @@ export default function ServerModel( return jsonObject as IConsentStateV2DTO; }; - this.createEventObject = function( + this.createEventObject = function ( event: BaseEvent, - user?: IMParticleUser + user?: IMParticleUser, ): SDKEvent | IUploadObject { - var uploadObject: Partial = {}; - var eventObject: Partial = {}; + let uploadObject: Partial = {}; + let eventObject: Partial = {}; // The `optOut` variable is passed later in this method to the `uploadObject` // so that it can be used to denote whether or not a user has "opted out" of being // tracked. If this is an `optOut` Event, we set `optOut` to the inverse of the SDK's // `isEnabled` boolean which is controlled via `MPInstanceManager.setOptOut`. - var optOut = + const optOut = event.messageType === Types.MessageType.OptOut ? !mpInstance._Store.isEnabled : null; @@ -273,20 +273,30 @@ export default function ServerModel( event.messageType === Types.MessageType.OptOut || mpInstance._Store.webviewBridgeEnabled ) { - let customFlags: SDKEventCustomFlags = {...event.customFlags}; - let integrationAttributes: IntegrationAttributes = mpInstance._Store.integrationAttributes; + let customFlags: SDKEventCustomFlags = { ...event.customFlags }; + let integrationAttributes: IntegrationAttributes = + mpInstance._Store.integrationAttributes; // https://go.mparticle.com/work/SQDSDKS-5053 - if (mpInstance._Helpers.getFeatureFlag && mpInstance._Helpers.getFeatureFlag(Constants.FeatureFlags.CaptureIntegrationSpecificIds)) { - + if ( + mpInstance._Helpers.getFeatureFlag && + mpInstance._Helpers.getFeatureFlag( + Constants.FeatureFlags.CaptureIntegrationSpecificIds, + ) + ) { // Attempt to recapture click IDs in case a third party integration // has added or updated new click IDs since the last event was sent. mpInstance._IntegrationCapture.capture(); - const transformedClickIDs = mpInstance._IntegrationCapture.getClickIdsAsCustomFlags(); - customFlags = {...transformedClickIDs, ...customFlags}; - - const transformedIntegrationAttributes = mpInstance._IntegrationCapture.getClickIdsAsIntegrationAttributes(); - integrationAttributes = {...transformedIntegrationAttributes, ...integrationAttributes}; + const transformedClickIDs = + mpInstance._IntegrationCapture.getClickIdsAsCustomFlags(); + customFlags = { ...transformedClickIDs, ...customFlags }; + + const transformedIntegrationAttributes = + mpInstance._IntegrationCapture.getClickIdsAsIntegrationAttributes(); + integrationAttributes = { + ...transformedIntegrationAttributes, + ...integrationAttributes, + }; } if (event.hasOwnProperty('toEventAPIObject')) { @@ -297,14 +307,14 @@ export default function ServerModel( // names are numbers (1, 2, or 10), but going forward with v3, these lifecycle // events do not have names, but are denoted by their `event_type` EventName: - event.name || - ((event.messageType as unknown) as string), + event.name || (event.messageType as unknown as string), EventCategory: event.eventType, EventAttributes: mpInstance._Helpers.sanitizeAttributes( event.data, - event.name + event.name, ), - ActiveTimeOnSite: mpInstance._timeOnSiteTimer?.getTimeInForeground(), + ActiveTimeOnSite: + mpInstance._timeOnSiteTimer?.getTimeInForeground(), SourceMessageId: event.sourceMessageId || mpInstance._Helpers.generateUniqueId(), @@ -337,7 +347,7 @@ export default function ServerModel( Package: mpInstance._Store.SDKConfig.package, ClientGeneratedId: mpInstance._Store.clientId, DeviceId: mpInstance._Store.deviceId, - IntegrationAttributes: integrationAttributes, + IntegrationAttributes: integrationAttributes, CurrencyCode: mpInstance._Store.currencyCode, DataPlan: mpInstance._Store.SDKConfig.dataPlan ? mpInstance._Store.SDKConfig.dataPlan @@ -351,7 +361,7 @@ export default function ServerModel( // FIXME: Remove duplicate occurence eventObject.CurrencyCode = mpInstance._Store.currencyCode; - var currentUser = user || mpInstance.Identity.getCurrentUser(); + const currentUser = user || mpInstance.Identity.getCurrentUser(); appendUserInfo(currentUser, eventObject as SDKEvent); if (event.messageType === Types.MessageType.SessionEnd) { @@ -373,7 +383,8 @@ export default function ServerModel( mpInstance._Store.sessionStartDate = null; } - uploadObject.Timestamp = mpInstance._Store.dateLastEventSent.getTime(); + uploadObject.Timestamp = + mpInstance._Store.dateLastEventSent.getTime(); return mpInstance._Helpers.extend({}, eventObject, uploadObject); } @@ -381,8 +392,8 @@ export default function ServerModel( return null; }; - this.convertEventToV2DTO = function(event: IUploadObject): IServerV2DTO { - var dto: Partial = { + this.convertEventToV2DTO = function (event: IUploadObject): IServerV2DTO { + const dto: Partial = { n: event.EventName, et: event.EventCategory, ua: event.UserAttributes, @@ -414,7 +425,7 @@ export default function ServerModel( } } - var consent = self.convertToConsentStateV2DTO(event.ConsentState); + const consent = self.convertToConsentStateV2DTO(event.ConsentState); if (consent) { dto.con = consent; } @@ -441,7 +452,7 @@ export default function ServerModel( if (event.ShoppingCart) { dto.sc = { pl: convertProductListToV2DTO( - event.ShoppingCart.ProductList + event.ShoppingCart.ProductList, ), }; } @@ -450,41 +461,41 @@ export default function ServerModel( dto.pd = { an: event.ProductAction.ProductActionType, cs: mpInstance._Helpers.parseNumber( - event.ProductAction.CheckoutStep + event.ProductAction.CheckoutStep, ), co: event.ProductAction.CheckoutOptions, pl: convertProductListToV2DTO( - event.ProductAction.ProductList + event.ProductAction.ProductList, ), ti: event.ProductAction.TransactionId, ta: event.ProductAction.Affiliation, tcc: event.ProductAction.CouponCode, tr: mpInstance._Helpers.parseNumber( - event.ProductAction.TotalAmount + event.ProductAction.TotalAmount, ), ts: mpInstance._Helpers.parseNumber( - event.ProductAction.ShippingAmount + event.ProductAction.ShippingAmount, ), tt: mpInstance._Helpers.parseNumber( - event.ProductAction.TaxAmount + event.ProductAction.TaxAmount, ), }; } else if (event.PromotionAction) { dto.pm = { an: event.PromotionAction.PromotionActionType, - pl: event.PromotionAction.PromotionList.map(function( - promotion - ) { - return { - id: promotion.Id, - nm: promotion.Name, - cr: promotion.Creative, - ps: promotion.Position ? promotion.Position : 0, - }; - }), + pl: event.PromotionAction.PromotionList.map( + function (promotion) { + return { + id: promotion.Id, + nm: promotion.Name, + cr: promotion.Creative, + ps: promotion.Position ? promotion.Position : 0, + }; + }, + ), }; } else if (event.ProductImpressions) { - dto.pi = event.ProductImpressions.map(function(impression) { + dto.pi = event.ProductImpressions.map(function (impression) { return { pil: impression.ProductImpressionList, pl: convertProductListToV2DTO(impression.ProductList), diff --git a/src/sessionManager.ts b/src/sessionManager.ts index cf96cfc79..a8f6e9f52 100644 --- a/src/sessionManager.ts +++ b/src/sessionManager.ts @@ -26,11 +26,11 @@ export interface ISessionManager { export default function SessionManager( this: ISessionManager, - mpInstance: IMParticleWebSDKInstance + mpInstance: IMParticleWebSDKInstance, ) { const self = this; - this.initialize = function(): void { + this.initialize = function (): void { if (mpInstance._Store.sessionId) { const sessionTimeoutInMilliseconds: number = mpInstance._Store.SDKConfig.sessionTimeout * 60000; @@ -39,19 +39,20 @@ export default function SessionManager( new Date() > new Date( mpInstance._Store.dateLastEventSent.getTime() + - sessionTimeoutInMilliseconds + sessionTimeoutInMilliseconds, ) ) { self.endSession(); self.startNewSession(); } else { // https://go.mparticle.com/work/SQDSDKS-6045 - const persistence: IPersistenceMinified = mpInstance._Persistence.getPersistence(); + const persistence: IPersistenceMinified = + mpInstance._Persistence.getPersistence(); if (persistence && !persistence.cu) { // https://go.mparticle.com/work/SQDSDKS-6323 mpInstance.Identity.identify( mpInstance._Store.SDKConfig.identifyRequest, - mpInstance._Store.SDKConfig.identityCallback + mpInstance._Store.SDKConfig.identityCallback, ); mpInstance._Store.identifyCalled = true; mpInstance._Store.SDKConfig.identityCallback = null; @@ -62,24 +63,24 @@ export default function SessionManager( } }; - this.getSession = function(): string { + this.getSession = function (): string { mpInstance.Logger.warning( generateDeprecationMessage( 'SessionManager.getSession()', - 'SessionManager.getSessionId()' - ) + 'SessionManager.getSessionId()', + ), ); return this.getSessionId(); }; - this.getSessionId = function(): string { + this.getSessionId = function (): string { return mpInstance._Store.sessionId; }; - this.startNewSession = function(): void { + this.startNewSession = function (): void { mpInstance.Logger.verbose( - Messages.InformationMessages.StartingNewSession + Messages.InformationMessages.StartingNewSession, ); if (mpInstance._Helpers.canLog()) { @@ -87,7 +88,8 @@ export default function SessionManager( .generateUniqueId() .toUpperCase(); - const currentUser: IMParticleUser = mpInstance.Identity.getCurrentUser(); + const currentUser: IMParticleUser = + mpInstance.Identity.getCurrentUser(); const mpid: MPID = currentUser ? currentUser.getMPID() : null; if (mpid) { @@ -105,7 +107,7 @@ export default function SessionManager( if (!mpInstance._Store.identifyCalled) { mpInstance.Identity.identify( mpInstance._Store.SDKConfig.identifyRequest, - mpInstance._Store.SDKConfig.identityCallback + mpInstance._Store.SDKConfig.identityCallback, ); mpInstance._Store.identifyCalled = true; mpInstance._Store.SDKConfig.identityCallback = null; @@ -116,14 +118,14 @@ export default function SessionManager( }); } else { mpInstance.Logger.verbose( - Messages.InformationMessages.AbandonStartSession + Messages.InformationMessages.AbandonStartSession, ); } }; - this.endSession = function(override: boolean): void { + this.endSession = function (override: boolean): void { mpInstance.Logger.verbose( - Messages.InformationMessages.StartingEndSession + Messages.InformationMessages.StartingEndSession, ); if (override) { @@ -142,7 +144,7 @@ export default function SessionManager( // - the devToken is undefined // - webviewBridgeEnabled is set to false mpInstance.Logger.verbose( - Messages.InformationMessages.AbandonEndSession + Messages.InformationMessages.AbandonEndSession, ); mpInstance._timeOnSiteTimer?.resetTimer(); @@ -152,11 +154,12 @@ export default function SessionManager( let sessionTimeoutInMilliseconds: number; let timeSinceLastEventSent: number; - const cookies: IPersistenceMinified = mpInstance._Persistence.getPersistence(); + const cookies: IPersistenceMinified = + mpInstance._Persistence.getPersistence(); - if (!cookies || cookies.gs && !cookies.gs.sid) { + if (!cookies || (cookies.gs && !cookies.gs.sid)) { mpInstance.Logger.verbose( - Messages.InformationMessages.NoSessionToEnd + Messages.InformationMessages.NoSessionToEnd, ); mpInstance._timeOnSiteTimer?.resetTimer(); @@ -189,16 +192,16 @@ export default function SessionManager( mpInstance._timeOnSiteTimer?.resetTimer(); }; - this.setSessionTimer = function(): void { + this.setSessionTimer = function (): void { const sessionTimeoutInMilliseconds: number = mpInstance._Store.SDKConfig.sessionTimeout * 60000; - mpInstance._Store.globalTimer = window.setTimeout(function() { + mpInstance._Store.globalTimer = window.setTimeout(function () { self.endSession(); }, sessionTimeoutInMilliseconds); }; - this.resetSessionTimer = function(): void { + this.resetSessionTimer = function (): void { if (!mpInstance._Store.webviewBridgeEnabled) { if (!mpInstance._Store.sessionId) { self.startNewSession(); @@ -209,7 +212,7 @@ export default function SessionManager( self.startNewSessionIfNeeded(); }; - this.clearSessionTimeout = function(): void { + this.clearSessionTimeout = function (): void { clearTimeout(mpInstance._Store.globalTimer); }; diff --git a/src/sideloadedKit.ts b/src/sideloadedKit.ts index 5bc6d1e63..082b427a3 100644 --- a/src/sideloadedKit.ts +++ b/src/sideloadedKit.ts @@ -14,11 +14,14 @@ export interface IMPSideloadedKit { filterDictionary: IKitFilterSettings; addEventTypeFilter(eventType: valueof): void; - addEventNameFilter(eventType: valueof, eventName: string): void; + addEventNameFilter( + eventType: valueof, + eventName: string, + ): void; addEventAttributeFilter( eventType: valueof, eventName: string, - customAttributeKey: string + customAttributeKey: string, ): void; addScreenNameFilter(screenName: string): void; addScreenAttributeFilter(screenName: string, screenAttribute: string): void; @@ -29,10 +32,10 @@ export interface IMPSideloadedKit { // This constructor is necessary to be able ot call new on mParticle.SideloadedKit // https://stackoverflow.com/questions/13407036/how-does-interfaces-with-construct-signatures-work export interface IMPSideloadedKitConstructor { - new(unregisteredKitInstance: UnregisteredKit): IMPSideloadedKit; + new (unregisteredKitInstance: UnregisteredKit): IMPSideloadedKit; } -export default class MPSideloadedKit implements IMPSideloadedKit{ +export default class MPSideloadedKit implements IMPSideloadedKit { public kitInstance: UnregisteredKit; public filterDictionary: IKitFilterSettings = { eventTypeFilters: [], @@ -65,11 +68,11 @@ export default class MPSideloadedKit implements IMPSideloadedKit{ public addEventNameFilter( eventType: valueof, - eventName: string + eventName: string, ): void { const hashedEventName = KitFilterHelper.hashEventName( eventName, - eventType + eventType, ); this.filterDictionary.eventNameFilters.push(hashedEventName); } @@ -77,12 +80,12 @@ export default class MPSideloadedKit implements IMPSideloadedKit{ public addEventAttributeFilter( eventType: valueof, eventName: string, - customAttributeKey: string + customAttributeKey: string, ): void { const hashedEventAttribute = KitFilterHelper.hashEventAttributeKey( eventType, eventName, - customAttributeKey + customAttributeKey, ); this.filterDictionary.attributeFilters.push(hashedEventAttribute); } @@ -97,29 +100,27 @@ export default class MPSideloadedKit implements IMPSideloadedKit{ public addScreenAttributeFilter( screenName: string, - screenAttribute: string + screenAttribute: string, ): void { const hashedScreenAttribute = KitFilterHelper.hashEventAttributeKey( EventType.Unknown, screenName, - screenAttribute + screenAttribute, ); this.filterDictionary.screenAttributeFilters.push( - hashedScreenAttribute + hashedScreenAttribute, ); } public addUserIdentityFilter(userIdentity: typeof IdentityType): void { - const hashedIdentityType = KitFilterHelper.hashUserIdentity( - userIdentity - ); + const hashedIdentityType = + KitFilterHelper.hashUserIdentity(userIdentity); this.filterDictionary.userIdentityFilters.push(hashedIdentityType); } public addUserAttributeFilter(userAttributeKey: string): void { - const hashedUserAttributeKey = KitFilterHelper.hashUserAttribute( - userAttributeKey - ); + const hashedUserAttributeKey = + KitFilterHelper.hashUserAttribute(userAttributeKey); this.filterDictionary.userAttributeFilters.push(hashedUserAttributeKey); } } diff --git a/src/store.ts b/src/store.ts index dfc8d327b..42def574c 100644 --- a/src/store.ts +++ b/src/store.ts @@ -30,7 +30,11 @@ import { returnConvertedBoolean, } from './utils'; import { IMinifiedConsentJSONObject, SDKConsentState } from './consent'; -import { ConfiguredKit, MPForwarder, UnregisteredKit } from './forwarders.interfaces'; +import { + ConfiguredKit, + MPForwarder, + UnregisteredKit, +} from './forwarders.interfaces'; import { IdentityCallback, UserAttributes } from './identity-user-interfaces'; import { IGlobalStoreV2MinifiedKeys, @@ -218,12 +222,10 @@ export default function Store( this: IStore, config: SDKInitConfig, mpInstance: IMParticleWebSDKInstance, - apiKey?: string + apiKey?: string, ) { - const { - createMainStorageName, - createProductStorageName, - } = mpInstance._Helpers; + const { createMainStorageName, createProductStorageName } = + mpInstance._Helpers; const { isWebviewEnabled } = mpInstance._NativeSdkHelpers; @@ -277,7 +279,7 @@ export default function Store( } as IPersistenceMinified, }; - for (var key in defaultStore) { + for (const key in defaultStore) { this[key] = defaultStore[key]; } this.devToken = apiKey || null; @@ -303,7 +305,7 @@ export default function Store( } if (config.hasOwnProperty('isDevelopmentMode')) { this.SDKConfig.isDevelopmentMode = returnConvertedBoolean( - config.isDevelopmentMode + config.isDevelopmentMode, ); } else { this.SDKConfig.isDevelopmentMode = false; @@ -312,7 +314,7 @@ export default function Store( const baseUrls: Dictionary = processBaseUrls( config, this.SDKConfig.flags, - apiKey + apiKey, ); for (const baseUrlKeys in baseUrls) { @@ -378,14 +380,14 @@ export default function Store( } if (config.hasOwnProperty('identityCallback')) { - var callback = config.identityCallback; + const callback = config.identityCallback; if (mpInstance._Helpers.Validators.isFunction(callback)) { this.SDKConfig.identityCallback = config.identityCallback; } else { mpInstance.Logger.warning( 'The optional callback must be a function. You tried entering a(n) ' + typeof callback + - ' . Callback not set. Please set your callback again.' + ' . Callback not set. Please set your callback again.', ); } } @@ -414,7 +416,7 @@ export default function Store( this.SDKConfig.dataPlan.PlanId = dataPlan.planId; } else { mpInstance.Logger.error( - 'Your data plan id must be a string and match the data plan slug format (i.e. under_case_slug)' + 'Your data plan id must be a string and match the data plan slug format (i.e. under_case_slug)', ); } } @@ -424,7 +426,7 @@ export default function Store( this.SDKConfig.dataPlan.PlanVersion = dataPlan.planVersion; } else { mpInstance.Logger.error( - 'Your data plan version must be a number' + 'Your data plan version must be a number', ); } } @@ -465,7 +467,7 @@ export default function Store( !dataPlanOptions.hasOwnProperty('blockUserIdentities') ) { mpInstance.Logger.error( - 'Ensure your config.dataPlanOptions object has the following keys: a "dataPlanVersion" object, and "blockUserAttributes", "blockEventAttributes", "blockEvents", "blockUserIdentities" booleans' + 'Ensure your config.dataPlanOptions object has the following keys: a "dataPlanVersion" object, and "blockUserAttributes", "blockEventAttributes", "blockEvents", "blockUserIdentities" booleans', ); } } @@ -475,7 +477,7 @@ export default function Store( this.SDKConfig.onCreateBatch = config.onCreateBatch; } else { mpInstance.Logger.error( - 'config.onCreateBatch must be a function' + 'config.onCreateBatch must be a function', ); // set to undefined because all items are set on createSDKConfig this.SDKConfig.onCreateBatch = undefined; @@ -541,13 +543,11 @@ export default function Store( }; this.getConsentState = (mpid: MPID): ConsentState => { - const { - fromMinifiedJsonObject, - } = mpInstance._Consent.ConsentSerialization; + const { fromMinifiedJsonObject } = + mpInstance._Consent.ConsentSerialization; - const serializedConsentState = this._getFromPersistence< - IMinifiedConsentJSONObject - >(mpid, 'con'); + const serializedConsentState = + this._getFromPersistence(mpid, 'con'); if (!isEmpty(serializedConsentState)) { return fromMinifiedJsonObject(serializedConsentState); @@ -557,16 +557,15 @@ export default function Store( }; this.setConsentState = (mpid: MPID, consentState: ConsentState) => { - const { - toMinifiedJsonObject, - } = mpInstance._Consent.ConsentSerialization; + const { toMinifiedJsonObject } = + mpInstance._Consent.ConsentSerialization; // If ConsentState is null, we assume the intent is to clear out the consent state if (consentState || consentState === null) { this._setPersistence( mpid, 'con', - toMinifiedJsonObject(consentState) + toMinifiedJsonObject(consentState), ); } }; @@ -578,7 +577,6 @@ export default function Store( mpInstance._Persistence.update(); }; - this.getFirstSeenTime = (mpid: MPID) => this._getFromPersistence(mpid, 'fst'); @@ -630,7 +628,7 @@ export default function Store( this.setUserAttributes = ( mpid: MPID, - userAttributes: UserAttributes + userAttributes: UserAttributes, ): void => this._setPersistence(mpid, 'ua', userAttributes); this.getUserIdentities = (mpid: MPID): UserIdentities => @@ -651,7 +649,7 @@ export default function Store( if (indexOfMPID >= 0) { this.currentSessionMPIDs = moveElementToEnd( this.currentSessionMPIDs, - indexOfMPID + indexOfMPID, ); } }; @@ -674,7 +672,7 @@ export default function Store( const baseUrls: Dictionary = processBaseUrls( config, this.SDKConfig.flags, - apiKey + apiKey, ); for (const baseUrlKeys in baseUrls) { @@ -686,7 +684,7 @@ export default function Store( mpInstance._timeOnSiteTimer = new ForegroundTimer(workspaceToken); } else { mpInstance.Logger.warning( - 'You should have a workspaceToken on your config object for security purposes.' + 'You should have a workspaceToken on your config object for security purposes.', ); } // add a new function to apply items to the store that require config to be returned @@ -698,7 +696,7 @@ export default function Store( this.webviewBridgeEnabled = isWebviewEnabled( this.SDKConfig.requiredWebviewBridgeName, - this.SDKConfig.minWebviewBridgeVersion + this.SDKConfig.minWebviewBridgeVersion, ); this.configurationLoaded = true; @@ -716,7 +714,7 @@ export function processFlags(config: SDKInitConfig): IFeatureFlags { CacheIdentity, AudienceAPI, CaptureIntegrationSpecificIds, - AstBackgroundEvents + AstBackgroundEvents, } = Constants.FeatureFlags; if (!config.flags) { @@ -734,7 +732,8 @@ export function processFlags(config: SDKInitConfig): IFeatureFlags { flags[DirectUrlRouting] = config.flags[DirectUrlRouting] === 'True'; flags[CacheIdentity] = config.flags[CacheIdentity] === 'True'; flags[AudienceAPI] = config.flags[AudienceAPI] === 'True'; - flags[CaptureIntegrationSpecificIds] = config.flags[CaptureIntegrationSpecificIds] === 'True'; + flags[CaptureIntegrationSpecificIds] = + config.flags[CaptureIntegrationSpecificIds] === 'True'; flags[AstBackgroundEvents] = config.flags[AstBackgroundEvents] === 'True'; return flags; @@ -743,7 +742,7 @@ export function processFlags(config: SDKInitConfig): IFeatureFlags { export function processBaseUrls( config: SDKInitConfig, flags: IFeatureFlags, - apiKey?: string + apiKey?: string, ): Dictionary { // an API key is not present in a webview only mode. In this case, no baseUrls are needed if (!apiKey) { @@ -775,14 +774,14 @@ function processCustomBaseUrls(config: SDKInitConfig): Dictionary { // This flag is set on the Rokt/MP snippet (starting at version 2.6), meaning config.domain will alwys be empty // if a customer is using a snippet prior to 2.6. if (!isEmpty(config.domain)) { - for (let pathKey in CNAMEUrlPaths) { + for (const pathKey in CNAMEUrlPaths) { newBaseUrls[pathKey] = `${config.domain}${CNAMEUrlPaths[pathKey]}`; } return newBaseUrls; } - for (let baseUrlKey in defaultBaseUrls) { + for (const baseUrlKey in defaultBaseUrls) { newBaseUrls[baseUrlKey] = config[baseUrlKey] || defaultBaseUrls[baseUrlKey]; } @@ -792,7 +791,7 @@ function processCustomBaseUrls(config: SDKInitConfig): Dictionary { function processDirectBaseUrls( config: SDKInitConfig, - apiKey: string + apiKey: string, ): Dictionary { const defaultBaseUrls = Constants.DefaultBaseUrls; const directBaseUrls: Dictionary = {}; @@ -809,7 +808,7 @@ function processDirectBaseUrls( const routingPrefix: string = splitKey.length <= 1 ? DEFAULT_SILO : splitKey[0]; - for (let baseUrlKey in defaultBaseUrls) { + for (const baseUrlKey in defaultBaseUrls) { // Any custom endpoints passed to mpConfig will take priority over direct // mapping to the silo. The most common use case is a customer provided CNAME. if (baseUrlKey === 'configUrl') { diff --git a/src/stub/mparticle.stub.js b/src/stub/mparticle.stub.js index cff68e792..6204ce879 100644 --- a/src/stub/mparticle.stub.js +++ b/src/stub/mparticle.stub.js @@ -1,4 +1,4 @@ -let mParticle = { +const mParticle = { endSession: voidFunction, getAppName: returnString, getAppVersion: returnString, @@ -71,7 +71,7 @@ function returnThis() { } function returnUser() { return { - getUserIdentities: function() { + getUserIdentities: function () { return { userIdentities: {}, }; @@ -101,7 +101,7 @@ function Cart() { add: voidFunction, clear: voidFunction, remove: voidFunction, - getCartProducts: function() { + getCartProducts: function () { return [returnProduct()]; }, }; diff --git a/src/types.ts b/src/types.ts index 3ac8a5ad9..603f625a8 100644 --- a/src/types.ts +++ b/src/types.ts @@ -160,7 +160,7 @@ export const IdentityType = { }, getIdentityType: ( - identityName: string + identityName: string, ): valueof | boolean => { switch (identityName) { case 'other': @@ -262,20 +262,21 @@ export const IdentityType = { // Strips out functions from Identity Types for easier lookups getValuesAsStrings: (): string[] => Object.values(IdentityType) - .map(value => (isNumber(value) ? value.toString() : undefined)) - .filter(value => value !== undefined) as string[], + .map((value) => (isNumber(value) ? value.toString() : undefined)) + .filter((value) => value !== undefined) as string[], getNewIdentitiesByName: ( - newIdentitiesByType: IdentitiesByType + newIdentitiesByType: IdentitiesByType, ): IdentitiesByType => { const newIdentitiesByName: IdentitiesByType = {}; - const identityTypeValuesAsStrings: string[] = IdentityType.getValuesAsStrings(); + const identityTypeValuesAsStrings: string[] = + IdentityType.getValuesAsStrings(); for (const key in newIdentitiesByType) { // IdentityTypes are stored as numbers but are passed in as strings if (identityTypeValuesAsStrings.includes(key)) { const identityNameKey = IdentityType.getIdentityName( - parseNumber(key) + parseNumber(key), ); newIdentitiesByName[identityNameKey] = newIdentitiesByType[key]; } diff --git a/src/uploaders.ts b/src/uploaders.ts index e28606c46..b0680b90a 100644 --- a/src/uploaders.ts +++ b/src/uploaders.ts @@ -13,7 +13,7 @@ export abstract class AsyncUploader { url: string; public abstract upload( fetchPayload: IFetchPayload, - url?: string + url?: string, ): Promise; constructor(url: string) { @@ -24,7 +24,7 @@ export abstract class AsyncUploader { export class FetchUploader extends AsyncUploader { public async upload( fetchPayload: IFetchPayload, - _url?: string + _url?: string, ): Promise { const url = _url || this.url; return await fetch(url, fetchPayload); @@ -37,7 +37,7 @@ export class XHRUploader extends AsyncUploader { this.url, fetchPayload.body, fetchPayload.method as HTTPMethod, - fetchPayload.headers + fetchPayload.headers, ); return response; } @@ -55,7 +55,7 @@ export class XHRUploader extends AsyncUploader { url: string, data: string, method: HTTPMethod = 'post', - headers: Record = {} + headers: Record = {}, ): Promise { const xhr: XMLHttpRequest = new XMLHttpRequest(); return new Promise((resolve, reject) => { @@ -65,12 +65,12 @@ export class XHRUploader extends AsyncUploader { // Process the response // We resolve all xhr responses whose ready state is 4 regardless of HTTP codes that may be errors (400+) // because these are valid HTTP responses. - resolve((xhr as unknown) as Response); + resolve(xhr as unknown as Response); }; // Reject a promise only when there is an xhr error xhr.onerror = () => { - reject((xhr as unknown) as Response); + reject(xhr as unknown as Response); }; xhr.open(method, url); diff --git a/src/user-utils.ts b/src/user-utils.ts index 9e491389b..d347f4700 100644 --- a/src/user-utils.ts +++ b/src/user-utils.ts @@ -1,12 +1,16 @@ import { UserIdentities } from '@mparticle/web-sdk'; -import { IMParticleUser, ISDKUserIdentity, IdentityResultBody } from './identity-user-interfaces'; +import { + IMParticleUser, + ISDKUserIdentity, + IdentityResultBody, +} from './identity-user-interfaces'; import { SDKEvent } from './sdkRuntimeModels'; import Types from './types'; import { isObject, parseNumber } from './utils'; export function hasMPIDAndUserLoginChanged( previousUser: IMParticleUser, - newUser: IMParticleUser + newUser: IMParticleUser, ): boolean { return ( !previousUser || @@ -18,7 +22,7 @@ export function hasMPIDAndUserLoginChanged( // https://go.mparticle.com/work/SQDSDKS-6504 export function hasMPIDChanged( prevUser: IMParticleUser, - identityApiResult: IdentityResultBody + identityApiResult: IdentityResultBody, ): boolean { return ( !prevUser || @@ -29,10 +33,7 @@ export function hasMPIDChanged( } // https://go.mparticle.com/work/SQDSDKS-7136 -export function appendUserInfo( - user: IMParticleUser, - event: SDKEvent -): void { +export function appendUserInfo(user: IMParticleUser, event: SDKEvent): void { if (!event) { return; } @@ -51,7 +52,8 @@ export function appendUserInfo( event.ConsentState = user.getConsentState(); event.UserAttributes = user.getAllUserAttributes(); - const userIdentities: UserIdentities = user.getUserIdentities().userIdentities; + const userIdentities: UserIdentities = + user.getUserIdentities().userIdentities; const dtoUserIdentities = {}; for (const identityKey in userIdentities) { const identityType = Types.IdentityType.getIdentityType(identityKey); diff --git a/src/utils.ts b/src/utils.ts index 962a567ff..c71e64d7d 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -28,7 +28,7 @@ const inArray = (items: any[], name: any): boolean => { if (Array.prototype.indexOf) { return items.indexOf(name, 0) >= 0; } else { - for (var n = items.length; i < n; i++) { + for (let n = items.length; i < n; i++) { if (i in items && items[i] === name) { return true; } @@ -40,7 +40,7 @@ const inArray = (items: any[], name: any): boolean => { const findKeyInObject = (obj: any, key: string): string => { if (key && obj) { - for (var prop in obj) { + for (const prop in obj) { if ( obj.hasOwnProperty(prop) && prop.toLowerCase() === key.toLowerCase() @@ -55,7 +55,7 @@ const findKeyInObject = (obj: any, key: string): string => { const generateDeprecationMessage = ( methodName: string, - alternateMethod: string + alternateMethod: string, ): string => { const messageArray: string[] = [ methodName, @@ -65,7 +65,7 @@ const generateDeprecationMessage = ( if (alternateMethod) { messageArray.push(alternateMethod); messageArray.push( - Messages.DeprecationMessages.MethodIsDeprecatedPostfix + Messages.DeprecationMessages.MethodIsDeprecatedPostfix, ); } @@ -73,7 +73,7 @@ const generateDeprecationMessage = ( }; function generateHash(name: string): number { - let hash: number = 0; + let hash = 0; let character: number; if (name === undefined || name === null) { @@ -83,7 +83,7 @@ function generateHash(name: string): number { name = name.toString().toLowerCase(); if (Array.prototype.reduce) { - return name.split('').reduce(function(a: number, b: string) { + return name.split('').reduce(function (a: number, b: string) { a = (a << 5) - a + b.charCodeAt(0); return a & a; }, 0); @@ -118,7 +118,7 @@ const generateRandomValue = (value?: string): string => { return (a ^ ((Math.random() * 16) >> (a / 4))).toString(16); }; -const generateUniqueId = (a: string = ''): string => +const generateUniqueId = (a = ''): string => // https://gist.github.com/jed/982883 // Added support for crypto for better random @@ -131,7 +131,7 @@ const generateUniqueId = (a: string = ''): string => // -1e11 -> //-100000000000, `${1e7}-${1e3}-${4e3}-${8e3}-${1e11}`.replace( /[018]/g, // zeroes, ones, and eights with - generateUniqueId // random hex digits + generateUniqueId, // random hex digits ); /** @@ -148,7 +148,7 @@ const getRampNumber = (value?: string): number => { }; const isObject = (value: any): boolean => { - var objType = Object.prototype.toString.call(value); + const objType = Object.prototype.toString.call(value); return objType === '[object Object]' || objType === '[object Error]'; }; @@ -156,20 +156,22 @@ const parseNumber = (value: string | number): number => { if (isNaN(value as number) || !isFinite(value as number)) { return 0; } - var floatValue = parseFloat(value as string); + const floatValue = parseFloat(value as string); return isNaN(floatValue) ? 0 : floatValue; }; const parseSettingsString = (settingsString: string): Dictionary[] => { try { - return settingsString ? JSON.parse(settingsString.replace(/"/g, '"')) : []; + return settingsString + ? JSON.parse(settingsString.replace(/"/g, '"')) + : []; } catch (error) { throw new Error('Settings string contains invalid JSON'); } }; const parseStringOrNumber = ( - value: string | number + value: string | number, ): string | number | null => { if (isStringOrNumber(value)) { return value; @@ -190,14 +192,16 @@ const replaceApostrophesWithQuotes = (value: string): string => const replaceQuotesWithApostrophes = (value: string): string => value.replace(/\"/g, "'"); -const replaceMPID = (value: string, mpid: MPID): string => value.replace('%%mpid%%', mpid); +const replaceMPID = (value: string, mpid: MPID): string => + value.replace('%%mpid%%', mpid); -const replaceAmpWithAmpersand = (value: string): string => value.replace(/&/g, '&'); +const replaceAmpWithAmpersand = (value: string): string => + value.replace(/&/g, '&'); const createCookieSyncUrl = ( mpid: MPID, pixelUrl: string, - redirectUrl?: string + redirectUrl?: string, ): string => { const modifiedPixelUrl = replaceAmpWithAmpersand(pixelUrl); const modifiedDirectUrl = redirectUrl @@ -228,10 +232,7 @@ const decoded = (s: string): string => const converted = (s: string): string => { if (s.indexOf('"') === 0) { - s = s - .slice(1, -1) - .replace(/\\"/g, '"') - .replace(/\\\\/g, '\\'); + s = s.slice(1, -1).replace(/\\"/g, '"').replace(/\\\\/g, '\\'); } return s; @@ -270,11 +271,11 @@ const moveElementToEnd = (array: T[], index: number): T[] => const queryStringParser = ( url: string, - keys: string[] = [] + keys: string[] = [], ): Dictionary => { let urlParams: URLSearchParams | URLSearchParamsFallback; - let results: Dictionary = {}; - let lowerCaseUrlParams: Dictionary = {}; + const results: Dictionary = {}; + const lowerCaseUrlParams: Dictionary = {}; if (!url) return results; @@ -292,7 +293,7 @@ const queryStringParser = ( if (isEmpty(keys)) { return lowerCaseUrlParams; } else { - keys.forEach(key => { + keys.forEach((key) => { const value = lowerCaseUrlParams[key.toLowerCase()]; if (value) { results[key] = value; @@ -313,7 +314,7 @@ const queryStringParserFallback = (url: string): URLSearchParamsFallback => { const queryString = url.split('?')[1] || ''; const pairs = queryString.split('&'); - pairs.forEach(pair => { + pairs.forEach((pair) => { const [key, ...valueParts] = pair.split('='); const value = valueParts.join('='); if (key && value !== undefined) { @@ -326,11 +327,11 @@ const queryStringParserFallback = (url: string): URLSearchParamsFallback => { }); return { - get: function(key: string) { + get: function (key: string) { return params[key]; }, - forEach: function(callback: (value: string, key: string) => void) { - for (var key in params) { + forEach: function (callback: (value: string, key: string) => void) { + for (const key in params) { if (params.hasOwnProperty(key)) { callback(params[key], key); } @@ -347,7 +348,9 @@ const getCookies = (keys?: string[]): Dictionary => { if (typeof window === 'undefined') { return []; } - return window.document.cookie.split(';').map(cookie => cookie.trim()); + return window.document.cookie + .split(';') + .map((cookie) => cookie.trim()); } catch (e) { console.error('Unable to parse cookies', e); return []; @@ -357,7 +360,7 @@ const getCookies = (keys?: string[]): Dictionary => { // Helper function to filter cookies by keys const filterCookies = ( cookies: string[], - keys?: string[] + keys?: string[], ): Dictionary => { const results: Dictionary = {}; for (const cookie of cookies) { @@ -385,7 +388,7 @@ const getHref = (): string => { const filterDictionaryWithHash = ( dictionary: Dictionary, filterList: any[], - hashFn: (key: string) => any + hashFn: (key: string) => any, ): Dictionary => { const filtered = {}; @@ -401,14 +404,21 @@ const filterDictionaryWithHash = ( } return filtered; -} +}; -const parseConfig = (config: SDKInitConfig, moduleName: string, moduleId: number): IKitConfigs | null => { - return config.kitConfigs?.find((kitConfig: IKitConfigs) => - kitConfig.name === moduleName && - kitConfig.moduleId === moduleId - ) || null; -} +const parseConfig = ( + config: SDKInitConfig, + moduleName: string, + moduleId: number, +): IKitConfigs | null => { + return ( + config.kitConfigs?.find( + (kitConfig: IKitConfigs) => + kitConfig.name === moduleName && + kitConfig.moduleId === moduleId, + ) || null + ); +}; export { createCookieString, diff --git a/src/validators.ts b/src/validators.ts index 7a29cf5b8..8377a6763 100644 --- a/src/validators.ts +++ b/src/validators.ts @@ -25,26 +25,26 @@ const Validators = { isStringOrNumber, // Validator Functions - isValidAttributeValue: function(value: any): boolean { + isValidAttributeValue: function (value: any): boolean { return value !== undefined && !isObject(value) && !Array.isArray(value); }, // Validator Functions // Neither null nor undefined can be a valid Key - isValidKeyValue: function(key: any): boolean { + isValidKeyValue: function (key: any): boolean { return Boolean( key && !isObject(key) && !Array.isArray(key) && - !this.isFunction(key) + !this.isFunction(key), ); }, - validateIdentities: function( + validateIdentities: function ( identityApiData: IdentityApiData, - method?: IdentityAPIMethod + method?: IdentityAPIMethod, ): ValidationIdentitiesReturn { - var validIdentityRequestKeys = { + const validIdentityRequestKeys = { userIdentities: 1, onUserAlias: 1, copyUserAttributes: 1, @@ -58,20 +58,18 @@ const Validators = { ) { return { valid: false, - error: - Constants.Messages.ValidationMessages - .ModifyIdentityRequestUserIdentitiesPresent, + error: Constants.Messages.ValidationMessages + .ModifyIdentityRequestUserIdentitiesPresent, }; } } - for (var key in identityApiData) { + for (const key in identityApiData) { if (identityApiData.hasOwnProperty(key)) { if (!validIdentityRequestKeys[key]) { return { valid: false, - error: - Constants.Messages.ValidationMessages - .IdentityRequesetInvalidKey, + error: Constants.Messages.ValidationMessages + .IdentityRequesetInvalidKey, }; } if ( @@ -80,9 +78,8 @@ const Validators = { ) { return { valid: false, - error: - Constants.Messages.ValidationMessages - .OnUserAliasType, + error: Constants.Messages.ValidationMessages + .OnUserAliasType, }; } } @@ -96,9 +93,8 @@ const Validators = { if (identityApiData.userIdentities === undefined) { return { valid: false, - error: - Constants.Messages.ValidationMessages - .UserIdentities, + error: Constants.Messages.ValidationMessages + .UserIdentities, }; // identityApiData.userIdentities can be null, but if it isn't null or undefined (above conditional), it must be an object } else if ( @@ -107,31 +103,29 @@ const Validators = { ) { return { valid: false, - error: - Constants.Messages.ValidationMessages - .UserIdentities, + error: Constants.Messages.ValidationMessages + .UserIdentities, }; } if ( isObject(identityApiData.userIdentities) && Object.keys(identityApiData.userIdentities).length ) { - for (var identityType in identityApiData.userIdentities) { + for (const identityType in identityApiData.userIdentities) { if ( identityApiData.userIdentities.hasOwnProperty( - identityType + identityType, ) ) { if ( Types.IdentityType.getIdentityType( - identityType + identityType, ) === false ) { return { valid: false, - error: - Constants.Messages.ValidationMessages - .UserIdentitiesInvalidKey, + error: Constants.Messages.ValidationMessages + .UserIdentitiesInvalidKey, }; } if ( @@ -146,9 +140,8 @@ const Validators = { ) { return { valid: false, - error: - Constants.Messages.ValidationMessages - .UserIdentitiesInvalidValues, + error: Constants.Messages.ValidationMessages + .UserIdentitiesInvalidValues, }; } } diff --git a/src/vault.ts b/src/vault.ts index 57d2a6dc1..2653434d3 100644 --- a/src/vault.ts +++ b/src/vault.ts @@ -21,7 +21,7 @@ export abstract class BaseVault { constructor( storageKey: string, storageObject: Storage, - options?: IVaultOptions + options?: IVaultOptions, ) { this._storageKey = storageKey; this.storageObject = storageObject; @@ -57,7 +57,7 @@ export abstract class BaseVault { this.logger.verbose(`Saving item to Storage: ${stringifiedItem}`); } catch (error) { this.logger.error( - `Cannot Save items to Storage: ${stringifiedItem}` + `Cannot Save items to Storage: ${stringifiedItem}`, ); this.logger.error(error as string); } @@ -102,4 +102,4 @@ export class SessionStorageVault extends BaseVault { constructor(storageKey: string, options?: IVaultOptions) { super(storageKey, window.sessionStorage, options); } -} \ No newline at end of file +} diff --git a/test/src/_test.index.ts b/test/src/_test.index.ts index 81513029e..b300c3a21 100644 --- a/test/src/_test.index.ts +++ b/test/src/_test.index.ts @@ -39,4 +39,3 @@ import './tests-identityApiClient'; import './tests-integration-capture'; import './tests-batchUploader_4'; import './tests-identity'; - diff --git a/test/src/config/constants.ts b/test/src/config/constants.ts index 6f645a13e..007ceea3a 100644 --- a/test/src/config/constants.ts +++ b/test/src/config/constants.ts @@ -1,5 +1,5 @@ -import { SDKInitConfig } from "../../../src/sdkRuntimeModels"; -import { MILLIS_IN_ONE_SEC, ONE_DAY_IN_SECONDS } from "../../../src/constants"; +import { SDKInitConfig } from '../../../src/sdkRuntimeModels'; +import { MILLIS_IN_ONE_SEC, ONE_DAY_IN_SECONDS } from '../../../src/constants'; export const urls = { events: 'https://jssdks.mparticle.com/v3/JS/test_key/events', @@ -9,11 +9,12 @@ export const urls = { modify: 'https://identity.mparticle.com/v1/testMPID/modify', config: 'https://jssdkcdns.mparticle.com/JS/v2/test_key/config?env=0', alias: 'https://jssdks.mparticle.com/v1/identity/test_key/Alias', - forwarding: 'https://jssdks.mparticle.com/v1/JS/test_key/Forwarding' + forwarding: 'https://jssdks.mparticle.com/v1/JS/test_key/Forwarding', }; -export const MILLISECONDS_IN_ONE_DAY = ONE_DAY_IN_SECONDS * MILLIS_IN_ONE_SEC -export const MILLISECONDS_IN_ONE_DAY_PLUS_ONE_SECOND = MILLISECONDS_IN_ONE_DAY + 1; +export const MILLISECONDS_IN_ONE_DAY = ONE_DAY_IN_SECONDS * MILLIS_IN_ONE_SEC; +export const MILLISECONDS_IN_ONE_DAY_PLUS_ONE_SECOND = + MILLISECONDS_IN_ONE_DAY + 1; export const mParticle = window.mParticle; @@ -79,4 +80,4 @@ export const CommerceEventType = { ProductAddToWishlist: 20, ProductRemoveFromWishlist: 21, ProductImpression: 22, -}; \ No newline at end of file +}; diff --git a/test/src/config/setup.ts b/test/src/config/setup.ts index ea780f0b2..f8bcd1bae 100644 --- a/test/src/config/setup.ts +++ b/test/src/config/setup.ts @@ -11,7 +11,7 @@ let userApi = null; window.mParticle._isTestEnv = true; -beforeEach(function() { +beforeEach(function () { // mocha can't clean up after itself, so this lets // tests mock the current user and restores in between runs. if (!userApi) { @@ -28,11 +28,11 @@ beforeEach(function() { isDevelopmentMode: false, flags: { eventBatchingIntervalMillis: 0, - } + }, }; - + // This is to tell the resetPersistence method that we are in a test environment // It should probably be refactored to be included as an argument window.mParticle._resetForTests(MPConfig); delete window.mParticle._instances['default_instance']; -}); \ No newline at end of file +}); diff --git a/test/src/config/utils.js b/test/src/config/utils.js index d94ee8e84..18f9ddcc5 100644 --- a/test/src/config/utils.js +++ b/test/src/config/utils.js @@ -18,34 +18,31 @@ var pluses = /\+/g, localStorage.getItem( mParticle .getInstance() - ._Helpers.createProductStorageName(workspaceToken) - ) - ) + ._Helpers.createProductStorageName(workspaceToken), + ), + ), ); }, decoded = function decoded(s) { return decodeURIComponent(s.replace(pluses, ' ')); }, - converted = function(s) { + converted = function (s) { if (s.indexOf('"') === 0) { - s = s - .slice(1, -1) - .replace(/\\"/g, '"') - .replace(/\\\\/g, '\\'); + s = s.slice(1, -1).replace(/\\"/g, '"').replace(/\\\\/g, '\\'); } return s; }, - getCookieDomain = function() { - var rootDomain = getDomain(document, location.hostname); + getCookieDomain = function () { + const rootDomain = getDomain(document, location.hostname); if (rootDomain === '') { return ''; } else { return '.' + rootDomain; } }, - getDomain = function(doc, locationHostname) { - var i, + getDomain = function (doc, locationHostname) { + let i, testParts, mpTest = 'mptest=cookie', hostname = locationHostname.split('.'); @@ -63,15 +60,13 @@ var pluses = /\+/g, } return ''; }, - findCookie = function(cookieName) { - var cookie; + findCookie = function (cookieName) { + let cookie; if (cookieName === v4CookieKey || !cookieName) { cookie = mParticle.getInstance()._Persistence.getCookie(); } else if (cookieName === v3CookieKey) { cookie = JSON.parse( - Utils.replacePipesWithCommas( - findEncodedCookie(cookieName) - ) + Utils.replacePipesWithCommas(findEncodedCookie(cookieName)), ); } else { cookie = JSON.parse(findEncodedCookie(cookieName)); @@ -82,21 +77,21 @@ var pluses = /\+/g, return null; } }, - findEncodedCookie = function(cookieName) { - var cookies = document.cookie.split('; '); - for (var i = 0, l = cookies.length; i < l; i++) { - var parts = cookies[i].split('='); - var name = decoded(parts.shift()); - var cookie = decoded(parts.join('=')); + findEncodedCookie = function (cookieName) { + const cookies = document.cookie.split('; '); + for (let i = 0, l = cookies.length; i < l; i++) { + const parts = cookies[i].split('='); + const name = decoded(parts.shift()); + const cookie = decoded(parts.join('=')); if (cookieName === name) { return Utils.replacePipesWithCommas(converted(cookie)); } } }, - setCookie = function(cname, data, raw) { - var date = new Date(), + setCookie = function (cname, data, raw) { + let date = new Date(), expires = new Date( - date.getTime() + 365 * 24 * 60 * 60 * 1000 + date.getTime() + 365 * 24 * 60 * 60 * 1000, ).toGMTString(), domain, cookieDomain, @@ -130,8 +125,8 @@ var pluses = /\+/g, ';path=/' + domain; }, - setLocalStorage = function(name, data, raw) { - var value; + setLocalStorage = function (name, data, raw) { + let value; //if we just set setLocalStorage(), we put a valid full length LS into localStorage if (arguments.length === 0) { data = { @@ -167,24 +162,27 @@ var pluses = /\+/g, localStorage.setItem(encodeURIComponent(name), value); }, - getLocalStorage = function(name) { + getLocalStorage = function (name) { if (name === v4LSKey || !name) { return mParticle.getInstance()._Persistence.getLocalStorage(); } }, // https://go.mparticle.com/work/SQDSDKS-6894 - findEventFromBatch = function(batch, eventName) { + findEventFromBatch = function (batch, eventName) { if (batch.events.length) { - return batch.events.find(function(event) { + return batch.events.find(function (event) { switch (event.event_type) { case 'screen_view': // The SDK sets "PageView" as the default for a screen_name if one is not provided - return ['PageView', eventName].includes(event.data.screen_name); + return ['PageView', eventName].includes( + event.data.screen_name, + ); case 'commerce_event': if (event.data.product_action) { - return event.data.product_action.action === eventName; - } - else if (event.data.promotion_action) { + return ( + event.data.product_action.action === eventName + ); + } else if (event.data.promotion_action) { // return the promotion action return true; } else { @@ -198,35 +196,39 @@ var pluses = /\+/g, return true; default: // all other events are lifecycle events (session start, end, AST) - return event.event_type === eventName + return event.event_type === eventName; } - }) + }); } return null; }, - getForwarderEvent = function(requests, eventName) { - var url = `https://jssdks.mparticle.com/v2/JS/${apiKey}/Forwarding` - var returnedReqs = []; + getForwarderEvent = function (requests, eventName) { + const url = `https://jssdks.mparticle.com/v2/JS/${apiKey}/Forwarding`; + const returnedReqs = []; if (requests.length) { - requests.filter(function(request) { - return (request.url === url) - }).forEach(function(request) { - JSON.parse(request.requestBody).data.forEach(function(internalRequest) { - if (internalRequest.n === eventName) { - returnedReqs.push(internalRequest) - } + requests + .filter(function (request) { + return request.url === url; }) - }); + .forEach(function (request) { + JSON.parse(request.requestBody).data.forEach( + function (internalRequest) { + if (internalRequest.n === eventName) { + returnedReqs.push(internalRequest); + } + }, + ); + }); } if (returnedReqs.length) { - return (returnedReqs[0]); + return returnedReqs[0]; } else { return null; } }, - findRequest = function(requests, eventName) { + findRequest = function (requests, eventName) { let matchingRequest; - requests.forEach(function(request) { + requests.forEach(function (request) { // Initial implementation of this function was to find the // first request that contained a batch that matched the event name // which would have been a post request. However, this was not @@ -235,48 +237,49 @@ var pluses = /\+/g, if (request[1].method.toLowerCase() === 'get') { return null; } - var batch = JSON.parse(request[1].body); + const batch = JSON.parse(request[1].body); if (!batch.events) { return null; } - for (var i = 0; i < batch.events.length; i++) { - var foundEventFromBatch = findEventFromBatch(batch, eventName); + for (let i = 0; i < batch.events.length; i++) { + const foundEventFromBatch = findEventFromBatch( + batch, + eventName, + ); if (foundEventFromBatch) { matchingRequest = request; break; } } - }) + }); return matchingRequest; }, - findRequestURL = function(requests, eventName) { - return findRequest(requests, eventName)[0] + findRequestURL = function (requests, eventName) { + return findRequest(requests, eventName)[0]; }, - findBatch = function(requests, eventName) { - var request = findRequest(requests, eventName); + findBatch = function (requests, eventName) { + const request = findRequest(requests, eventName); if (request) { return JSON.parse(findRequest(requests, eventName)[1].body); } else { return null; } - }, - findEventFromRequest= function(requests, eventName) { - var batch = findBatch(requests, eventName); + findEventFromRequest = function (requests, eventName) { + const batch = findBatch(requests, eventName); if (batch) { return findEventFromBatch(batch, eventName); } else { return null; } - }, - getIdentityRequests = function(requests, path) { - var returnedRequests = [], + getIdentityRequests = function (requests, path) { + const returnedRequests = [], fullPath = 'https://identity.mparticle.com/v1/' + path; if (path !== 'modify') { - requests.forEach(function(item) { + requests.forEach(function (item) { if (!item.url && item[0] === fullPath) { returnedRequests.push(item); } @@ -285,7 +288,7 @@ var pluses = /\+/g, } }); } else { - requests.forEach(function(item) { + requests.forEach(function (item) { let url; if (!item.url) { url = item[0]; @@ -299,19 +302,19 @@ var pluses = /\+/g, } return returnedRequests; }, - getIdentityEvent = function(mockRequests, endpoint) { - var returnedReqs = getIdentityRequests(mockRequests, endpoint); + getIdentityEvent = function (mockRequests, endpoint) { + const returnedReqs = getIdentityRequests(mockRequests, endpoint); if (returnedReqs[0] && returnedReqs[0][1].body) { return JSON.parse(returnedReqs[0][1].body); } return null; }, - forwarderDefaultConfiguration = function( + forwarderDefaultConfiguration = function ( forwarderName, forwarderId, suffix, ) { - var config = { + const config = { name: forwarderName || 'MockForwarder', suffix: suffix || null, moduleId: forwarderId || 1, @@ -340,9 +343,9 @@ var pluses = /\+/g, return config; }, - MockForwarder = function(forwarderName, forwarderId, suffix) { - var constructor = function() { - var self = this; + MockForwarder = function (forwarderName, forwarderId, suffix) { + const constructor = function () { + const self = this; this.id = forwarderId || 1; this.initCalled = false; this.processCalled = false; @@ -363,11 +366,11 @@ var pluses = /\+/g, this.appVersion = null; this.appName = null; - this.logOut = function() { + this.logOut = function () { this.logOutCalled = true; }; - this.init = function( + this.init = function ( settings, reportingService, testMode, @@ -375,7 +378,7 @@ var pluses = /\+/g, userAttributes, userIdentities, appVersion, - appName + appName, ) { self.reportingService = reportingService; self.initCalled = true; @@ -391,14 +394,14 @@ var pluses = /\+/g, self.testMode = testMode; }; - this.process = function(event) { + this.process = function (event) { self.processCalled = true; this.receivedEvent = event; self.reportingService(self, event); self.logger.verbose(event.EventName + ' sent'); }; - this.setUserIdentity = function(a, b) { + this.setUserIdentity = function (a, b) { this.userIdentities = {}; this.userIdentities[b] = a; self.setUserIdentityCalled = true; @@ -408,59 +411,63 @@ var pluses = /\+/g, PriorityValue: 1, }; - this.setOptOut = function() { + this.setOptOut = function () { this.setOptOutCalled = true; }; - this.onUserIdentified = function(user) { + this.onUserIdentified = function (user) { this.onUserIdentifiedCalled = true; this.onUserIdentifiedUser = user; }; - this.onIdentifyComplete = function( + this.onIdentifyComplete = function ( filteredUser, - filteredUserIdentities + filteredUserIdentities, ) { this.onIdentifyCompleteCalled = true; this.onIdentifyCompleteUser = filteredUser; - this.onIdentifyCompleteFilteredUserIdentities = filteredUserIdentities; + this.onIdentifyCompleteFilteredUserIdentities = + filteredUserIdentities; }; - this.onLoginComplete = function( + this.onLoginComplete = function ( filteredUser, - filteredUserIdentities + filteredUserIdentities, ) { this.onLoginCompleteCalled = true; this.onLoginCompleteUser = filteredUser; - this.onLoginCompleteFilteredUserIdentities = filteredUserIdentities; + this.onLoginCompleteFilteredUserIdentities = + filteredUserIdentities; }; - this.onLogoutComplete = function( + this.onLogoutComplete = function ( filteredUser, - filteredUserIdentities + filteredUserIdentities, ) { this.onLogoutCompleteCalled = true; this.onLogoutCompleteUser = filteredUser; - this.onLogoutCompleteFilteredUserIdentities = filteredUserIdentities; + this.onLogoutCompleteFilteredUserIdentities = + filteredUserIdentities; }; - this.onModifyComplete = function( + this.onModifyComplete = function ( filteredUser, - filteredUserIdentities + filteredUserIdentities, ) { this.onModifyCompleteCalled = true; this.onModifyCompleteUser = filteredUser; - this.onModifyCompleteFilteredUserIdentities = filteredUserIdentities; + this.onModifyCompleteFilteredUserIdentities = + filteredUserIdentities; }; - this.setUserAttribute = function(key, value) { + this.setUserAttribute = function (key, value) { this.setUserAttributeCalled = true; this.userAttributes[key] = value; }; - this.removeUserAttribute = function(key) { + this.removeUserAttribute = function (key) { this.removeUserAttributeCalled = true; - delete this.userAttributes[key] + delete this.userAttributes[key]; }; window[this.name + this.id] = { @@ -490,12 +497,12 @@ var pluses = /\+/g, getId: getId, constructor: constructor, name: this.name, - suffix: this.suffix + suffix: this.suffix, }; }, MockSideloadedKit = MockForwarder, - mParticleAndroid = function() { - var self = this; + mParticleAndroid = function () { + const self = this; this.addedToCartItem = null; this.logEventCalled = false; @@ -514,98 +521,98 @@ var pluses = /\+/g, this.aliasUsers = null; this.uploadCalled = false; - this.resetSessionAttrData = function() { + this.resetSessionAttrData = function () { self.sessionAttrData = []; }; - this.login = function(data) { + this.login = function (data) { self.loginData = data; }; - this.logout = function(data) { + this.logout = function (data) { self.logoutData = data; }; - this.modify = function(data) { + this.modify = function (data) { self.modifyData = data; }; - this.identify = function(data) { + this.identify = function (data) { self.modifyData = data; }; - this.logEvent = function(event) { + this.logEvent = function (event) { self.logEventCalled = true; self.event = event; }; - this.setUserIdentity = function() { + this.setUserIdentity = function () { self.setUserIdentityCalled = true; }; - this.removeUserIdentity = function() { + this.removeUserIdentity = function () { self.removeUserIdentityCalled = true; }; - this.setUserTag = function() { + this.setUserTag = function () { self.setUserTagCalled = true; }; - this.removeUserTag = function() { + this.removeUserTag = function () { self.removeUserTagCalled = true; }; - this.resetUserAttributes = function() { + this.resetUserAttributes = function () { self.userAttrData = []; }; - this.setUserAttribute = function(data) { + this.setUserAttribute = function (data) { self.setUserAttributeCalled = true; self.userAttrData.push(data); }; - this.removeUserAttribute = function() { + this.removeUserAttribute = function () { self.removeUserAttributeCalled = true; }; - this.setSessionAttribute = function(data) { + this.setSessionAttribute = function (data) { self.setSessionAttributeCalled = true; self.sessionAttrData.push(data); }; - this.addToCart = function(item) { + this.addToCart = function (item) { self.addToCartCalled = true; self.addedToCartItem = item; }; - this.removeFromCart = function(item) { + this.removeFromCart = function (item) { self.removeFromCartCalled = true; self.removedFromCartItem = item; }; - this.clearCart = function() { + this.clearCart = function () { self.addedToCartItem = null; self.clearCartCalled = true; }; - this.aliasUsers = function(item) { + this.aliasUsers = function (item) { self.aliasUsers = item; }; - this.upload = function() { + this.upload = function () { self.uploadCalled = true; }; }, - mParticleIOS = function() { - var self = this; + mParticleIOS = function () { + const self = this; this.data = []; - this.postMessage = function(data) { + this.postMessage = function (data) { self.data.push(data); }; - this.reset = function() { + this.reset = function () { self.data = []; }; }, - deleteAllCookies = function() { - var cookies = document.cookie.split(";"); - - for (var i = 0; i < cookies.length; i++) { - var cookie = cookies[i]; - var eqPos = cookie.indexOf("="); - var name = eqPos > -1 ? cookie.substr(0, eqPos) : cookie; - document.cookie = name + "=;expires=Thu, 01 Jan 1970 00:00:00 GMT"; + deleteAllCookies = function () { + const cookies = document.cookie.split(';'); + + for (let i = 0; i < cookies.length; i++) { + const cookie = cookies[i]; + const eqPos = cookie.indexOf('='); + const name = eqPos > -1 ? cookie.substr(0, eqPos) : cookie; + document.cookie = name + '=;expires=Thu, 01 Jan 1970 00:00:00 GMT'; } }, waitForCondition = function async( conditionFn, timeout = 200, - interval = 10 + interval = 10, ) { return new Promise((resolve, reject) => { const startTime = Date.now(); @@ -628,16 +635,20 @@ var pluses = /\+/g, status: 200, body: JSON.stringify(body), }, - { overwriteRoutes: true } + { overwriteRoutes: true }, ); }, hasIdentifyReturned = () => { - return window.mParticle.Identity.getCurrentUser()?.getMPID() === testMPID; + return ( + window.mParticle.Identity.getCurrentUser()?.getMPID() === testMPID + ); }, - hasIdentityCallInflightReturned = () => !mParticle.getInstance()?._Store?.identityCallInFlight, - hasConfigurationReturned = () => !!mParticle.getInstance()?._Store?.configurationLoaded; + hasIdentityCallInflightReturned = () => + !mParticle.getInstance()?._Store?.identityCallInFlight, + hasConfigurationReturned = () => + !!mParticle.getInstance()?._Store?.configurationLoaded; -var TestsCore = { +const TestsCore = { getLocalStorageProducts: getLocalStorageProducts, findCookie: findCookie, setCookie: setCookie, @@ -667,4 +678,4 @@ var TestsCore = { hasConfigurationReturned, }; -export default TestsCore; \ No newline at end of file +export default TestsCore; diff --git a/test/src/tests-apiClient.ts b/test/src/tests-apiClient.ts index 614045fbb..83da8d987 100644 --- a/test/src/tests-apiClient.ts +++ b/test/src/tests-apiClient.ts @@ -21,7 +21,7 @@ describe('Api Client', () => { mParticle._resetForTests(MPConfig); }); - it('should update queued events with latest user info', done => { + it('should update queued events with latest user info', (done) => { const event = { messageType: Types.MessageType.PageEvent, name: 'foo page', @@ -31,7 +31,7 @@ describe('Api Client', () => { }; expect(mParticle.getInstance()._Store).to.be.ok; - let sdkEvent1 = mParticle + const sdkEvent1 = mParticle .getInstance() ._ServerModel.createEventObject(event); @@ -41,7 +41,7 @@ describe('Api Client', () => { expect(sdkEvent1.UserIdentities).equal(null); expect(sdkEvent1.ConsentState).equal(null); - let sdkEvent2 = mParticle + const sdkEvent2 = mParticle .getInstance() ._ServerModel.createEventObject(event); @@ -63,8 +63,8 @@ describe('Api Client', () => { 10, 'foo document', 'foo location', - 'foo hardware id' - ) + 'foo hardware id', + ), ); mParticle.getInstance().Identity.getCurrentUser = () => { @@ -100,7 +100,7 @@ describe('Api Client', () => { .getInstance() ._APIClient.appendUserInfoToEvents( mParticle.Identity.getCurrentUser(), - [sdkEvent1, sdkEvent2] + [sdkEvent1, sdkEvent2], ); expect(sdkEvent1.UserIdentities.length).to.equal(6); @@ -115,4 +115,4 @@ describe('Api Client', () => { done(); }); -}); \ No newline at end of file +}); diff --git a/test/src/tests-audience-manager.ts b/test/src/tests-audience-manager.ts index c7302bd66..faf3e9d5a 100644 --- a/test/src/tests-audience-manager.ts +++ b/test/src/tests-audience-manager.ts @@ -3,9 +3,13 @@ import fetchMock from 'fetch-mock/esm/client'; import { expect } from 'chai'; import { urls, apiKey, testMPID } from './config/constants'; import Constants from '../../src/constants'; -import { IMParticleInstanceManager, SDKLoggerApi } from '../../src/sdkRuntimeModels'; +import { + IMParticleInstanceManager, + SDKLoggerApi, +} from '../../src/sdkRuntimeModels'; import AudienceManager, { - IAudienceMemberships, IAudienceMembershipsServerResponse + IAudienceMemberships, + IAudienceMembershipsServerResponse, } from '../../src/audienceManager'; import Logger from '../../src/logger.js'; import Utils from './config/utils'; @@ -21,16 +25,17 @@ declare global { const userAudienceUrl = `https://${Constants.DefaultBaseUrls.userAudienceUrl}${apiKey}/audience`; describe('AudienceManager', () => { - before(function() { + before(function () { fetchMock.restore(); sinon.restore(); }); - beforeEach(function() { + beforeEach(function () { fetchMock.restore(); fetchMockSuccess(urls.identify, { - mpid: testMPID, is_logged_in: false + mpid: testMPID, + is_logged_in: false, }); window.mParticle.config.flags = { @@ -63,22 +68,23 @@ describe('AudienceManager', () => { const audienceManager = new AudienceManager( Constants.DefaultBaseUrls.userAudienceUrl, apiKey, - newLogger + newLogger, ); - const audienceMembershipServerResponse: IAudienceMembershipsServerResponse = { - ct: 1710441407914, - dt: 'cam', - id: 'foo-id', - audience_memberships: [ - { - audience_id: 7628, - }, - { - audience_id: 13388, - }, - ] - }; + const audienceMembershipServerResponse: IAudienceMembershipsServerResponse = + { + ct: 1710441407914, + dt: 'cam', + id: 'foo-id', + audience_memberships: [ + { + audience_id: 7628, + }, + { + audience_id: 13388, + }, + ], + }; const expectedAudienceMembership: IAudienceMemberships = { currentAudienceMemberships: [ @@ -88,7 +94,7 @@ describe('AudienceManager', () => { { audience_id: 13388, }, - ] + ], }; it('should invoke a callback with user audiences of interface IMPParsedAudienceMemberships', async () => { @@ -96,16 +102,19 @@ describe('AudienceManager', () => { fetchMock.get(`${userAudienceUrl}?mpid=${testMPID}`, { status: 200, - body: JSON.stringify(audienceMembershipServerResponse) + body: JSON.stringify(audienceMembershipServerResponse), }); - await audienceManager.sendGetUserAudienceRequest(testMPID, callback); + await audienceManager.sendGetUserAudienceRequest( + testMPID, + callback, + ); expect(audienceManager.logger).to.be.ok; expect(audienceManager.url).to.equal(userAudienceUrl); expect(callback.calledOnce).to.eq(true); expect(callback.getCall(0).lastArg).to.deep.equal( - expectedAudienceMembership + expectedAudienceMembership, ); }); @@ -117,54 +126,58 @@ describe('AudienceManager', () => { fetchMock.get(testMPIDAudienceEndpoint, { status: 200, - body: JSON.stringify(audienceMembershipServerResponse) + body: JSON.stringify(audienceMembershipServerResponse), }); - const audienceMembershipServerResponse2: IAudienceMembershipsServerResponse = { - ct: 1710441407915, - dt: 'cam', - id: 'foo-id-2', - audience_memberships: [ + const audienceMembershipServerResponse2: IAudienceMembershipsServerResponse = + { + ct: 1710441407915, + dt: 'cam', + id: 'foo-id-2', + audience_memberships: [ + { + audience_id: 9876, + }, + { + audience_id: 5432, + }, + ], + }; + + const expectedAudienceMembership2: IAudienceMemberships = { + currentAudienceMemberships: [ { audience_id: 9876, }, { audience_id: 5432, }, - ] + ], }; - const expectedAudienceMembership2: IAudienceMemberships = { - currentAudienceMemberships: [ - { - audience_id: 9876, - }, - { - audience_id: 5432, - }, - ] - }; - fetchMock.get(newMPIDAudienceEndpoint, { status: 200, - body: JSON.stringify(audienceMembershipServerResponse2) + body: JSON.stringify(audienceMembershipServerResponse2), }); - await audienceManager.sendGetUserAudienceRequest(testMPID, callback); + await audienceManager.sendGetUserAudienceRequest( + testMPID, + callback, + ); expect(audienceManager.logger).to.be.ok; expect(audienceManager.url).to.equal(userAudienceUrl); expect(callback.calledOnce).to.eq(true); expect(callback.getCall(0).lastArg).to.deep.equal( - expectedAudienceMembership + expectedAudienceMembership, ); await audienceManager.sendGetUserAudienceRequest(newMPID, callback); expect(callback.calledTwice).to.eq(true); expect(callback.getCall(1).lastArg).to.deep.equal( - expectedAudienceMembership2 + expectedAudienceMembership2, ); }); }); -}); \ No newline at end of file +}); diff --git a/test/src/tests-batchUploader.ts b/test/src/tests-batchUploader.ts index 766e6d1b7..12a7e61d1 100644 --- a/test/src/tests-batchUploader.ts +++ b/test/src/tests-batchUploader.ts @@ -13,7 +13,7 @@ import _BatchValidator from '../../src/mockBatchCreator'; import Logger from '../../src/logger.js'; import { event0, event1, event2, event3 } from '../fixtures/events'; import fetchMock from 'fetch-mock/esm/client'; -const { fetchMockSuccess, waitForCondition, hasIdentifyReturned } = Utils; +const { fetchMockSuccess, waitForCondition, hasIdentifyReturned } = Utils; declare global { interface Window { @@ -47,10 +47,10 @@ describe('batch uploader', () => { }); // https://go.mparticle.com/work/ - describe('AST background events fired during page events', () => { + describe('AST background events fired during page events', () => { describe('should not fire AST background events if flag is astBackgroundEvents "False"', () => { beforeEach(() => { - window.mParticle.config.flags.astBackgroundEvents = "False" + window.mParticle.config.flags.astBackgroundEvents = 'False'; }); afterEach(() => { delete window.mParticle.config.flags.astBackgroundEvents; @@ -65,11 +65,11 @@ describe('batch uploader', () => { it('should not have an AST of background event when visibility changes', async () => { window.mParticle.init(apiKey, window.mParticle.config); await waitForCondition(hasIdentifyReturned); - + const now = Date.now(); clock = sinon.useFakeTimers({ now: now, - shouldAdvanceTime: true + shouldAdvanceTime: true, }); // Add a regular event first to ensure we have something in the queue @@ -81,7 +81,7 @@ describe('batch uploader', () => { // Trigger visibility change Object.defineProperty(document, 'visibilityState', { configurable: true, - get: () => 'hidden' + get: () => 'hidden', }); document.dispatchEvent(new Event('visibilitychange')); @@ -89,7 +89,10 @@ describe('batch uploader', () => { await Promise.resolve(); // Verify that beacon was called - expect(beaconSpy.calledOnce, 'Expected beacon to be called once').to.be.true; + expect( + beaconSpy.calledOnce, + 'Expected beacon to be called once', + ).to.be.true; // Get the beacon call data const beaconCall = beaconSpy.getCall(0); @@ -108,8 +111,12 @@ describe('batch uploader', () => { // Parse the beacon data which is a batch const batch = JSON.parse(blobContent as string); - expect(batch.events, 'Expected beacon data to have events').to.exist; - expect(batch.events.length, 'Expected beacon data to have at least one event').to.equal(3); + expect(batch.events, 'Expected beacon data to have events').to + .exist; + expect( + batch.events.length, + 'Expected beacon data to have at least one event', + ).to.equal(3); const event1 = batch.events[0]; const event2 = batch.events[1]; const event3 = batch.events[2]; @@ -120,16 +127,22 @@ describe('batch uploader', () => { console.log(event1.event_type); expect(event1.event_type).to.equal('session_start'); - expect(event2.event_type).to.equal('application_state_transition'); - expect(event2.event_type).to.equal('application_state_transition'); - expect(event2.data.application_transition_type).to.equal('application_initialized'); + expect(event2.event_type).to.equal( + 'application_state_transition', + ); + expect(event2.event_type).to.equal( + 'application_state_transition', + ); + expect(event2.data.application_transition_type).to.equal( + 'application_initialized', + ); expect(event3.event_type).to.equal('custom_event'); }); }); describe('should fire AST background events if flag is astBackgroundEvents "True"', () => { beforeEach(() => { - window.mParticle.config.flags.astBackgroundEvents = "True" + window.mParticle.config.flags.astBackgroundEvents = 'True'; }); afterEach(() => { @@ -142,98 +155,214 @@ describe('batch uploader', () => { } }); - it('should add application state transition event when visibility changes to hidden', async () => { - window.mParticle.init(apiKey, window.mParticle.config); - await waitForCondition(hasIdentifyReturned); - - const now = Date.now(); - clock = sinon.useFakeTimers({ - now: now, - shouldAdvanceTime: true - }); + it('should add application state transition event when visibility changes to hidden', async () => { + window.mParticle.init(apiKey, window.mParticle.config); + await waitForCondition(hasIdentifyReturned); - // Add a regular event first to ensure we have something in the queue - window.mParticle.logEvent('Test Event'); + const now = Date.now(); + clock = sinon.useFakeTimers({ + now: now, + shouldAdvanceTime: true, + }); - // Mock navigator.sendBeacon - beaconSpy = sinon.spy(navigator, 'sendBeacon'); + // Add a regular event first to ensure we have something in the queue + window.mParticle.logEvent('Test Event'); - // Trigger visibility change - Object.defineProperty(document, 'visibilityState', { - configurable: true, - get: () => 'hidden' - }); - document.dispatchEvent(new Event('visibilitychange')); + // Mock navigator.sendBeacon + beaconSpy = sinon.spy(navigator, 'sendBeacon'); - // Run all pending promises - await Promise.resolve(); + // Trigger visibility change + Object.defineProperty(document, 'visibilityState', { + configurable: true, + get: () => 'hidden', + }); + document.dispatchEvent(new Event('visibilitychange')); - // Verify that beacon was called - expect(beaconSpy.calledOnce, 'Expected beacon to be called once').to.be.true; + // Run all pending promises + await Promise.resolve(); - // Get the beacon call data - const beaconCall = beaconSpy.getCall(0); - expect(beaconCall, 'Expected beacon call to exist').to.exist; + // Verify that beacon was called + expect( + beaconSpy.calledOnce, + 'Expected beacon to be called once', + ).to.be.true; - // Get the Blob from the beacon call - const blob = beaconCall.args[1]; - expect(blob).to.be.instanceof(Blob); + // Get the beacon call data + const beaconCall = beaconSpy.getCall(0); + expect(beaconCall, 'Expected beacon call to exist').to.exist; - // Read the Blob content - const reader = new FileReader(); - const blobContent = await new Promise((resolve) => { - reader.onload = () => resolve(reader.result); - reader.readAsText(blob); - }); + // Get the Blob from the beacon call + const blob = beaconCall.args[1]; + expect(blob).to.be.instanceof(Blob); - // Parse the beacon data which is a batch - const batch = JSON.parse(blobContent as string); - expect(batch.events, 'Expected beacon data to have events').to.exist; - expect(batch.events.length, 'Expected beacon data to have at least one event').to.be.greaterThan(0); + // Read the Blob content + const reader = new FileReader(); + const blobContent = await new Promise((resolve) => { + reader.onload = () => resolve(reader.result); + reader.readAsText(blob); + }); - // Verify the AST event properties - const lastEvent = batch.events[batch.events.length - 1]; + // Parse the beacon data which is a batch + const batch = JSON.parse(blobContent as string); + expect(batch.events, 'Expected beacon data to have events').to + .exist; + expect( + batch.events.length, + 'Expected beacon data to have at least one event', + ).to.be.greaterThan(0); - expect(lastEvent.event_type).to.equal('application_state_transition'); - expect(lastEvent.data.application_transition_type).to.equal('application_background'); - expect(beaconSpy.calledOnce, 'Expected beacon to be called once').to.be.true; - }); + // Verify the AST event properties + const lastEvent = batch.events[batch.events.length - 1]; + expect(lastEvent.event_type).to.equal( + 'application_state_transition', + ); + expect(lastEvent.data.application_transition_type).to.equal( + 'application_background', + ); + expect( + beaconSpy.calledOnce, + 'Expected beacon to be called once', + ).to.be.true; + }); - it('should add application state transition event before pagehide', async () => { - window.mParticle.init(apiKey, window.mParticle.config); - await waitForCondition(hasIdentifyReturned); + it('should add application state transition event before pagehide', async () => { + window.mParticle.init(apiKey, window.mParticle.config); + await waitForCondition(hasIdentifyReturned); - const now = Date.now(); - clock = sinon.useFakeTimers({ - now: now, - shouldAdvanceTime: true + const now = Date.now(); + clock = sinon.useFakeTimers({ + now: now, + shouldAdvanceTime: true, + }); + + // Log a regular event + window.mParticle.logEvent('Test Event'); + + // Mock navigator.sendBeacon + beaconSpy = sinon.spy(navigator, 'sendBeacon'); + + // Create event listener that prevents default + const preventUnload = (e) => { + e.preventDefault(); + return (e.returnValue = ''); + }; + window.addEventListener('pagehide', preventUnload); + + try { + // Trigger pagehide + const pagehideEvent = new Event('pagehide', { + cancelable: true, + }); + window.dispatchEvent(pagehideEvent); + + // Run all pending promises + await Promise.resolve(); + clock.runAll(); + + // Verify that beacon was called + expect( + beaconSpy.calledOnce, + 'Expected beacon to be called once', + ).to.be.true; + + // Get the beacon call data + const beaconCall = beaconSpy.getCall(0); + expect(beaconCall, 'Expected beacon call to exist').to + .exist; + + // Get the Blob from the beacon call + const blob = beaconCall.args[1]; + expect(blob).to.be.instanceof(Blob); + + // Read the Blob content + const reader = new FileReader(); + const blobContent = await new Promise((resolve) => { + reader.onload = () => resolve(reader.result); + reader.readAsText(blob); + }); + + // Parse the beacon data which is a batch + const batch = JSON.parse(blobContent as string); + const events = batch.events; + + // The application state transition event should be the last event + expect(events[events.length - 1].event_type).to.equal( + 'application_state_transition', + ); + expect(events[events.length - 2].data.event_name).to.equal( + 'Test Event', + ); + } finally { + window.removeEventListener('pagehide', preventUnload); + } }); - // Log a regular event - window.mParticle.logEvent('Test Event'); + it('should create application state transition event with correct properties on event and batch', async () => { + window.mParticle.config.appName = 'Test App'; + window.mParticle.config.appVersion = '1.0.0'; + window.mParticle.config.package = 'com.test.app'; - // Mock navigator.sendBeacon - beaconSpy = sinon.spy(navigator, 'sendBeacon'); + window.mParticle.config.identifyRequest = { + userIdentities: { + email: 'test@test.com', + }, + }; - // Create event listener that prevents default - const preventUnload = (e) => { - e.preventDefault(); - return (e.returnValue = ''); - }; - window.addEventListener('pagehide', preventUnload); + const consentState = + window.mParticle.Consent.createConsentState(); + const timestamp = new Date().getTime(); + const ccpaConsent = window.mParticle.Consent.createCCPAConsent( + true, + timestamp, + 'consentDoc', + 'location', + 'hardware', + ); + const gdprConsent = window.mParticle.Consent.createGDPRConsent( + false, + timestamp, + 'consentDoc', + 'location', + 'hardware', + ); + consentState.setCCPAConsentState(ccpaConsent); + consentState.addGDPRConsentState('test purpose', gdprConsent); - try { - // Trigger pagehide - const pagehideEvent = new Event('pagehide', { cancelable: true }); - window.dispatchEvent(pagehideEvent); + window.mParticle.init(apiKey, window.mParticle.config); + await waitForCondition(hasIdentifyReturned); + window.mParticle.Identity.getCurrentUser().setUserAttribute( + 'foo', + 'value', + ); + const user = window.mParticle.Identity.getCurrentUser(); + user.setConsentState(consentState); + + const now = Date.now(); + clock = sinon.useFakeTimers({ + now: now, + shouldAdvanceTime: true, + }); + + // Mock navigator.sendBeacon + beaconSpy = sinon.spy(navigator, 'sendBeacon'); + + // Trigger visibility change + Object.defineProperty(document, 'visibilityState', { + configurable: true, + get: () => 'hidden', + }); + document.dispatchEvent(new Event('visibilitychange')); // Run all pending promises await Promise.resolve(); clock.runAll(); // Verify that beacon was called - expect(beaconSpy.calledOnce, 'Expected beacon to be called once').to.be.true; + expect( + beaconSpy.calledOnce, + 'Expected beacon to be called once', + ).to.be.true; // Get the beacon call data const beaconCall = beaconSpy.getCall(0); @@ -252,128 +381,72 @@ describe('batch uploader', () => { // Parse the beacon data which is a batch const batch = JSON.parse(blobContent as string); - const events = batch.events; - - // The application state transition event should be the last event - expect(events[events.length - 1].event_type).to.equal('application_state_transition'); - expect(events[events.length - 2].data.event_name).to.equal('Test Event'); - } finally { - window.removeEventListener('pagehide', preventUnload); - } - }); - - it('should create application state transition event with correct properties on event and batch', async () => { - window.mParticle.config.appName = 'Test App'; - window.mParticle.config.appVersion = '1.0.0'; - window.mParticle.config.package = 'com.test.app'; - - window.mParticle.config.identifyRequest = { - userIdentities: { - email: 'test@test.com' - } - }; - - const consentState = window.mParticle.Consent.createConsentState(); - const timestamp = new Date().getTime(); - const ccpaConsent = window.mParticle.Consent.createCCPAConsent( - true, - timestamp, - 'consentDoc', - 'location', - 'hardware' - ); - const gdprConsent = window.mParticle.Consent.createGDPRConsent( - false, - timestamp, - 'consentDoc', - 'location', - 'hardware' - ); - consentState.setCCPAConsentState(ccpaConsent); - consentState.addGDPRConsentState('test purpose', gdprConsent); - - window.mParticle.init(apiKey, window.mParticle.config); - await waitForCondition(hasIdentifyReturned); - window.mParticle.Identity.getCurrentUser().setUserAttribute('foo', 'value'); - const user = window.mParticle.Identity.getCurrentUser(); - user.setConsentState(consentState); - - const now = Date.now(); - clock = sinon.useFakeTimers({ - now: now, - shouldAdvanceTime: true - }); - - // Mock navigator.sendBeacon - beaconSpy = sinon.spy(navigator, 'sendBeacon'); - - // Trigger visibility change - Object.defineProperty(document, 'visibilityState', { - configurable: true, - get: () => 'hidden' - }); - document.dispatchEvent(new Event('visibilitychange')); - - // Run all pending promises - await Promise.resolve(); - clock.runAll(); - - // Verify that beacon was called - expect(beaconSpy.calledOnce, 'Expected beacon to be called once').to.be.true; - - // Get the beacon call data - const beaconCall = beaconSpy.getCall(0); - expect(beaconCall, 'Expected beacon call to exist').to.exist; + expect(batch.user_identities.email).to.equal('test@test.com'); + expect(batch.user_attributes.foo).to.equal('value'); + expect(batch.application_info.application_name).to.equal( + 'Test App', + ); + expect(batch.application_info.application_version).to.equal( + '1.0.0', + ); + expect(batch.application_info.package).to.equal('com.test.app'); + expect(batch.consent_state).to.have.property('ccpa'); + expect(batch.consent_state.ccpa).to.have.property( + 'data_sale_opt_out', + ); + expect( + batch.consent_state.ccpa.data_sale_opt_out, + ).to.have.property('consented'); + expect( + batch.consent_state.ccpa.data_sale_opt_out.consented, + ).to.equal(true); + expect( + batch.consent_state.ccpa.data_sale_opt_out, + ).to.have.property('timestamp_unixtime_ms'); + expect( + batch.consent_state.ccpa.data_sale_opt_out, + ).to.have.property('document'); + expect(batch.consent_state.gdpr).to.have.property( + 'test purpose', + ); + expect( + batch.consent_state.gdpr['test purpose'], + ).to.have.property('consented'); + expect( + batch.consent_state.gdpr['test purpose'].consented, + ).to.equal(false); + expect( + batch.consent_state.gdpr['test purpose'], + ).to.have.property('timestamp_unixtime_ms'); + expect( + batch.consent_state.gdpr['test purpose'], + ).to.have.property('document'); - // Get the Blob from the beacon call - const blob = beaconCall.args[1]; - expect(blob).to.be.instanceof(Blob); + const astEvent = batch.events[batch.events.length - 1]; - // Read the Blob content - const reader = new FileReader(); - const blobContent = await new Promise((resolve) => { - reader.onload = () => resolve(reader.result); - reader.readAsText(blob); + expect(astEvent.event_type).to.equal( + 'application_state_transition', + ); + expect(astEvent.data.active_time_on_site_ms).to.be.a('number'); + expect(astEvent.data.application_transition_type).to.equal( + 'application_background', + ); + expect(astEvent.data.custom_attributes).to.exist; + expect(astEvent.data.is_first_run).to.be.a('boolean'); + expect(astEvent.data.is_upgrade).to.be.a('boolean'); + expect(astEvent.data.location).to.equal(null); + expect(astEvent.data.session_start_unixtime_ms).to.be.a( + 'number', + ); + expect(astEvent.data.session_uuid).to.exist; + expect(astEvent.data.source_message_id).to.be.a('string'); + expect(astEvent.data.timestamp_unixtime_ms).to.be.a('number'); + + // reset to prevent other tests from potentially failing + delete window.mParticle.config.appName; + delete window.mParticle.config.appVersion; + delete window.mParticle.config.package; }); - - // Parse the beacon data which is a batch - const batch = JSON.parse(blobContent as string); - expect(batch.user_identities.email).to.equal('test@test.com'); - expect(batch.user_attributes.foo).to.equal('value'); - expect(batch.application_info.application_name).to.equal('Test App'); - expect(batch.application_info.application_version).to.equal('1.0.0'); - expect(batch.application_info.package).to.equal('com.test.app'); - expect(batch.consent_state).to.have.property('ccpa'); - expect(batch.consent_state.ccpa).to.have.property('data_sale_opt_out'); - expect(batch.consent_state.ccpa.data_sale_opt_out).to.have.property('consented'); - expect(batch.consent_state.ccpa.data_sale_opt_out.consented).to.equal(true); - expect(batch.consent_state.ccpa.data_sale_opt_out).to.have.property('timestamp_unixtime_ms'); - expect(batch.consent_state.ccpa.data_sale_opt_out).to.have.property('document'); - expect(batch.consent_state.gdpr).to.have.property('test purpose'); - expect(batch.consent_state.gdpr['test purpose']).to.have.property('consented'); - expect(batch.consent_state.gdpr['test purpose'].consented).to.equal(false); - expect(batch.consent_state.gdpr['test purpose']).to.have.property('timestamp_unixtime_ms'); - expect(batch.consent_state.gdpr['test purpose']).to.have.property('document'); - - const astEvent = batch.events[batch.events.length - 1]; - - expect(astEvent.event_type).to.equal('application_state_transition'); - expect(astEvent.data.active_time_on_site_ms).to.be.a('number'); - expect(astEvent.data.application_transition_type).to.equal('application_background'); - expect(astEvent.data.custom_attributes).to.exist; - expect(astEvent.data.is_first_run).to.be.a('boolean'); - expect(astEvent.data.is_upgrade).to.be.a('boolean'); - expect(astEvent.data.location).to.equal(null); - expect(astEvent.data.session_start_unixtime_ms).to.be.a('number'); - expect(astEvent.data.session_uuid).to.exist; - expect(astEvent.data.source_message_id).to.be.a('string'); - expect(astEvent.data.timestamp_unixtime_ms).to.be.a('number'); - - // reset to prevent other tests from potentially failing - delete window.mParticle.config.appName; - delete window.mParticle.config.appVersion; - delete window.mParticle.config.package; - }); }); }); @@ -384,10 +457,10 @@ describe('batch uploader', () => { ...window.mParticle.config, flags: { ...window.mParticle.config.flags, - astBackgroundEvents: "True" - } + astBackgroundEvents: 'True', + }, }; - await Promise.resolve() + await Promise.resolve(); }); afterEach(() => { @@ -408,11 +481,11 @@ describe('batch uploader', () => { window.mParticle.init(apiKey, window.mParticle.config); await waitForCondition(hasIdentifyReturned); - + const now = Date.now(); clock = sinon.useFakeTimers({ now: now, - shouldAdvanceTime: true + shouldAdvanceTime: true, }); // Add a regular event first to ensure we have something in the queue @@ -424,7 +497,7 @@ describe('batch uploader', () => { // Trigger visibility change Object.defineProperty(document, 'visibilityState', { configurable: true, - get: () => 'hidden' + get: () => 'hidden', }); document.dispatchEvent(new Event('visibilitychange')); @@ -433,7 +506,8 @@ describe('batch uploader', () => { await Promise.resolve(); // clock.runAll(); - expect(beaconSpy.calledOnce, 'Expected beacon to be called once').to.be.true; + expect(beaconSpy.calledOnce, 'Expected beacon to be called once').to + .be.true; // Get the beacon call data const beaconCall = beaconSpy.getCall(0); @@ -452,13 +526,19 @@ describe('batch uploader', () => { // Parse the beacon data which is a batch const batch = JSON.parse(blobContent as string); - expect(batch.events, 'Expected beacon data to have events').to.exist; - expect(batch.events.length, 'Expected beacon data to have at least one event').to.be.greaterThan(0); + expect(batch.events, 'Expected beacon data to have events').to + .exist; + expect( + batch.events.length, + 'Expected beacon data to have at least one event', + ).to.be.greaterThan(0); // Verify the AST event properties const lastEvent = batch.events[batch.events.length - 1]; - expect(lastEvent.event_type).to.equal('application_state_transition'); + expect(lastEvent.event_type).to.equal( + 'application_state_transition', + ); // Clean up clock.tick(500); @@ -467,17 +547,18 @@ describe('batch uploader', () => { // Run all pending promises await Promise.resolve(); - expect(beaconSpy.calledOnce, 'Expected beacon to be called twice').to.be.true; + expect(beaconSpy.calledOnce, 'Expected beacon to be called twice') + .to.be.true; }); it('should fire multiple ASTs when another visibility event happens outside the debounce time window', async () => { window.mParticle.init(apiKey, window.mParticle.config); await waitForCondition(hasIdentifyReturned); - + const now = Date.now(); clock = sinon.useFakeTimers({ now: now, - shouldAdvanceTime: true + shouldAdvanceTime: true, }); // Add a regular event first to ensure we have something in the queue @@ -489,7 +570,7 @@ describe('batch uploader', () => { // Trigger visibility change Object.defineProperty(document, 'visibilityState', { configurable: true, - get: () => 'hidden' + get: () => 'hidden', }); document.dispatchEvent(new Event('visibilitychange')); @@ -497,7 +578,8 @@ describe('batch uploader', () => { await Promise.resolve(); // Verify that beacon was called - expect(beaconSpy.calledOnce, 'Expected beacon to be called once').to.be.true; + expect(beaconSpy.calledOnce, 'Expected beacon to be called once').to + .be.true; // Get the beacon call data const beaconCall = beaconSpy.getCall(0); @@ -516,16 +598,25 @@ describe('batch uploader', () => { // Parse the beacon data which is a batch const batch = JSON.parse(blobContent as string); - expect(batch.events, 'Expected beacon data to have events').to.exist; - expect(batch.events.length, 'Expected beacon data to have at least one event').to.be.greaterThan(0); + expect(batch.events, 'Expected beacon data to have events').to + .exist; + expect( + batch.events.length, + 'Expected beacon data to have at least one event', + ).to.be.greaterThan(0); // Verify the AST event properties const lastEvent = batch.events[batch.events.length - 1]; - expect(lastEvent.event_type).to.equal('application_state_transition'); - expect(lastEvent.data.application_transition_type).to.equal('application_background'); + expect(lastEvent.event_type).to.equal( + 'application_state_transition', + ); + expect(lastEvent.data.application_transition_type).to.equal( + 'application_background', + ); - expect(beaconSpy.calledOnce, 'Expected beacon to be called once').to.be.true; + expect(beaconSpy.calledOnce, 'Expected beacon to be called once').to + .be.true; // Clean up clock.tick(1500); document.dispatchEvent(new Event('visibilitychange')); @@ -533,94 +624,95 @@ describe('batch uploader', () => { // Run all pending promises await Promise.resolve(); - expect(beaconSpy.calledTwice, 'Expected beacon to be called twice').to.be.true; + expect(beaconSpy.calledTwice, 'Expected beacon to be called twice') + .to.be.true; }); - }) + }); describe('Unit Tests', () => { describe('#queueEvent', () => { it('should add events to the Pending Events Queue', () => { window.mParticle._resetForTests(MPConfig); window.mParticle.init(apiKey, window.mParticle.config); - - waitForCondition(hasIdentifyReturned) - .then(() => { - const mpInstance = window.mParticle.getInstance(); - const uploader = new BatchUploader(mpInstance, 1000); - - const event: SDKEvent = { - EventName: 'Test Event', - EventAttributes: null, - SourceMessageId: 'test-smid', - EventDataType: 4, - EventCategory: 1, - ExpandedEventCount: 0, - CustomFlags: {}, - IsFirstRun: false, - CurrencyCode: null, - MPID: 'testMPID', - ConsentState: null, - UserAttributes: {}, - UserIdentities: [], - SDKVersion: 'X.XX.XX', - SessionId: 'test-session-id', - SessionStartDate: 0, - Debug: false, - DeviceId: 'test-device', - Timestamp: 0, - ActiveTimeOnSite: 10 - }; - - uploader.queueEvent(event); - - expect(uploader.eventsQueuedForProcessing.length).to.eql(1); - }) + waitForCondition(hasIdentifyReturned).then(() => { + const mpInstance = window.mParticle.getInstance(); + + const uploader = new BatchUploader(mpInstance, 1000); + + const event: SDKEvent = { + EventName: 'Test Event', + EventAttributes: null, + SourceMessageId: 'test-smid', + EventDataType: 4, + EventCategory: 1, + ExpandedEventCount: 0, + CustomFlags: {}, + IsFirstRun: false, + CurrencyCode: null, + MPID: 'testMPID', + ConsentState: null, + UserAttributes: {}, + UserIdentities: [], + SDKVersion: 'X.XX.XX', + SessionId: 'test-session-id', + SessionStartDate: 0, + Debug: false, + DeviceId: 'test-device', + Timestamp: 0, + ActiveTimeOnSite: 10, + }; + + uploader.queueEvent(event); + + expect(uploader.eventsQueuedForProcessing.length).to.eql(1); + }); }); it('should reject batches without events', () => { window.mParticle._resetForTests(MPConfig); window.mParticle.init(apiKey, window.mParticle.config); - waitForCondition(hasIdentifyReturned) - .then(() => { + waitForCondition(hasIdentifyReturned).then(() => { + const mpInstance = window.mParticle.getInstance(); - const mpInstance = window.mParticle.getInstance(); - - const uploader = new BatchUploader(mpInstance, 1000); + const uploader = new BatchUploader(mpInstance, 1000); - uploader.queueEvent(null); - uploader.queueEvent({} as unknown as SDKEvent); + uploader.queueEvent(null); + uploader.queueEvent({} as unknown as SDKEvent); - expect(uploader.eventsQueuedForProcessing).to.eql([]); - expect(uploader.batchesQueuedForProcessing).to.eql([]); - }) + expect(uploader.eventsQueuedForProcessing).to.eql([]); + expect(uploader.batchesQueuedForProcessing).to.eql([]); + }); }); it('should add events in the order they are received', () => { window.mParticle._resetForTests(MPConfig); window.mParticle.init(apiKey, window.mParticle.config); - waitForCondition(hasIdentifyReturned) - .then(() => { - - const mpInstance = window.mParticle.getInstance(); - - const uploader = new BatchUploader(mpInstance, 1000); - - uploader.queueEvent(event1); - uploader.queueEvent(event2); - uploader.queueEvent(event3); - - expect(uploader.eventsQueuedForProcessing.length).to.eql(3); - expect(uploader.eventsQueuedForProcessing[0]).to.eql(event1); - expect(uploader.eventsQueuedForProcessing[1]).to.eql(event2); - expect(uploader.eventsQueuedForProcessing[2]).to.eql(event3); - }) + waitForCondition(hasIdentifyReturned).then(() => { + const mpInstance = window.mParticle.getInstance(); + + const uploader = new BatchUploader(mpInstance, 1000); + + uploader.queueEvent(event1); + uploader.queueEvent(event2); + uploader.queueEvent(event3); + + expect(uploader.eventsQueuedForProcessing.length).to.eql(3); + expect(uploader.eventsQueuedForProcessing[0]).to.eql( + event1, + ); + expect(uploader.eventsQueuedForProcessing[1]).to.eql( + event2, + ); + expect(uploader.eventsQueuedForProcessing[2]).to.eql( + event3, + ); + }); }); }); describe('#uploadBatches', () => { - it('should reject batches without events', async () => { window.mParticle.init(apiKey, window.mParticle.config); @@ -642,7 +734,7 @@ describe('batch uploader', () => { const actualBatch = batchValidator.returnBatch(baseEvent); const eventlessBatch = batchValidator.returnBatch( - {} as unknown as BaseEvent + {} as unknown as BaseEvent, ); fetchMock.resetHistory(); @@ -650,13 +742,13 @@ describe('batch uploader', () => { await (uploader).uploadBatches( newLogger, [actualBatch, eventlessBatch], - false + false, ); expect(fetchMock.calls().length).to.equal(1); const actualBatchResult = JSON.parse( - fetchMock.calls()[0][1].body as string + fetchMock.calls()[0][1].body as string, ); expect(actualBatchResult.events.length).to.equal(1); @@ -667,146 +759,148 @@ describe('batch uploader', () => { window.mParticle.init(apiKey, window.mParticle.config); waitForCondition(hasIdentifyReturned) - .then(async () => { - - fetchMock.post(urls.events, 500); - - const newLogger = new Logger(window.mParticle.config); - const mpInstance = window.mParticle.getInstance(); - - const uploader = new BatchUploader(mpInstance, 1000); - - const batchValidator = new _BatchValidator(); - - const batch1 = batchValidator.returnBatch({ - messageType: 4, - name: 'Test Event 1', - }); - - const batch2 = batchValidator.returnBatch({ - messageType: 4, - name: 'Test Event 2', - }); - const batch3 = batchValidator.returnBatch({ - messageType: 4, - name: 'Test Event 3', - }); - - // HACK: Directly access uploader to Force an upload - const batchesNotUploaded = await (uploader).uploadBatches( - newLogger, - [batch1, batch2, batch3], - false - ); - - expect( - batchesNotUploaded.length, - 'Should have 3 uploaded batches' - ).to.equal(3); - - expect( - batchesNotUploaded[0].events[0].data.event_name - ).to.equal('Test Event 1'); - expect( - batchesNotUploaded[1].events[0].data.event_name - ).to.equal('Test Event 2'); - expect( - batchesNotUploaded[2].events[0].data.event_name - ).to.equal('Test Event 3'); - }) - .catch((e) => { - }); + .then(async () => { + fetchMock.post(urls.events, 500); + + const newLogger = new Logger(window.mParticle.config); + const mpInstance = window.mParticle.getInstance(); + + const uploader = new BatchUploader(mpInstance, 1000); + + const batchValidator = new _BatchValidator(); + + const batch1 = batchValidator.returnBatch({ + messageType: 4, + name: 'Test Event 1', + }); + + const batch2 = batchValidator.returnBatch({ + messageType: 4, + name: 'Test Event 2', + }); + const batch3 = batchValidator.returnBatch({ + messageType: 4, + name: 'Test Event 3', + }); + + // HACK: Directly access uploader to Force an upload + const batchesNotUploaded = await (( + uploader + )).uploadBatches( + newLogger, + [batch1, batch2, batch3], + false, + ); + + expect( + batchesNotUploaded.length, + 'Should have 3 uploaded batches', + ).to.equal(3); + + expect( + batchesNotUploaded[0].events[0].data.event_name, + ).to.equal('Test Event 1'); + expect( + batchesNotUploaded[1].events[0].data.event_name, + ).to.equal('Test Event 2'); + expect( + batchesNotUploaded[2].events[0].data.event_name, + ).to.equal('Test Event 3'); + }) + .catch((e) => {}); }); it('should return batches that fail to upload with 429 errors', async () => { window.mParticle.init(apiKey, window.mParticle.config); - waitForCondition(hasIdentifyReturned) - .then(async () => { - fetchMock.post(urls.events, 429); - - const newLogger = new Logger(window.mParticle.config); - const mpInstance = window.mParticle.getInstance(); - - const uploader = new BatchUploader(mpInstance, 1000); - - const batchValidator = new _BatchValidator(); - - const batch1 = batchValidator.returnBatch({ - messageType: 4, - name: 'Test Event 1', - }); - - const batch2 = batchValidator.returnBatch({ - messageType: 4, - name: 'Test Event 2', + waitForCondition(hasIdentifyReturned).then(async () => { + fetchMock.post(urls.events, 429); + + const newLogger = new Logger(window.mParticle.config); + const mpInstance = window.mParticle.getInstance(); + + const uploader = new BatchUploader(mpInstance, 1000); + + const batchValidator = new _BatchValidator(); + + const batch1 = batchValidator.returnBatch({ + messageType: 4, + name: 'Test Event 1', + }); + + const batch2 = batchValidator.returnBatch({ + messageType: 4, + name: 'Test Event 2', + }); + const batch3 = batchValidator.returnBatch({ + messageType: 4, + name: 'Test Event 3', + }); + + // HACK: Directly access uploader to Force an upload + const batchesNotUploaded = await (( + uploader + )).uploadBatches( + newLogger, + [batch1, batch2, batch3], + false, + ); + + expect( + batchesNotUploaded.length, + 'Should have 3 uploaded batches', + ).to.equal(3); + + expect( + batchesNotUploaded[0].events[0].data.event_name, + ).to.equal('Test Event 1'); + expect( + batchesNotUploaded[1].events[0].data.event_name, + ).to.equal('Test Event 2'); + expect( + batchesNotUploaded[2].events[0].data.event_name, + ).to.equal('Test Event 3'); }); - const batch3 = batchValidator.returnBatch({ - messageType: 4, - name: 'Test Event 3', - }); - - // HACK: Directly access uploader to Force an upload - const batchesNotUploaded = await (uploader).uploadBatches( - newLogger, - [batch1, batch2, batch3], - false - ); - - expect( - batchesNotUploaded.length, - 'Should have 3 uploaded batches' - ).to.equal(3); - - expect( - batchesNotUploaded[0].events[0].data.event_name - ).to.equal('Test Event 1'); - expect( - batchesNotUploaded[1].events[0].data.event_name - ).to.equal('Test Event 2'); - expect( - batchesNotUploaded[2].events[0].data.event_name - ).to.equal('Test Event 3'); - }) }); it('should return null if batches fail to upload with 401 errors', async () => { window.mParticle.init(apiKey, window.mParticle.config); - waitForCondition(hasIdentifyReturned) - .then(async () => { - fetchMock.post(urls.events, 401); + waitForCondition(hasIdentifyReturned).then(async () => { + fetchMock.post(urls.events, 401); - const newLogger = new Logger(window.mParticle.config); - const mpInstance = window.mParticle.getInstance(); + const newLogger = new Logger(window.mParticle.config); + const mpInstance = window.mParticle.getInstance(); - const uploader = new BatchUploader(mpInstance, 1000); + const uploader = new BatchUploader(mpInstance, 1000); - const batchValidator = new _BatchValidator(); + const batchValidator = new _BatchValidator(); - const batch1 = batchValidator.returnBatch({ - messageType: 4, - name: 'Test Event 1', - }); + const batch1 = batchValidator.returnBatch({ + messageType: 4, + name: 'Test Event 1', + }); - const batch2 = batchValidator.returnBatch({ - messageType: 4, - name: 'Test Event 2', - }); - const batch3 = batchValidator.returnBatch({ - messageType: 4, - name: 'Test Event 3', - }); + const batch2 = batchValidator.returnBatch({ + messageType: 4, + name: 'Test Event 2', + }); + const batch3 = batchValidator.returnBatch({ + messageType: 4, + name: 'Test Event 3', + }); - // HACK: Directly access uploader to Force an upload - const batchesNotUploaded = await (uploader).uploadBatches( - newLogger, - [batch1, batch2, batch3], - false - ); + // HACK: Directly access uploader to Force an upload + const batchesNotUploaded = await (( + uploader + )).uploadBatches( + newLogger, + [batch1, batch2, batch3], + false, + ); - expect(batchesNotUploaded === null).to.equal(true); - }) + expect(batchesNotUploaded === null).to.equal(true); + }); }); it('should not throw an error when upload is called while storage has not been created yet', async () => { @@ -818,65 +912,71 @@ describe('batch uploader', () => { const mpInstance = window.mParticle.getInstance(); const uploader = mpInstance._APIClient.uploader; - expect(uploader).to.equal(null) + expect(uploader).to.equal(null); - expect(() => { window.mParticle.upload() }).to.not.throw(TypeError, /Cannot read properties of null \(reading 'prepareAndUpload'\)/) + expect(() => { + window.mParticle.upload(); + }).to.not.throw( + TypeError, + /Cannot read properties of null \(reading 'prepareAndUpload'\)/, + ); }); it('should return batches that fail to unknown HTTP errors', async () => { window.mParticle.init(apiKey, window.mParticle.config); waitForCondition(hasIdentifyReturned) - .then(async () => { - fetchMock.post(urls.events, 400); - - const newLogger = new Logger(window.mParticle.config); - const mpInstance = window.mParticle.getInstance(); - - const uploader = new BatchUploader(mpInstance, 1000); - - const batchValidator = new _BatchValidator(); - - const batch1 = batchValidator.returnBatch({ - messageType: 4, - name: 'Test Event 1', - }); - - const batch2 = batchValidator.returnBatch({ - messageType: 4, - name: 'Test Event 2', - }); - const batch3 = batchValidator.returnBatch({ - messageType: 4, - name: 'Test Event 3', - }); - - // HACK: Directly access uploader to Force an upload - const batchesNotUploaded = await (uploader).uploadBatches( - newLogger, - [batch1, batch2, batch3], - false - ); - - expect(batchesNotUploaded).to.be.ok; - - expect( - batchesNotUploaded.length, - 'Should have 3 uploaded batches' - ).to.equal(3); - - expect( - batchesNotUploaded[0].events[0].data.event_name - ).to.equal('Test Event 1'); - expect( - batchesNotUploaded[1].events[0].data.event_name - ).to.equal('Test Event 2'); - expect( - batchesNotUploaded[2].events[0].data.event_name - ).to.equal('Test Event 3'); - }) - .catch((e) => { - }); + .then(async () => { + fetchMock.post(urls.events, 400); + + const newLogger = new Logger(window.mParticle.config); + const mpInstance = window.mParticle.getInstance(); + + const uploader = new BatchUploader(mpInstance, 1000); + + const batchValidator = new _BatchValidator(); + + const batch1 = batchValidator.returnBatch({ + messageType: 4, + name: 'Test Event 1', + }); + + const batch2 = batchValidator.returnBatch({ + messageType: 4, + name: 'Test Event 2', + }); + const batch3 = batchValidator.returnBatch({ + messageType: 4, + name: 'Test Event 3', + }); + + // HACK: Directly access uploader to Force an upload + const batchesNotUploaded = await (( + uploader + )).uploadBatches( + newLogger, + [batch1, batch2, batch3], + false, + ); + + expect(batchesNotUploaded).to.be.ok; + + expect( + batchesNotUploaded.length, + 'Should have 3 uploaded batches', + ).to.equal(3); + + expect( + batchesNotUploaded[0].events[0].data.event_name, + ).to.equal('Test Event 1'); + expect( + batchesNotUploaded[1].events[0].data.event_name, + ).to.equal('Test Event 2'); + expect( + batchesNotUploaded[2].events[0].data.event_name, + ).to.equal('Test Event 3'); + }) + .catch((e) => {}); }); }); }); @@ -902,57 +1002,56 @@ describe('batch uploader', () => { window.mParticle.init(apiKey, window.mParticle.config); waitForCondition(hasIdentifyReturned) - .then(() => { - const getItemSpy = sinon.spy(Storage.prototype, 'getItem'); - const setItemSpy = sinon.spy(Storage.prototype, 'setItem'); - - const mpInstance = window.mParticle.getInstance(); - - const uploader = new BatchUploader(mpInstance, 1000); - - const event: SDKEvent = { - EventName: 'Test Event', - EventAttributes: null, - SourceMessageId: 'test-smid', - EventDataType: 4, - EventCategory: 1, - ExpandedEventCount: 0, - CustomFlags: {}, - IsFirstRun: false, - CurrencyCode: null, - MPID: 'testMPID', - ConsentState: null, - UserAttributes: {}, - UserIdentities: [], - SDKVersion: 'X.XX.XX', - SessionId: 'test-session-id', - SessionStartDate: 0, - Debug: false, - DeviceId: 'test-device', - Timestamp: 0, - ActiveTimeOnSite: 10 - }; - - const expectedEvent = [event]; - - uploader.queueEvent(event); - - expect(uploader.eventsQueuedForProcessing.length).to.eql(1); - - expect(setItemSpy.called).to.eq(true); - expect(setItemSpy.getCall(0).lastArg).to.equal( - JSON.stringify(expectedEvent) - ); - - expect(getItemSpy.called).to.eq(true); - expect(getItemSpy.getCall(0).lastArg).to.equal( - 'mprtcl-v4_abcdef-events' - ); - - done(); - }) - .catch((e) => { - }); + .then(() => { + const getItemSpy = sinon.spy(Storage.prototype, 'getItem'); + const setItemSpy = sinon.spy(Storage.prototype, 'setItem'); + + const mpInstance = window.mParticle.getInstance(); + + const uploader = new BatchUploader(mpInstance, 1000); + + const event: SDKEvent = { + EventName: 'Test Event', + EventAttributes: null, + SourceMessageId: 'test-smid', + EventDataType: 4, + EventCategory: 1, + ExpandedEventCount: 0, + CustomFlags: {}, + IsFirstRun: false, + CurrencyCode: null, + MPID: 'testMPID', + ConsentState: null, + UserAttributes: {}, + UserIdentities: [], + SDKVersion: 'X.XX.XX', + SessionId: 'test-session-id', + SessionStartDate: 0, + Debug: false, + DeviceId: 'test-device', + Timestamp: 0, + ActiveTimeOnSite: 10, + }; + + const expectedEvent = [event]; + + uploader.queueEvent(event); + + expect(uploader.eventsQueuedForProcessing.length).to.eql(1); + + expect(setItemSpy.called).to.eq(true); + expect(setItemSpy.getCall(0).lastArg).to.equal( + JSON.stringify(expectedEvent), + ); + + expect(getItemSpy.called).to.eq(true); + expect(getItemSpy.getCall(0).lastArg).to.equal( + 'mprtcl-v4_abcdef-events', + ); + + done(); + }) + .catch((e) => {}); }); it('should not use local storage when disabled', () => { @@ -963,52 +1062,50 @@ describe('batch uploader', () => { window.mParticle._resetForTests(MPConfig); window.mParticle.init(apiKey, window.mParticle.config); waitForCondition(hasIdentifyReturned) - .then( () => { - - const getItemSpy = sinon.spy(Storage.prototype, 'getItem'); - const setItemSpy = sinon.spy(Storage.prototype, 'setItem'); - - const mpInstance = window.mParticle.getInstance(); - - const uploader = new BatchUploader(mpInstance, 1000); - - const event: SDKEvent = { - EventName: 'Test Event', - EventAttributes: null, - SourceMessageId: 'test-smid', - EventDataType: 4, - EventCategory: 1, - ExpandedEventCount: 0, - CustomFlags: {}, - IsFirstRun: false, - CurrencyCode: null, - MPID: 'testMPID', - ConsentState: null, - UserAttributes: {}, - UserIdentities: [], - SDKVersion: 'X.XX.XX', - SessionId: 'test-session-id', - SessionStartDate: 0, - Debug: false, - DeviceId: 'test-device', - Timestamp: 0, - ActiveTimeOnSite: 10 - }; - - uploader.queueEvent(event); - - expect(uploader.eventsQueuedForProcessing.length).to.eql(1); - expect(uploader.eventsQueuedForProcessing[0]).to.eql(event); - - expect(setItemSpy.called).to.eq(false); - expect(getItemSpy.called).to.eq(false); - - expect( - window.localStorage.getItem('mprtcl-v4_abcdef-events') - ).to.equal(null); - }) - .catch((e) => { - }); + .then(() => { + const getItemSpy = sinon.spy(Storage.prototype, 'getItem'); + const setItemSpy = sinon.spy(Storage.prototype, 'setItem'); + + const mpInstance = window.mParticle.getInstance(); + + const uploader = new BatchUploader(mpInstance, 1000); + + const event: SDKEvent = { + EventName: 'Test Event', + EventAttributes: null, + SourceMessageId: 'test-smid', + EventDataType: 4, + EventCategory: 1, + ExpandedEventCount: 0, + CustomFlags: {}, + IsFirstRun: false, + CurrencyCode: null, + MPID: 'testMPID', + ConsentState: null, + UserAttributes: {}, + UserIdentities: [], + SDKVersion: 'X.XX.XX', + SessionId: 'test-session-id', + SessionStartDate: 0, + Debug: false, + DeviceId: 'test-device', + Timestamp: 0, + ActiveTimeOnSite: 10, + }; + + uploader.queueEvent(event); + + expect(uploader.eventsQueuedForProcessing.length).to.eql(1); + expect(uploader.eventsQueuedForProcessing[0]).to.eql(event); + + expect(setItemSpy.called).to.eq(false); + expect(getItemSpy.called).to.eq(false); + + expect( + window.localStorage.getItem('mprtcl-v4_abcdef-events'), + ).to.equal(null); + }) + .catch((e) => {}); }); }); @@ -1022,7 +1119,7 @@ describe('batch uploader', () => { window.localStorage.clear(); }); - it('should not save events or batches in local storage', done => { + it('should not save events or batches in local storage', (done) => { const eventStorageKey = 'mprtcl-v4_abcdef-events'; const batchStorageKey = 'mprtcl-v4_abcdef-batches'; @@ -1030,40 +1127,41 @@ describe('batch uploader', () => { window.mParticle.init(apiKey, window.mParticle.config); waitForCondition(hasIdentifyReturned) - .then(() => { - const mpInstance = window.mParticle.getInstance(); - const uploader = mpInstance._APIClient.uploader; + .then(() => { + const mpInstance = window.mParticle.getInstance(); + const uploader = mpInstance._APIClient.uploader; - // Init will fire a Session Start and AST. We are adding event0 - // to show that manually queued events will also be grouped - // into a batch - uploader.queueEvent(event0); + // Init will fire a Session Start and AST. We are adding event0 + // to show that manually queued events will also be grouped + // into a batch + uploader.queueEvent(event0); - const eventQueue: SDKEvent[] = uploader.eventsQueuedForProcessing; + const eventQueue: SDKEvent[] = + uploader.eventsQueuedForProcessing; - expect(eventQueue.length).to.equal(3); + expect(eventQueue.length).to.equal(3); - expect( - window.localStorage.getItem(eventStorageKey), - 'Local Storage Events should be empty' - ).to.equal(null); + expect( + window.localStorage.getItem(eventStorageKey), + 'Local Storage Events should be empty', + ).to.equal(null); - const batchQueue: Batch[] = uploader.batchesQueuedForProcessing; + const batchQueue: Batch[] = + uploader.batchesQueuedForProcessing; - // Manually initiate the upload process - turn event into batches and upload the batch - window.mParticle.upload(); + // Manually initiate the upload process - turn event into batches and upload the batch + window.mParticle.upload(); - expect(batchQueue.length).to.equal(2); + expect(batchQueue.length).to.equal(2); - expect( - window.localStorage.getItem(batchStorageKey), - 'Local Storage Batches should be empty' - ).to.equal(null); + expect( + window.localStorage.getItem(batchStorageKey), + 'Local Storage Batches should be empty', + ).to.equal(null); - done(); - }) - .catch((e) => { - }); + done(); + }) + .catch((e) => {}); }); }); @@ -1086,44 +1184,50 @@ describe('batch uploader', () => { sinon.restore(); }); - it('should store events in Session Storage in order of creation', done => { + it('should store events in Session Storage in order of creation', (done) => { const eventStorageKey = 'mprtcl-v4_abcdef-events'; window.mParticle._resetForTests(MPConfig); window.mParticle.init(apiKey, window.mParticle.config); waitForCondition(hasIdentifyReturned) - .then(() => { - const mpInstance = window.mParticle.getInstance(); - const uploader = mpInstance._APIClient.uploader; - - // Init will fire a Session Start and AST. We are adding event0 - // to show that manually queued events will also be grouped - // into a batch - uploader.queueEvent(event0); - - const eventQueue: SDKEvent[] = uploader.eventsQueuedForProcessing; - - expect(eventQueue.length).to.equal(3); - - const storedEvents: SDKEvent[] = JSON.parse( - window.sessionStorage.getItem(eventStorageKey) - ); - - expect(storedEvents.length, 'Local Storage Events').to.equal(3); - - expect(storedEvents[0], 'Local Storage: Session Start').to.eql( - eventQueue[0] - ); - expect(storedEvents[1], 'Local Storage: AST').to.eql(eventQueue[1]); - expect(storedEvents[2], 'Local Storage: Test Event 0').to.eql( - eventQueue[2] - ); - - done(); - }) - .catch((e) => { - }) - + .then(() => { + const mpInstance = window.mParticle.getInstance(); + const uploader = mpInstance._APIClient.uploader; + + // Init will fire a Session Start and AST. We are adding event0 + // to show that manually queued events will also be grouped + // into a batch + uploader.queueEvent(event0); + + const eventQueue: SDKEvent[] = + uploader.eventsQueuedForProcessing; + + expect(eventQueue.length).to.equal(3); + + const storedEvents: SDKEvent[] = JSON.parse( + window.sessionStorage.getItem(eventStorageKey), + ); + + expect( + storedEvents.length, + 'Local Storage Events', + ).to.equal(3); + + expect( + storedEvents[0], + 'Local Storage: Session Start', + ).to.eql(eventQueue[0]); + expect(storedEvents[1], 'Local Storage: AST').to.eql( + eventQueue[1], + ); + expect( + storedEvents[2], + 'Local Storage: Test Event 0', + ).to.eql(eventQueue[2]); + + done(); + }) + .catch((e) => {}); }); it('should purge events from Session Storage upon Batch Creation', async () => { @@ -1134,41 +1238,53 @@ describe('batch uploader', () => { window.mParticle._resetForTests(MPConfig); window.mParticle.init(apiKey, window.mParticle.config); waitForCondition(hasIdentifyReturned) - .then(async () => { - const mpInstance = window.mParticle.getInstance(); - const uploader = mpInstance._APIClient.uploader; - - // Init will fire a Session Start and AST. We are adding event0 - // to show that manually queued events will also be grouped - // into a batch - uploader.queueEvent(event0); - - expect(uploader.eventsQueuedForProcessing.length).to.equal(3); - expect(uploader.batchesQueuedForProcessing.length).to.equal(0); - - expect( - window.sessionStorage.getItem(eventStorageKey), - 'Queued Events should appear in Session Storage' - ).to.be.ok; - expect( - JSON.parse(window.sessionStorage.getItem(eventStorageKey)) - .length - ).to.equal(3); - - // Manually initiate the upload process - turn event into batches and upload the batch - await window.mParticle.getInstance()._APIClient.uploader.prepareAndUpload(); - - // If Session Storage is purged, it should return an empty string - expect(window.sessionStorage.getItem(eventStorageKey)).to.equal(''); - expect(uploader.eventsQueuedForProcessing.length).to.equal(0); - - // Batch Queue should be empty because batch successfully uploaded - expect(uploader.batchesQueuedForProcessing.length).to.equal(0); - clock.restore(); - // done(); - }) - .catch((e) => { - }) + .then(async () => { + const mpInstance = window.mParticle.getInstance(); + const uploader = mpInstance._APIClient.uploader; + + // Init will fire a Session Start and AST. We are adding event0 + // to show that manually queued events will also be grouped + // into a batch + uploader.queueEvent(event0); + + expect(uploader.eventsQueuedForProcessing.length).to.equal( + 3, + ); + expect(uploader.batchesQueuedForProcessing.length).to.equal( + 0, + ); + + expect( + window.sessionStorage.getItem(eventStorageKey), + 'Queued Events should appear in Session Storage', + ).to.be.ok; + expect( + JSON.parse( + window.sessionStorage.getItem(eventStorageKey), + ).length, + ).to.equal(3); + + // Manually initiate the upload process - turn event into batches and upload the batch + await window.mParticle + .getInstance() + ._APIClient.uploader.prepareAndUpload(); + + // If Session Storage is purged, it should return an empty string + expect( + window.sessionStorage.getItem(eventStorageKey), + ).to.equal(''); + expect(uploader.eventsQueuedForProcessing.length).to.equal( + 0, + ); + + // Batch Queue should be empty because batch successfully uploaded + expect(uploader.batchesQueuedForProcessing.length).to.equal( + 0, + ); + clock.restore(); + // done(); + }) + .catch((e) => {}); }); it('should save batches in sequence to Local Storage when an HTTP 500 error is encountered', async () => { @@ -1179,52 +1295,53 @@ describe('batch uploader', () => { window.mParticle._resetForTests(MPConfig); window.mParticle.init(apiKey, window.mParticle.config); waitForCondition(hasIdentifyReturned) - .then(async() => { - - const mpInstance = window.mParticle.getInstance(); - const uploader = mpInstance._APIClient.uploader; - - // Init will fire a Session Start and AST. We are adding event0 - // to show that manually queued events will also be grouped - // into a batch - uploader.queueEvent(event0); - - // Manually initiate the upload process - turn event into batches and upload the batch - await window.mParticle.getInstance()._APIClient.uploader.prepareAndUpload(); - - expect(window.localStorage.getItem(batchStorageKey)).to.be.ok; - - const storedBatches: Batch[] = JSON.parse( - window.localStorage.getItem(batchStorageKey) - ); - - // Note: Events are usually are groupd together into a single batch - // However, in this case, since we are mocking a custom event (event0) - // our batching logic is grouping event0 into a separate batch from - // the Session Start + AST event from init as they have a different - // SessionID - expect(storedBatches.length).to.equal(2); - expect( - storedBatches[0].events[0].event_type, - 'Batch 1: Session Start' - ).to.equal('session_start'); - expect( - storedBatches[0].events[1].event_type, - 'Batch 1: AST' - ).to.equal('application_state_transition'); - - expect( - storedBatches[1].events[0].event_type, - 'Batch 2: Custom Event Type' - ).to.equal('custom_event'); - expect( - (storedBatches[1].events[0].data as CustomEventData) - .event_name, - 'Batch 2: Custom Event Name' - ).to.equal('Test Event 0'); - }) - .catch((e) => { - }) + .then(async () => { + const mpInstance = window.mParticle.getInstance(); + const uploader = mpInstance._APIClient.uploader; + + // Init will fire a Session Start and AST. We are adding event0 + // to show that manually queued events will also be grouped + // into a batch + uploader.queueEvent(event0); + + // Manually initiate the upload process - turn event into batches and upload the batch + await window.mParticle + .getInstance() + ._APIClient.uploader.prepareAndUpload(); + + expect(window.localStorage.getItem(batchStorageKey)).to.be + .ok; + + const storedBatches: Batch[] = JSON.parse( + window.localStorage.getItem(batchStorageKey), + ); + + // Note: Events are usually are groupd together into a single batch + // However, in this case, since we are mocking a custom event (event0) + // our batching logic is grouping event0 into a separate batch from + // the Session Start + AST event from init as they have a different + // SessionID + expect(storedBatches.length).to.equal(2); + expect( + storedBatches[0].events[0].event_type, + 'Batch 1: Session Start', + ).to.equal('session_start'); + expect( + storedBatches[0].events[1].event_type, + 'Batch 1: AST', + ).to.equal('application_state_transition'); + + expect( + storedBatches[1].events[0].event_type, + 'Batch 2: Custom Event Type', + ).to.equal('custom_event'); + expect( + (storedBatches[1].events[0].data as CustomEventData) + .event_name, + 'Batch 2: Custom Event Name', + ).to.equal('Test Event 0'); + }) + .catch((e) => {}); }); it('should save batches in sequence to Local Storage when an HTTP 429 error is encountered', () => { @@ -1235,48 +1352,50 @@ describe('batch uploader', () => { window.mParticle._resetForTests(MPConfig); window.mParticle.init(apiKey, window.mParticle.config); waitForCondition(hasIdentifyReturned) - .then(async () => { - const mpInstance = window.mParticle.getInstance(); - const uploader = mpInstance._APIClient.uploader; - - // Init will fire a Session Start and AST. We are adding event0 - // to show that manually queued events will also be grouped - // into a batch - uploader.queueEvent(event0); - - // Manually initiate the upload process - turn event into batches and upload the batch - await window.mParticle.getInstance()._APIClient.uploader.prepareAndUpload(); + .then(async () => { + const mpInstance = window.mParticle.getInstance(); + const uploader = mpInstance._APIClient.uploader; - clock.restore(); + // Init will fire a Session Start and AST. We are adding event0 + // to show that manually queued events will also be grouped + // into a batch + uploader.queueEvent(event0); - expect(window.localStorage.getItem(batchStorageKey)).to.be.ok; + // Manually initiate the upload process - turn event into batches and upload the batch + await window.mParticle + .getInstance() + ._APIClient.uploader.prepareAndUpload(); - const storedBatches: Batch[] = JSON.parse( - window.localStorage.getItem(batchStorageKey) - ); - - expect(storedBatches.length).to.equal(2); - expect( - storedBatches[0].events[0].event_type, - 'Batch 1: Session Start' - ).to.equal('session_start'); - expect( - storedBatches[0].events[1].event_type, - 'Batch 1: AST' - ).to.equal('application_state_transition'); + clock.restore(); - expect( - storedBatches[1].events[0].event_type, - 'Batch 2: Custom Event Type' - ).to.equal('custom_event'); - expect( - (storedBatches[1].events[0].data as CustomEventData) - .event_name, - 'Batch 2: Custom Event Name' - ).to.equal('Test Event 0'); - }) - .catch((e) => { - }) + expect(window.localStorage.getItem(batchStorageKey)).to.be + .ok; + + const storedBatches: Batch[] = JSON.parse( + window.localStorage.getItem(batchStorageKey), + ); + + expect(storedBatches.length).to.equal(2); + expect( + storedBatches[0].events[0].event_type, + 'Batch 1: Session Start', + ).to.equal('session_start'); + expect( + storedBatches[0].events[1].event_type, + 'Batch 1: AST', + ).to.equal('application_state_transition'); + + expect( + storedBatches[1].events[0].event_type, + 'Batch 2: Custom Event Type', + ).to.equal('custom_event'); + expect( + (storedBatches[1].events[0].data as CustomEventData) + .event_name, + 'Batch 2: Custom Event Name', + ).to.equal('Test Event 0'); + }) + .catch((e) => {}); }); it('should NOT save any batches to Local Storage when an HTTP 401 error is encountered', (done) => { @@ -1290,25 +1409,26 @@ describe('batch uploader', () => { window.mParticle._resetForTests(MPConfig); window.mParticle.init(apiKey, window.mParticle.config); waitForCondition(hasIdentifyReturned) - .then(async () => { - const mpInstance = window.mParticle.getInstance(); - const uploader = mpInstance._APIClient.uploader; - - // Init will fire a Session Start and AST. We are adding event0 - // to show that manually queued events will also be grouped - // into a batch - uploader.queueEvent(event0); - - // Manually initiate the upload process - turn event into batches and upload the batch - await window.mParticle.getInstance()._APIClient.uploader.prepareAndUpload(); - - expect(window.localStorage.getItem(batchStorageKey)).to.equal( - '' - ); - done(); - }) - .catch((e) => { - }) + .then(async () => { + const mpInstance = window.mParticle.getInstance(); + const uploader = mpInstance._APIClient.uploader; + + // Init will fire a Session Start and AST. We are adding event0 + // to show that manually queued events will also be grouped + // into a batch + uploader.queueEvent(event0); + + // Manually initiate the upload process - turn event into batches and upload the batch + await window.mParticle + .getInstance() + ._APIClient.uploader.prepareAndUpload(); + + expect( + window.localStorage.getItem(batchStorageKey), + ).to.equal(''); + done(); + }) + .catch((e) => {}); }); it('should save batches in sequence to Local Storage when upload is interrupted', async () => { @@ -1333,122 +1453,127 @@ describe('batch uploader', () => { window.mParticle._resetForTests(MPConfig); window.mParticle.init(apiKey, window.mParticle.config); waitForCondition(hasIdentifyReturned) - .then(async () => { - const mpInstance = window.mParticle.getInstance(); - const uploader = mpInstance._APIClient.uploader; - - const batchValidator = new _BatchValidator(); - - // Create sample batches for testing - const batch1 = batchValidator.returnBatch([ - { - messageType: 4, - name: 'Test Event 1', - }, - { - messageType: 4, - name: 'Test Event 2', - }, - ]); - - const batch2 = batchValidator.returnBatch([ - { - messageType: 4, - name: 'Test Event 3', - }, - { - messageType: 4, - name: 'Test Event 4', - }, - ]); - - const batch3 = batchValidator.returnBatch([ - { - messageType: 4, - name: 'Test Event 5', - }, - { - messageType: 4, - name: 'Test Event 6', - }, - ]); - - // Init will generate a batch with Session Start and AST which normally comes first - // but for testing purposes the Session Start + AST batches will be the last batches - // as we are manually queueing additional batches to verify sequence - uploader.batchesQueuedForProcessing.push(batch1); - uploader.batchesQueuedForProcessing.push(batch2); - uploader.batchesQueuedForProcessing.push(batch3); - - // Manually initiate the upload process - // This will also turn the SessionStart + AST events into a batch and add it to the end of the queue - await window.mParticle.getInstance()._APIClient.uploader.prepareAndUpload(); - - expect(window.localStorage.getItem(batchStorageKey)).to.be.ok; - - const storedBatches: Batch[] = JSON.parse( - window.localStorage.getItem(batchStorageKey) - ); - - // We tried to upload 4 batches (3 unique batches + Session Start/AST from init) - expect(storedBatches.length).to.equal(3); - - // FIXME: cursor changed these comments. Double check that this is correct - // The following assertions should verify the sequence presented below - // - Batch 1: Test Event 1 and 2 - Read from Offline Storage - // - Batch 2: Test Event 3 and 4 - Read from Offline Storage - // - Batch 3: Test Event 5 and 6 - Read from Offline Storage - // - Batch 4: Session Start and AST - (new) Created by Init - - expect( - (storedBatches[0].events[0].data as CustomEventData) - .event_name, - 'Batch 1: Test Event 1 ' - ).to.equal('Test Event 1'); - expect( - (storedBatches[0].events[1].data as CustomEventData) - .event_name, - 'Batch 1: Test Event 2' - ).to.equal('Test Event 2'); - - expect( - (storedBatches[1].events[0].data as CustomEventData) - .event_name, - 'Batch 2: Test Event 3 Event Name' - ).to.equal('Test Event 3'); - expect( - (storedBatches[1].events[1].data as CustomEventData) - .event_name, - 'Batch 2: Test Event 4 Event Name' - ).to.equal('Test Event 4'); - - expect( - (storedBatches[2].events[0].data as CustomEventData) - .event_name, - 'Batch 2: Test Event 5 Event Name' - ).to.equal('Test Event 5'); - expect( - (storedBatches[2].events[1].data as CustomEventData) - .event_name, - 'Batch 2: Test Event 6 Event Name' - ).to.equal('Test Event 6'); - - // These are the events that are generated by mParticle.init. Usually they - // come before any queued events, but we manually queued the previous - // batches increase the number of attempted uploads to verify that batches - // are retained in Offline Storage in order of creation - expect( - storedBatches[3].events[0].event_type, - 'Batch 4: Session Start' - ).to.equal('session_start'); - expect( - storedBatches[3].events[1].event_type, - 'Batch 4: AST' - ).to.equal('application_state_transition'); - }) - .catch((e) => { - console.log('should save batches in sequence to Local Storage when upload is interrupted') - }) + .then(async () => { + const mpInstance = window.mParticle.getInstance(); + const uploader = mpInstance._APIClient.uploader; + + const batchValidator = new _BatchValidator(); + + // Create sample batches for testing + const batch1 = batchValidator.returnBatch([ + { + messageType: 4, + name: 'Test Event 1', + }, + { + messageType: 4, + name: 'Test Event 2', + }, + ]); + + const batch2 = batchValidator.returnBatch([ + { + messageType: 4, + name: 'Test Event 3', + }, + { + messageType: 4, + name: 'Test Event 4', + }, + ]); + + const batch3 = batchValidator.returnBatch([ + { + messageType: 4, + name: 'Test Event 5', + }, + { + messageType: 4, + name: 'Test Event 6', + }, + ]); + + // Init will generate a batch with Session Start and AST which normally comes first + // but for testing purposes the Session Start + AST batches will be the last batches + // as we are manually queueing additional batches to verify sequence + uploader.batchesQueuedForProcessing.push(batch1); + uploader.batchesQueuedForProcessing.push(batch2); + uploader.batchesQueuedForProcessing.push(batch3); + + // Manually initiate the upload process + // This will also turn the SessionStart + AST events into a batch and add it to the end of the queue + await window.mParticle + .getInstance() + ._APIClient.uploader.prepareAndUpload(); + + expect(window.localStorage.getItem(batchStorageKey)).to.be + .ok; + + const storedBatches: Batch[] = JSON.parse( + window.localStorage.getItem(batchStorageKey), + ); + + // We tried to upload 4 batches (3 unique batches + Session Start/AST from init) + expect(storedBatches.length).to.equal(3); + + // FIXME: cursor changed these comments. Double check that this is correct + // The following assertions should verify the sequence presented below + // - Batch 1: Test Event 1 and 2 - Read from Offline Storage + // - Batch 2: Test Event 3 and 4 - Read from Offline Storage + // - Batch 3: Test Event 5 and 6 - Read from Offline Storage + // - Batch 4: Session Start and AST - (new) Created by Init + + expect( + (storedBatches[0].events[0].data as CustomEventData) + .event_name, + 'Batch 1: Test Event 1 ', + ).to.equal('Test Event 1'); + expect( + (storedBatches[0].events[1].data as CustomEventData) + .event_name, + 'Batch 1: Test Event 2', + ).to.equal('Test Event 2'); + + expect( + (storedBatches[1].events[0].data as CustomEventData) + .event_name, + 'Batch 2: Test Event 3 Event Name', + ).to.equal('Test Event 3'); + expect( + (storedBatches[1].events[1].data as CustomEventData) + .event_name, + 'Batch 2: Test Event 4 Event Name', + ).to.equal('Test Event 4'); + + expect( + (storedBatches[2].events[0].data as CustomEventData) + .event_name, + 'Batch 2: Test Event 5 Event Name', + ).to.equal('Test Event 5'); + expect( + (storedBatches[2].events[1].data as CustomEventData) + .event_name, + 'Batch 2: Test Event 6 Event Name', + ).to.equal('Test Event 6'); + + // These are the events that are generated by mParticle.init. Usually they + // come before any queued events, but we manually queued the previous + // batches increase the number of attempted uploads to verify that batches + // are retained in Offline Storage in order of creation + expect( + storedBatches[3].events[0].event_type, + 'Batch 4: Session Start', + ).to.equal('session_start'); + expect( + storedBatches[3].events[1].event_type, + 'Batch 4: AST', + ).to.equal('application_state_transition'); + }) + .catch((e) => { + console.log( + 'should save batches in sequence to Local Storage when upload is interrupted', + ); + }); }); it('should attempt to upload batches from Offline Storage before new batches', () => { @@ -1463,135 +1588,137 @@ describe('batch uploader', () => { window.mParticle._resetForTests(MPConfig); window.mParticle.init(apiKey, window.mParticle.config); waitForCondition(hasIdentifyReturned) - .then(async () => { - - const mpInstance = window.mParticle.getInstance(); - const uploader = mpInstance._APIClient.uploader; - - const batchValidator = new _BatchValidator(); - - // Create sample batches for testing - const batch1 = batchValidator.returnBatch([ - { - messageType: 4, - name: 'Test Event 1', - }, - { - messageType: 4, - name: 'Test Event 2', - }, - ]); - - const batch2 = batchValidator.returnBatch([ - { - messageType: 4, - name: 'Test Event 3', - }, - { - messageType: 4, - name: 'Test Event 4', - }, - ]); - - const batch3 = batchValidator.returnBatch([ - { - messageType: 4, - name: 'Test Event 5', - }, - { - messageType: 4, - name: 'Test Event 6', - }, - ]); - - // Write batches to Offline Storage before queuing new events or batches - window.localStorage.setItem( - batchStorageKey, - JSON.stringify([batch1, batch2, batch3]) - ); - - // Batch Queue should be empty before we upload - expect(uploader.batchesQueuedForProcessing.length).to.equal(0); - - // Manually initiate the upload process - turn event into batches and upload the batch - await window.mParticle.getInstance()._APIClient.uploader.prepareAndUpload(); - - expect( - window.localStorage.getItem(batchStorageKey), - 'Offline Batch Storage should be empty' - ).to.equal(''); - - // To verify the sequence, we should look at what has been uploaded - // as the upload queue and Offline Storage should be empty - expect(fetchMock.calls().length).to.equal(4); - - const uploadedBatch1: Batch = JSON.parse( - fetchMock.calls()[0][1].body as string - ); - const uploadedBatch2: Batch = JSON.parse( - fetchMock.calls()[1][1].body as string - ); - const uploadedBatch3: Batch = JSON.parse( - fetchMock.calls()[2][1].body as string - ); - const uploadedBatch4: Batch = JSON.parse( - fetchMock.calls()[3][1].body as string - ); - - // The following assertions should verify the sequence presented below - // - Batch 1: Test Event 1 and 2 - Read from Offline Storage - // - Batch 2: Test Event 3 and 4 - Read from Offline Storage - // - Batch 3: Test Event 5 and 6 - Read from Offline Storage - // - Batch 4: Session Start and AST - (new) Created by Init - - expect( - (uploadedBatch1.events[0].data as CustomEventData) - .event_name, - 'Batch 1: Test Event 1 ' - ).to.equal('Test Event 1'); - expect( - (uploadedBatch1.events[1].data as CustomEventData) - .event_name, - 'Batch 1: Test Event 2' - ).to.equal('Test Event 2'); - - expect( - (uploadedBatch2.events[0].data as CustomEventData) - .event_name, - 'Batch 2: Test Event 3 Event Name' - ).to.equal('Test Event 3'); - expect( - (uploadedBatch2.events[1].data as CustomEventData) - .event_name, - 'Batch 2: Test Event 4 Event Name' - ).to.equal('Test Event 4'); - - expect( - (uploadedBatch3.events[0].data as CustomEventData) - .event_name, - 'Batch 2: Test Event 5 Event Name' - ).to.equal('Test Event 5'); - expect( - (uploadedBatch3.events[1].data as CustomEventData) - .event_name, - 'Batch 2: Test Event 6 Event Name' - ).to.equal('Test Event 6'); - - // These are the events that are generated by mParticle.init. Usually they - // come before any queued events, but we manually queued the previous - // batches increase the number of attempted uploads to verify that batches - // are retained in Offline Storage in order of creation - expect( - uploadedBatch4.events[0].event_type, - 'Batch 4: Session Start' - ).to.equal('session_start'); - expect( - uploadedBatch4.events[1].event_type, - 'Batch 4: AST' - ).to.equal('application_state_transition'); - }) - .catch((e) => { - }) + .then(async () => { + const mpInstance = window.mParticle.getInstance(); + const uploader = mpInstance._APIClient.uploader; + + const batchValidator = new _BatchValidator(); + + // Create sample batches for testing + const batch1 = batchValidator.returnBatch([ + { + messageType: 4, + name: 'Test Event 1', + }, + { + messageType: 4, + name: 'Test Event 2', + }, + ]); + + const batch2 = batchValidator.returnBatch([ + { + messageType: 4, + name: 'Test Event 3', + }, + { + messageType: 4, + name: 'Test Event 4', + }, + ]); + + const batch3 = batchValidator.returnBatch([ + { + messageType: 4, + name: 'Test Event 5', + }, + { + messageType: 4, + name: 'Test Event 6', + }, + ]); + + // Write batches to Offline Storage before queuing new events or batches + window.localStorage.setItem( + batchStorageKey, + JSON.stringify([batch1, batch2, batch3]), + ); + + // Batch Queue should be empty before we upload + expect(uploader.batchesQueuedForProcessing.length).to.equal( + 0, + ); + + // Manually initiate the upload process - turn event into batches and upload the batch + await window.mParticle + .getInstance() + ._APIClient.uploader.prepareAndUpload(); + + expect( + window.localStorage.getItem(batchStorageKey), + 'Offline Batch Storage should be empty', + ).to.equal(''); + + // To verify the sequence, we should look at what has been uploaded + // as the upload queue and Offline Storage should be empty + expect(fetchMock.calls().length).to.equal(4); + + const uploadedBatch1: Batch = JSON.parse( + fetchMock.calls()[0][1].body as string, + ); + const uploadedBatch2: Batch = JSON.parse( + fetchMock.calls()[1][1].body as string, + ); + const uploadedBatch3: Batch = JSON.parse( + fetchMock.calls()[2][1].body as string, + ); + const uploadedBatch4: Batch = JSON.parse( + fetchMock.calls()[3][1].body as string, + ); + + // The following assertions should verify the sequence presented below + // - Batch 1: Test Event 1 and 2 - Read from Offline Storage + // - Batch 2: Test Event 3 and 4 - Read from Offline Storage + // - Batch 3: Test Event 5 and 6 - Read from Offline Storage + // - Batch 4: Session Start and AST - (new) Created by Init + + expect( + (uploadedBatch1.events[0].data as CustomEventData) + .event_name, + 'Batch 1: Test Event 1 ', + ).to.equal('Test Event 1'); + expect( + (uploadedBatch1.events[1].data as CustomEventData) + .event_name, + 'Batch 1: Test Event 2', + ).to.equal('Test Event 2'); + + expect( + (uploadedBatch2.events[0].data as CustomEventData) + .event_name, + 'Batch 2: Test Event 3 Event Name', + ).to.equal('Test Event 3'); + expect( + (uploadedBatch2.events[1].data as CustomEventData) + .event_name, + 'Batch 2: Test Event 4 Event Name', + ).to.equal('Test Event 4'); + + expect( + (uploadedBatch3.events[0].data as CustomEventData) + .event_name, + 'Batch 2: Test Event 5 Event Name', + ).to.equal('Test Event 5'); + expect( + (uploadedBatch3.events[1].data as CustomEventData) + .event_name, + 'Batch 2: Test Event 6 Event Name', + ).to.equal('Test Event 6'); + + // These are the events that are generated by mParticle.init. Usually they + // come before any queued events, but we manually queued the previous + // batches increase the number of attempted uploads to verify that batches + // are retained in Offline Storage in order of creation + expect( + uploadedBatch4.events[0].event_type, + 'Batch 4: Session Start', + ).to.equal('session_start'); + expect( + uploadedBatch4.events[1].event_type, + 'Batch 4: AST', + ).to.equal('application_state_transition'); + }) + .catch((e) => {}); }); }); -}); \ No newline at end of file +}); diff --git a/test/src/tests-batchUploader_2.ts b/test/src/tests-batchUploader_2.ts index 105a3fe59..69cd3aa8c 100644 --- a/test/src/tests-batchUploader_2.ts +++ b/test/src/tests-batchUploader_2.ts @@ -5,7 +5,7 @@ import _BatchValidator from '../../src/mockBatchCreator'; import fetchMock from 'fetch-mock/esm/client'; import { IMParticleInstanceManager } from '../../src/sdkRuntimeModels'; import { CustomEvent } from '@mparticle/event-models'; -const { fetchMockSuccess, waitForCondition, hasIdentifyReturned } = Utils; +const { fetchMockSuccess, waitForCondition, hasIdentifyReturned } = Utils; declare global { interface Window { @@ -37,8 +37,7 @@ describe('batch uploader', () => { }); describe('Upload Workflow', () => { - beforeEach(() => { - }); + beforeEach(() => {}); afterEach(() => { fetchMock.restore(); @@ -57,63 +56,81 @@ describe('batch uploader', () => { window.mParticle._resetForTests(MPConfig); window.mParticle.init(apiKey, window.mParticle.config); waitForCondition(hasIdentifyReturned) - .then(() => { - window.mParticle.logEvent('Test Event 0'); - - // Manually initiate the upload process - turn event into batches and upload the batch - window.mParticle.upload(); - - expect( - fetchMock.called(), - 'FetchMock should have been called' - ).to.equal(true); - - const batch1 = JSON.parse(fetchMock.lastCall()[1].body as string); - - // Batch 1 should contain only session start, AST and a single event - // in this exact order - expect(batch1.events.length).to.equal(3); - expect(batch1.events[0].event_type).to.equal('session_start'); - expect(batch1.events[1].event_type).to.equal( - 'application_state_transition' - ); - expect(batch1.events[2].data.event_name).to.equal('Test Event 0'); - - // Log a second batch of events - window.mParticle.logEvent('Test Event 1'); - window.mParticle.logEvent('Test Event 2'); - window.mParticle.logEvent('Test Event 3'); - - // Manually initiate the upload process - turn event into batches and upload the batch - window.mParticle.upload(); - - const batch2 = JSON.parse(fetchMock.lastCall()[1].body as string); - - // Batch 2 should contain three custom events - expect(batch2.events.length).to.equal(3); - expect(batch2.events[0].data.event_name).to.equal('Test Event 1'); - expect(batch2.events[1].data.event_name).to.equal('Test Event 2'); - expect(batch2.events[2].data.event_name).to.equal('Test Event 3'); - - // Log a third batch of events - window.mParticle.logEvent('Test Event 4'); - window.mParticle.logEvent('Test Event 5'); - - // Manually initiate the upload process - turn event into batches and upload the batch - window.mParticle.upload(); - - const batch3 = JSON.parse(fetchMock.lastCall()[1].body as string); - - // Batch 3 should contain two custom events - expect(batch3.events.length).to.equal(2); - expect(batch3.events[0].data.event_name).to.equal('Test Event 4'); - expect(batch3.events[1].data.event_name).to.equal('Test Event 5'); - - done(); - - }) - .catch((e) => { - }) + .then(() => { + window.mParticle.logEvent('Test Event 0'); + + // Manually initiate the upload process - turn event into batches and upload the batch + window.mParticle.upload(); + + expect( + fetchMock.called(), + 'FetchMock should have been called', + ).to.equal(true); + + const batch1 = JSON.parse( + fetchMock.lastCall()[1].body as string, + ); + + // Batch 1 should contain only session start, AST and a single event + // in this exact order + expect(batch1.events.length).to.equal(3); + expect(batch1.events[0].event_type).to.equal( + 'session_start', + ); + expect(batch1.events[1].event_type).to.equal( + 'application_state_transition', + ); + expect(batch1.events[2].data.event_name).to.equal( + 'Test Event 0', + ); + + // Log a second batch of events + window.mParticle.logEvent('Test Event 1'); + window.mParticle.logEvent('Test Event 2'); + window.mParticle.logEvent('Test Event 3'); + + // Manually initiate the upload process - turn event into batches and upload the batch + window.mParticle.upload(); + + const batch2 = JSON.parse( + fetchMock.lastCall()[1].body as string, + ); + + // Batch 2 should contain three custom events + expect(batch2.events.length).to.equal(3); + expect(batch2.events[0].data.event_name).to.equal( + 'Test Event 1', + ); + expect(batch2.events[1].data.event_name).to.equal( + 'Test Event 2', + ); + expect(batch2.events[2].data.event_name).to.equal( + 'Test Event 3', + ); + + // Log a third batch of events + window.mParticle.logEvent('Test Event 4'); + window.mParticle.logEvent('Test Event 5'); + + // Manually initiate the upload process - turn event into batches and upload the batch + window.mParticle.upload(); + + const batch3 = JSON.parse( + fetchMock.lastCall()[1].body as string, + ); + + // Batch 3 should contain two custom events + expect(batch3.events.length).to.equal(2); + expect(batch3.events[0].data.event_name).to.equal( + 'Test Event 4', + ); + expect(batch3.events[1].data.event_name).to.equal( + 'Test Event 5', + ); + + done(); + }) + .catch((e) => {}); }); // TODO: Investigate workflow with unshift vs push @@ -135,12 +152,12 @@ describe('batch uploader', () => { // Adds a custom event to Batch 1 window.mParticle.logEvent('Test Event 0'); - // Manually initiate the upload process - turn event into batches and upload the batch + // Manually initiate the upload process - turn event into batches and upload the batch window.mParticle.upload(); expect( fetchMock.called(), - 'FetchMock should have been called' + 'FetchMock should have been called', ).to.equal(true); const batch1 = JSON.parse(fetchMock.calls()[0][1].body as string); @@ -150,7 +167,7 @@ describe('batch uploader', () => { expect(batch1.events.length).to.equal(3); expect(batch1.events[0].event_type).to.equal('session_start'); expect(batch1.events[1].event_type).to.equal( - 'application_state_transition' + 'application_state_transition', ); expect(batch1.events[2].data.event_name).to.equal('Test Event 0'); @@ -181,32 +198,34 @@ describe('batch uploader', () => { expect(batchQueue.length).to.equal(3); expect(batchQueue[0].events[0].event_type).to.equal( - 'session_start' + 'session_start', ); expect(batchQueue[0].events[1].event_type).to.equal( - 'application_state_transition' - ); - expect((batchQueue[0].events[2] as CustomEvent).data.event_name).to.equal('Test Event 0'); - - expect((batchQueue[1].events[0] as CustomEvent).data.event_name).to.equal( - 'Test Event 1' - ); - expect((batchQueue[1].events[1] as CustomEvent).data.event_name).to.equal( - 'Test Event 2' - ); - expect((batchQueue[1].events[2] as CustomEvent).data.event_name).to.equal( - 'Test Event 3' - ); - - expect((batchQueue[2].events[0] as CustomEvent).data.event_name).to.equal( - 'Test Event 4' - ); - expect((batchQueue[2].events[1] as CustomEvent).data.event_name).to.equal( - 'Test Event 5' - ); - expect((batchQueue[2].events[2] as CustomEvent).data.event_name).to.equal( - 'Test Event 6' + 'application_state_transition', ); + expect( + (batchQueue[0].events[2] as CustomEvent).data.event_name, + ).to.equal('Test Event 0'); + + expect( + (batchQueue[1].events[0] as CustomEvent).data.event_name, + ).to.equal('Test Event 1'); + expect( + (batchQueue[1].events[1] as CustomEvent).data.event_name, + ).to.equal('Test Event 2'); + expect( + (batchQueue[1].events[2] as CustomEvent).data.event_name, + ).to.equal('Test Event 3'); + + expect( + (batchQueue[2].events[0] as CustomEvent).data.event_name, + ).to.equal('Test Event 4'); + expect( + (batchQueue[2].events[1] as CustomEvent).data.event_name, + ).to.equal('Test Event 5'); + expect( + (batchQueue[2].events[2] as CustomEvent).data.event_name, + ).to.equal('Test Event 6'); done(); }, 0); @@ -236,7 +255,7 @@ describe('batch uploader', () => { // Adds a custom event to Batch 1 window.mParticle.logEvent('Test Event 0'); - // Manually initiate the upload process - turn event into batches and upload the batch + // Manually initiate the upload process - turn event into batches and upload the batch window.mParticle.upload(); // Batch 2 @@ -244,7 +263,7 @@ describe('batch uploader', () => { window.mParticle.logEvent('Test Event 2'); window.mParticle.logEvent('Test Event 3'); - // Manually initiate the upload process - turn event into batches and upload the batch + // Manually initiate the upload process - turn event into batches and upload the batch window.mParticle.upload(); // Batch 3 @@ -252,7 +271,7 @@ describe('batch uploader', () => { window.mParticle.logEvent('Test Event 5'); window.mParticle.logEvent('Test Event 6'); - // Manually initiate the upload process - turn event into batches and upload the batch + // Manually initiate the upload process - turn event into batches and upload the batch window.mParticle.upload(); // Reset timer so the setTimeout can trigger @@ -269,28 +288,28 @@ describe('batch uploader', () => { expect(batchQueue.length).to.equal(2); - expect((batchQueue[0].events[0] as CustomEvent).data.event_name).to.equal( - 'Test Event 1' - ); - expect((batchQueue[0].events[1] as CustomEvent).data.event_name).to.equal( - 'Test Event 2' - ); - expect((batchQueue[0].events[2] as CustomEvent).data.event_name).to.equal( - 'Test Event 3' - ); - - expect((batchQueue[1].events[0] as CustomEvent).data.event_name).to.equal( - 'Test Event 4' - ); - expect((batchQueue[1].events[1] as CustomEvent).data.event_name).to.equal( - 'Test Event 5' - ); - expect((batchQueue[1].events[2] as CustomEvent).data.event_name).to.equal( - 'Test Event 6' - ); + expect( + (batchQueue[0].events[0] as CustomEvent).data.event_name, + ).to.equal('Test Event 1'); + expect( + (batchQueue[0].events[1] as CustomEvent).data.event_name, + ).to.equal('Test Event 2'); + expect( + (batchQueue[0].events[2] as CustomEvent).data.event_name, + ).to.equal('Test Event 3'); + + expect( + (batchQueue[1].events[0] as CustomEvent).data.event_name, + ).to.equal('Test Event 4'); + expect( + (batchQueue[1].events[1] as CustomEvent).data.event_name, + ).to.equal('Test Event 5'); + expect( + (batchQueue[1].events[2] as CustomEvent).data.event_name, + ).to.equal('Test Event 6'); done(); }, 0); }); }); -}); \ No newline at end of file +}); diff --git a/test/src/tests-batchUploader_3.ts b/test/src/tests-batchUploader_3.ts index 9009250ee..066e70030 100644 --- a/test/src/tests-batchUploader_3.ts +++ b/test/src/tests-batchUploader_3.ts @@ -6,7 +6,7 @@ import _BatchValidator from '../../src/mockBatchCreator'; import fetchMock from 'fetch-mock/esm/client'; import { ProductActionType } from '../../src/types'; import { IMParticleInstanceManager } from '../../src/sdkRuntimeModels'; -const { fetchMockSuccess, waitForCondition, hasIdentifyReturned } = Utils; +const { fetchMockSuccess, waitForCondition, hasIdentifyReturned } = Utils; declare global { interface Window { @@ -49,115 +49,142 @@ describe('batch uploader', () => { window.mParticle.config.flags.eventBatchingIntervalMillis = 0; }); - it('should use custom v3 endpoint', function(done) { + it('should use custom v3 endpoint', function (done) { window.mParticle._resetForTests(MPConfig); fetchMock.resetHistory(); window.mParticle.init(apiKey, window.mParticle.config); - waitForCondition(hasIdentifyReturned) - .then(() => { - window.mParticle.logEvent('Test Event'); - - window.mParticle.upload(); - - const lastCall = fetchMock.lastCall(); - const endpoint = lastCall[0]; - const batch = JSON.parse(fetchMock.lastCall()[1].body as string); - - endpoint.should.equal(urls.events); - batch.events[0].event_type.should.equal('session_start'); - batch.events[1].event_type.should.equal('application_state_transition'); - batch.events[2].event_type.should.equal('custom_event'); - batch.events[2].data.event_name.should.equal('Test Event'); - - done(); - }) + waitForCondition(hasIdentifyReturned).then(() => { + window.mParticle.logEvent('Test Event'); + + window.mParticle.upload(); + + const lastCall = fetchMock.lastCall(); + const endpoint = lastCall[0]; + const batch = JSON.parse( + fetchMock.lastCall()[1].body as string, + ); + + endpoint.should.equal(urls.events); + batch.events[0].event_type.should.equal('session_start'); + batch.events[1].event_type.should.equal( + 'application_state_transition', + ); + batch.events[2].event_type.should.equal('custom_event'); + batch.events[2].data.event_name.should.equal('Test Event'); + + done(); + }); }); - it('should have latitude/longitude for location when batching', function(done) { + it('should have latitude/longitude for location when batching', function (done) { window.mParticle._resetForTests(MPConfig); window.mParticle.init(apiKey, window.mParticle.config); - waitForCondition(hasIdentifyReturned) - .then(() => { - window.mParticle.setPosition(100, 100); - window.mParticle.logEvent('Test Event'); - window.mParticle.upload(); - const lastCall = fetchMock.lastCall(); - const endpoint = lastCall[0]; - const batch = JSON.parse(fetchMock.lastCall()[1].body as string); - endpoint.should.equal(urls.events); - batch.events[2].data.location.should.have.property('latitude', 100) - batch.events[2].data.location.should.have.property('longitude', 100) - - done(); - }) + waitForCondition(hasIdentifyReturned).then(() => { + window.mParticle.setPosition(100, 100); + window.mParticle.logEvent('Test Event'); + window.mParticle.upload(); + const lastCall = fetchMock.lastCall(); + const endpoint = lastCall[0]; + const batch = JSON.parse( + fetchMock.lastCall()[1].body as string, + ); + endpoint.should.equal(urls.events); + batch.events[2].data.location.should.have.property( + 'latitude', + 100, + ); + batch.events[2].data.location.should.have.property( + 'longitude', + 100, + ); + + done(); + }); }); - it('should force uploads when using public `upload`', function(done) { + it('should force uploads when using public `upload`', function (done) { window.mParticle._resetForTests(MPConfig); window.mParticle.init(apiKey, window.mParticle.config); - waitForCondition(hasIdentifyReturned) - .then(() => { - window.mParticle.logEvent('Test Event'); - // Identity call - // Session start, AST, and `Test Event` are queued. - fetchMock.calls().length.should.equal(1); - (fetchMock.lastCall()[0].endsWith('identify')).should.equal(true) - - // force upload, triggering window.fetch - window.mParticle.upload(); - - const lastCall = fetchMock.lastCall(); - const endpoint = lastCall[0]; - const batch = JSON.parse(fetchMock.lastCall()[1].body as string); - - endpoint.should.equal(urls.events); - batch.events[0].event_type.should.equal('session_start'); - batch.events[1].event_type.should.equal('application_state_transition'); - batch.events[2].event_type.should.equal('custom_event'); - batch.events[2].data.event_name.should.equal('Test Event'); - - done(); - }) + waitForCondition(hasIdentifyReturned).then(() => { + window.mParticle.logEvent('Test Event'); + // Identity call + // Session start, AST, and `Test Event` are queued. + fetchMock.calls().length.should.equal(1); + fetchMock.lastCall()[0].endsWith('identify').should.equal(true); + + // force upload, triggering window.fetch + window.mParticle.upload(); + + const lastCall = fetchMock.lastCall(); + const endpoint = lastCall[0]; + const batch = JSON.parse( + fetchMock.lastCall()[1].body as string, + ); + + endpoint.should.equal(urls.events); + batch.events[0].event_type.should.equal('session_start'); + batch.events[1].event_type.should.equal( + 'application_state_transition', + ); + batch.events[2].event_type.should.equal('custom_event'); + batch.events[2].data.event_name.should.equal('Test Event'); + + done(); + }); }); - it('should force uploads when a commerce event is called', function(done) { + it('should force uploads when a commerce event is called', function (done) { window.mParticle._resetForTests(MPConfig); window.mParticle.init(apiKey, window.mParticle.config); - waitForCondition(hasIdentifyReturned) - .then(() => { - window.mParticle.logEvent('Test Event'); - - var product1 = window.mParticle.eCommerce.createProduct('iphone', 'iphoneSKU', 999); - window.mParticle.eCommerce.logProductAction(ProductActionType.AddToCart, product1); - - const lastCall = fetchMock.lastCall(); - const endpoint = lastCall[0]; - const batch = JSON.parse(fetchMock.lastCall()[1].body as string); - - endpoint.should.equal(urls.events); - batch.events[0].event_type.should.equal('session_start'); - batch.events[1].event_type.should.equal('application_state_transition'); - batch.events[2].event_type.should.equal('custom_event'); - batch.events[2].data.event_name.should.equal('Test Event'); - batch.events[3].event_type.should.equal('commerce_event'); - batch.events[3].data.product_action.action.should.equal('add_to_cart'); - - done(); + waitForCondition(hasIdentifyReturned).then(() => { + window.mParticle.logEvent('Test Event'); + + const product1 = window.mParticle.eCommerce.createProduct( + 'iphone', + 'iphoneSKU', + 999, + ); + window.mParticle.eCommerce.logProductAction( + ProductActionType.AddToCart, + product1, + ); + + const lastCall = fetchMock.lastCall(); + const endpoint = lastCall[0]; + const batch = JSON.parse( + fetchMock.lastCall()[1].body as string, + ); + + endpoint.should.equal(urls.events); + batch.events[0].event_type.should.equal('session_start'); + batch.events[1].event_type.should.equal( + 'application_state_transition', + ); + batch.events[2].event_type.should.equal('custom_event'); + batch.events[2].data.event_name.should.equal('Test Event'); + batch.events[3].event_type.should.equal('commerce_event'); + batch.events[3].data.product_action.action.should.equal( + 'add_to_cart', + ); + + done(); }); }); - it('should return pending uploads if a 500 is returned', async function() { + it('should return pending uploads if a 500 is returned', async function () { window.mParticle._resetForTests(MPConfig); fetchMock.post(urls.events, 500); - + window.mParticle.init(apiKey, window.mParticle.config); await waitForCondition(hasIdentifyReturned); window.mParticle.logEvent('Test Event'); - let pendingEvents = window.mParticle.getInstance()._APIClient.uploader.eventsQueuedForProcessing; + const pendingEvents = + window.mParticle.getInstance()._APIClient.uploader + .eventsQueuedForProcessing; pendingEvents.length.should.equal(3); pendingEvents[0].EventName.should.equal(1); @@ -165,68 +192,77 @@ describe('batch uploader', () => { pendingEvents[2].EventName.should.equal('Test Event'); fetchMock.post(urls.events, 200); - + // First fetch call is an identify call - (fetchMock.lastCall()[0].endsWith('identify')).should.equal(true); + fetchMock.lastCall()[0].endsWith('identify').should.equal(true); window.mParticle.upload(); - let nowPendingEvents = window.mParticle.getInstance()._APIClient.uploader.eventsQueuedForProcessing; + const nowPendingEvents = + window.mParticle.getInstance()._APIClient.uploader + .eventsQueuedForProcessing; nowPendingEvents.length.should.equal(0); const batch = JSON.parse(fetchMock.lastCall()[1].body as string); batch.events[0].event_type.should.equal('session_start'); - batch.events[1].event_type.should.equal('application_state_transition'); + batch.events[1].event_type.should.equal( + 'application_state_transition', + ); batch.events[2].event_type.should.equal('custom_event'); batch.events[2].data.event_name.should.equal('Test Event'); }); - it('should send source_message_id with events to v3 endpoint', function(done) { + it('should send source_message_id with events to v3 endpoint', function (done) { window.mParticle._resetForTests(MPConfig); window.mParticle.init(apiKey, window.mParticle.config); - waitForCondition(hasIdentifyReturned) - .then(() => { - window.mParticle.logEvent('Test Event'); + waitForCondition(hasIdentifyReturned).then(() => { + window.mParticle.logEvent('Test Event'); - window.mParticle.upload(); + window.mParticle.upload(); - const lastCall = fetchMock.lastCall(); - const endpoint = lastCall[0]; - const batch = JSON.parse(fetchMock.lastCall()[1].body as string); + const lastCall = fetchMock.lastCall(); + const endpoint = lastCall[0]; + const batch = JSON.parse( + fetchMock.lastCall()[1].body as string, + ); - endpoint.should.equal(urls.events); - batch.events[0].data.should.have.property('source_message_id') + endpoint.should.equal(urls.events); + batch.events[0].data.should.have.property('source_message_id'); - done(); - }) + done(); + }); }); - it('should send user-defined SourceMessageId events to v3 endpoint', function(done) { + it('should send user-defined SourceMessageId events to v3 endpoint', function (done) { window.mParticle._resetForTests(MPConfig); window.mParticle.init(apiKey, window.mParticle.config); - waitForCondition(hasIdentifyReturned) - .then(() => { - window.mParticle.logBaseEvent({ - messageType: 4, - name: 'Test Event', - data: {key: 'value'}, - eventType: 3, - customFlags: {flagKey: 'flagValue'}, - sourceMessageId: 'abcdefg' + waitForCondition(hasIdentifyReturned).then(() => { + window.mParticle.logBaseEvent({ + messageType: 4, + name: 'Test Event', + data: { key: 'value' }, + eventType: 3, + customFlags: { flagKey: 'flagValue' }, + sourceMessageId: 'abcdefg', + }); + + window.mParticle.upload(); + + const lastCall = fetchMock.lastCall(); + const endpoint = lastCall[0]; + const batch = JSON.parse( + fetchMock.lastCall()[1].body as string, + ); + + endpoint.should.equal(urls.events); + // event batch includes session start, ast, then last event is Test Event + batch.events[batch.events.length - 1].data.should.have.property( + 'source_message_id', + 'abcdefg', + ); + + done(); }); - - window.mParticle.upload(); - - const lastCall = fetchMock.lastCall(); - const endpoint = lastCall[0]; - const batch = JSON.parse(fetchMock.lastCall()[1].body as string); - - endpoint.should.equal(urls.events); - // event batch includes session start, ast, then last event is Test Event - batch.events[batch.events.length-1].data.should.have.property('source_message_id', 'abcdefg') - - done(); - }) }); it('should call the identity callback after a session ends if user is returning to the page after a long period of time', async () => { @@ -239,201 +275,214 @@ describe('batch uploader', () => { // start. window.mParticle._resetForTests(MPConfig); - - window.mParticle.config.identityCallback = function(result) { - let currentUser = result.getUser() + + window.mParticle.config.identityCallback = function (result) { + const currentUser = result.getUser(); if (currentUser) { // TODO: Investigate if we should update definitely typed typings for // setUserAttribute which only allows strings right now // more context at https://go.mparticle.com/work/SQDSDKS-4576 - currentUser.setUserAttribute("number", `${Math.floor((Math.random() * 1000) + 1)}`) + currentUser.setUserAttribute( + 'number', + `${Math.floor(Math.random() * 1000 + 1)}`, + ); } - } - - var endSessionFunction = window.mParticle.getInstance()._SessionManager.endSession; - - window.mParticle.init(apiKey, window.mParticle.config); - waitForCondition(() => { - return ( - window.mParticle.getInstance()._Store?.identityCallInFlight === false - ); - }) - .then(() => { - // Mock end session so that the SDK doesn't actually send it. We do this - // to mimic a return to page behavior, below: - window.mParticle.getInstance()._SessionManager.endSession = function() {} - clock = sinon.useFakeTimers({now: new Date().getTime()}); - - // Force 35 minutes to pass, so that when we return to the page, when - // the SDK initializes it will know to end the session. - clock.tick(35*60000); - - // Undo mock of end session so that when we initializes, it will end - // the session for real. - window.mParticle.getInstance()._SessionManager.endSession = endSessionFunction; - clock.restore(); - - // Initialize imitates returning to the page - window.mParticle.init(apiKey, window.mParticle.config); - waitForCondition(() => { - return ( - window.mParticle.getInstance()?._Store?.identityCallInFlight === false - ); - }) - .then(async () => { - // Manually initiate the upload process - turn event into batches and upload the batch - await window.mParticle.getInstance()._APIClient.uploader.prepareAndUpload(); - - const batch1 = JSON.parse(fetchMock.calls()[0][1].body as string); - const batch2 = JSON.parse(fetchMock.calls()[1][1].body as string); - const batch3 = JSON.parse(fetchMock.calls()[2][1].body as string); - - // UAC, session start, AST - expect( - batch1.events.length, - 'Batch 1: UAC Event, Session Start, AST' - ).to.equal(3); - - // session end - expect(batch2.events.length, 'Batch 2: Session End').to.equal( - 1 - ); - - // UAC, session start, AST - expect( - batch3.events.length, - 'Batch 3: UAC, Session Start, AST' - ).to.equal(3); - - const batch1UAC = Utils.findEventFromBatch( - batch1, - 'user_attribute_change' - ); - const batch1SessionStart = Utils.findEventFromBatch( - batch1, - 'session_start' - ); - const batch1AST = Utils.findEventFromBatch( - batch1, - 'application_state_transition' - ); - - batch1UAC.should.be.ok(); - batch1SessionStart.should.be.ok(); - batch1AST.should.be.ok(); - - const batch2SessionEnd = Utils.findEventFromBatch( - batch2, - 'session_end' - ); - batch2SessionEnd.should.be.ok(); - - const batch3UAC = Utils.findEventFromBatch( - batch3, - 'user_attribute_change' - ); - const batch3SessionStart = Utils.findEventFromBatch( - batch3, - 'session_start' - ); - const batch3AST = Utils.findEventFromBatch( - batch3, - 'application_state_transition' - ); - - batch3UAC.should.be.ok(); - batch3SessionStart.should.be.ok(); - batch3AST.should.be.ok(); - - - (typeof batch1.source_request_id).should.equal('string'); - (typeof batch2.source_request_id).should.equal('string'); - (typeof batch3.source_request_id).should.equal('string'); + }; - batch1.source_request_id.should.not.equal( - batch2.source_request_id - ); - batch1.source_request_id.should.not.equal( - batch3.source_request_id - ); - batch2.source_request_id.should.not.equal( - batch3.source_request_id - ); - - batch1UAC.data.session_uuid.should.equal( - batch1AST.data.session_uuid - ); - batch1UAC.data.session_uuid.should.equal( - batch1SessionStart.data.session_uuid - ); - batch1UAC.data.session_uuid.should.not.equal( - batch3UAC.data.session_uuid - ); - batch1UAC.data.session_uuid.should.not.equal( - batch3SessionStart.data.session_uuid - ); - batch1UAC.data.session_uuid.should.not.equal( - batch3AST.data.session_uuid - ); + const endSessionFunction = + window.mParticle.getInstance()._SessionManager.endSession; - batch1UAC.data.session_start_unixtime_ms.should.equal( - batch1AST.data.session_start_unixtime_ms - ); - batch1UAC.data.session_start_unixtime_ms.should.equal( - batch1SessionStart.data.session_start_unixtime_ms - ); - batch1UAC.data.session_start_unixtime_ms.should.not.equal( - batch3UAC.data.session_start_unixtime_ms - ); - batch1UAC.data.session_start_unixtime_ms.should.not.equal( - batch3SessionStart.data.session_start_unixtime_ms - ); - batch1UAC.data.session_start_unixtime_ms.should.not.equal( - batch3AST.data.session_start_unixtime_ms - ); - - batch1SessionStart.data.session_uuid.should.equal( - batch1AST.data.session_uuid - ); - batch1SessionStart.data.session_uuid.should.equal( - batch2SessionEnd.data.session_uuid - ); - batch1AST.data.session_uuid.should.equal( - batch2SessionEnd.data.session_uuid - ); - - batch1SessionStart.data.session_start_unixtime_ms.should.equal( - batch1AST.data.session_start_unixtime_ms - ); - batch1SessionStart.data.session_start_unixtime_ms.should.equal( - batch2SessionEnd.data.session_start_unixtime_ms - ); - batch1AST.data.session_start_unixtime_ms.should.equal( - batch2SessionEnd.data.session_start_unixtime_ms - ); - - batch3AST.data.session_uuid.should.equal( - batch3UAC.data.session_uuid - ); - batch3SessionStart.data.session_uuid.should.equal( - batch3UAC.data.session_uuid - ); - batch3SessionStart.data.session_uuid.should.equal( - batch3AST.data.session_uuid - ); - - batch3AST.data.session_start_unixtime_ms.should.equal( - batch3UAC.data.session_start_unixtime_ms - ); - batch3SessionStart.data.session_start_unixtime_ms.should.equal( - batch3UAC.data.session_start_unixtime_ms - ); - batch3SessionStart.data.session_start_unixtime_ms.should.equal( - batch3AST.data.session_start_unixtime_ms - ); - - }) - }) + window.mParticle.init(apiKey, window.mParticle.config); + waitForCondition(() => { + return ( + window.mParticle.getInstance()._Store + ?.identityCallInFlight === false + ); + }).then(() => { + // Mock end session so that the SDK doesn't actually send it. We do this + // to mimic a return to page behavior, below: + window.mParticle.getInstance()._SessionManager.endSession = + function () {}; + clock = sinon.useFakeTimers({ now: new Date().getTime() }); + + // Force 35 minutes to pass, so that when we return to the page, when + // the SDK initializes it will know to end the session. + clock.tick(35 * 60000); + + // Undo mock of end session so that when we initializes, it will end + // the session for real. + window.mParticle.getInstance()._SessionManager.endSession = + endSessionFunction; + clock.restore(); + + // Initialize imitates returning to the page + window.mParticle.init(apiKey, window.mParticle.config); + waitForCondition(() => { + return ( + window.mParticle.getInstance()?._Store + ?.identityCallInFlight === false + ); + }).then(async () => { + // Manually initiate the upload process - turn event into batches and upload the batch + await window.mParticle + .getInstance() + ._APIClient.uploader.prepareAndUpload(); + + const batch1 = JSON.parse( + fetchMock.calls()[0][1].body as string, + ); + const batch2 = JSON.parse( + fetchMock.calls()[1][1].body as string, + ); + const batch3 = JSON.parse( + fetchMock.calls()[2][1].body as string, + ); + + // UAC, session start, AST + expect( + batch1.events.length, + 'Batch 1: UAC Event, Session Start, AST', + ).to.equal(3); + + // session end + expect( + batch2.events.length, + 'Batch 2: Session End', + ).to.equal(1); + + // UAC, session start, AST + expect( + batch3.events.length, + 'Batch 3: UAC, Session Start, AST', + ).to.equal(3); + + const batch1UAC = Utils.findEventFromBatch( + batch1, + 'user_attribute_change', + ); + const batch1SessionStart = Utils.findEventFromBatch( + batch1, + 'session_start', + ); + const batch1AST = Utils.findEventFromBatch( + batch1, + 'application_state_transition', + ); + + batch1UAC.should.be.ok(); + batch1SessionStart.should.be.ok(); + batch1AST.should.be.ok(); + + const batch2SessionEnd = Utils.findEventFromBatch( + batch2, + 'session_end', + ); + batch2SessionEnd.should.be.ok(); + + const batch3UAC = Utils.findEventFromBatch( + batch3, + 'user_attribute_change', + ); + const batch3SessionStart = Utils.findEventFromBatch( + batch3, + 'session_start', + ); + const batch3AST = Utils.findEventFromBatch( + batch3, + 'application_state_transition', + ); + + batch3UAC.should.be.ok(); + batch3SessionStart.should.be.ok(); + batch3AST.should.be.ok(); + + (typeof batch1.source_request_id).should.equal('string'); + (typeof batch2.source_request_id).should.equal('string'); + (typeof batch3.source_request_id).should.equal('string'); + + batch1.source_request_id.should.not.equal( + batch2.source_request_id, + ); + batch1.source_request_id.should.not.equal( + batch3.source_request_id, + ); + batch2.source_request_id.should.not.equal( + batch3.source_request_id, + ); + + batch1UAC.data.session_uuid.should.equal( + batch1AST.data.session_uuid, + ); + batch1UAC.data.session_uuid.should.equal( + batch1SessionStart.data.session_uuid, + ); + batch1UAC.data.session_uuid.should.not.equal( + batch3UAC.data.session_uuid, + ); + batch1UAC.data.session_uuid.should.not.equal( + batch3SessionStart.data.session_uuid, + ); + batch1UAC.data.session_uuid.should.not.equal( + batch3AST.data.session_uuid, + ); + + batch1UAC.data.session_start_unixtime_ms.should.equal( + batch1AST.data.session_start_unixtime_ms, + ); + batch1UAC.data.session_start_unixtime_ms.should.equal( + batch1SessionStart.data.session_start_unixtime_ms, + ); + batch1UAC.data.session_start_unixtime_ms.should.not.equal( + batch3UAC.data.session_start_unixtime_ms, + ); + batch1UAC.data.session_start_unixtime_ms.should.not.equal( + batch3SessionStart.data.session_start_unixtime_ms, + ); + batch1UAC.data.session_start_unixtime_ms.should.not.equal( + batch3AST.data.session_start_unixtime_ms, + ); + + batch1SessionStart.data.session_uuid.should.equal( + batch1AST.data.session_uuid, + ); + batch1SessionStart.data.session_uuid.should.equal( + batch2SessionEnd.data.session_uuid, + ); + batch1AST.data.session_uuid.should.equal( + batch2SessionEnd.data.session_uuid, + ); + + batch1SessionStart.data.session_start_unixtime_ms.should.equal( + batch1AST.data.session_start_unixtime_ms, + ); + batch1SessionStart.data.session_start_unixtime_ms.should.equal( + batch2SessionEnd.data.session_start_unixtime_ms, + ); + batch1AST.data.session_start_unixtime_ms.should.equal( + batch2SessionEnd.data.session_start_unixtime_ms, + ); + + batch3AST.data.session_uuid.should.equal( + batch3UAC.data.session_uuid, + ); + batch3SessionStart.data.session_uuid.should.equal( + batch3UAC.data.session_uuid, + ); + batch3SessionStart.data.session_uuid.should.equal( + batch3AST.data.session_uuid, + ); + + batch3AST.data.session_start_unixtime_ms.should.equal( + batch3UAC.data.session_start_unixtime_ms, + ); + batch3SessionStart.data.session_start_unixtime_ms.should.equal( + batch3UAC.data.session_start_unixtime_ms, + ); + batch3SessionStart.data.session_start_unixtime_ms.should.equal( + batch3AST.data.session_start_unixtime_ms, + ); + }); + }); }); }); -}); \ No newline at end of file +}); diff --git a/test/src/tests-batchUploader_4.ts b/test/src/tests-batchUploader_4.ts index 41c016a29..045715b3b 100644 --- a/test/src/tests-batchUploader_4.ts +++ b/test/src/tests-batchUploader_4.ts @@ -7,7 +7,7 @@ import _BatchValidator from '../../src/mockBatchCreator'; import fetchMock from 'fetch-mock/esm/client'; import { ProductActionType } from '../../src/types'; import { IMParticleInstanceManager } from '../../src/sdkRuntimeModels'; -const { fetchMockSuccess, waitForCondition, hasIdentifyReturned } = Utils; +const { fetchMockSuccess, waitForCondition, hasIdentifyReturned } = Utils; declare global { interface Window { @@ -34,20 +34,20 @@ describe('batch uploader', () => { }); describe('batching via XHR for older browsers without window.fetch', () => { - var fetch = window.fetch; + const fetch = window.fetch; beforeEach(() => { - delete window.fetch + delete window.fetch; window.mParticle.config.flags = { eventBatchingIntervalMillis: 1000, - } + }; mockServer = sinon.createFakeServer(); mockServer.respondImmediately = true; mockServer.respondWith(urls.events, [ 200, {}, - JSON.stringify({ mpid: testMPID, Store: {}}) + JSON.stringify({ mpid: testMPID, Store: {} }), ]); mockServer.respondWith(urls.identify, [ 200, @@ -55,119 +55,132 @@ describe('batch uploader', () => { JSON.stringify({ mpid: testMPID, is_logged_in: false }), ]); }); - + afterEach(() => { window.mParticle._resetForTests(MPConfig); window.fetch = fetch; sinon.restore(); }); - it('should use custom v3 endpoint', function(done) { + it('should use custom v3 endpoint', function (done) { window.mParticle._resetForTests(MPConfig); mockServer.requests = []; window.mParticle.init(apiKey, window.mParticle.config); waitForCondition(hasIdentifyReturned) - .then(() => { - window.mParticle.logEvent('Test Event'); - - mockServer.requests.length.should.equal(1); - window.mParticle.upload() - // 1st request is /Identity call, 2nd request is /Event call - - const batch = JSON.parse(mockServer.secondRequest.requestBody); - - batch.events[0].event_type.should.equal('session_start'); - batch.events[1].event_type.should.equal('application_state_transition'); - batch.events[2].event_type.should.equal('custom_event'); - batch.events[2].data.event_name.should.equal('Test Event'); - - done(); - }).catch((e) => { - }) + .then(() => { + window.mParticle.logEvent('Test Event'); + + mockServer.requests.length.should.equal(1); + window.mParticle.upload(); + // 1st request is /Identity call, 2nd request is /Event call + + const batch = JSON.parse( + mockServer.secondRequest.requestBody, + ); + + batch.events[0].event_type.should.equal('session_start'); + batch.events[1].event_type.should.equal( + 'application_state_transition', + ); + batch.events[2].event_type.should.equal('custom_event'); + batch.events[2].data.event_name.should.equal('Test Event'); + + done(); + }) + .catch((e) => {}); }); - it('should force uploads when using public `upload`', function(done) { + it('should force uploads when using public `upload`', function (done) { window.mParticle._resetForTests(MPConfig); window.mParticle.init(apiKey, window.mParticle.config); - waitForCondition(hasIdentifyReturned) - .then(() => { - - - window.mParticle.logEvent('Test Event'); - - // The only request to the server should be the identify call - // Session start, AST, and Test Event are queued. - mockServer.requests.length.should.equal(1); - // Upload interval hit, now will send requests - - window.mParticle.upload(); - // 1st request is /Identity call, 2nd request is /Event call - const batch = JSON.parse(mockServer.secondRequest.requestBody); - - batch.events[0].event_type.should.equal('session_start'); - batch.events[1].event_type.should.equal('application_state_transition'); - batch.events[2].event_type.should.equal('custom_event'); - batch.events[2].data.event_name.should.equal('Test Event'); - - done(); - }) + waitForCondition(hasIdentifyReturned).then(() => { + window.mParticle.logEvent('Test Event'); + + // The only request to the server should be the identify call + // Session start, AST, and Test Event are queued. + mockServer.requests.length.should.equal(1); + // Upload interval hit, now will send requests + + window.mParticle.upload(); + // 1st request is /Identity call, 2nd request is /Event call + const batch = JSON.parse(mockServer.secondRequest.requestBody); + + batch.events[0].event_type.should.equal('session_start'); + batch.events[1].event_type.should.equal( + 'application_state_transition', + ); + batch.events[2].event_type.should.equal('custom_event'); + batch.events[2].data.event_name.should.equal('Test Event'); + + done(); + }); }); - it('should trigger an upload of batch when a commerce event is called', function(done) { + it('should trigger an upload of batch when a commerce event is called', function (done) { window.mParticle._resetForTests(MPConfig); window.mParticle.init(apiKey, window.mParticle.config); - waitForCondition(hasIdentifyReturned) - .then(() => { - window.mParticle.logEvent('Test Event'); - // The only request to the server should be the identify call - // Session start, AST, and Test Event are queued. - mockServer.requests.length.should.equal(1); - - var product1 = window.mParticle.eCommerce.createProduct('iphone', 'iphoneSKU', 999); - window.mParticle.eCommerce.logProductAction(ProductActionType.AddToCart, product1); - // 1st request is /Identity call, 2nd request is /Event call - const batch = JSON.parse(mockServer.secondRequest.requestBody); - - batch.events[0].event_type.should.equal('session_start'); - batch.events[1].event_type.should.equal('application_state_transition'); - batch.events[2].event_type.should.equal('custom_event'); - batch.events[2].data.event_name.should.equal('Test Event'); - batch.events[3].event_type.should.equal('commerce_event'); - batch.events[3].data.product_action.action.should.equal('add_to_cart'); - - done(); - }) + waitForCondition(hasIdentifyReturned).then(() => { + window.mParticle.logEvent('Test Event'); + // The only request to the server should be the identify call + // Session start, AST, and Test Event are queued. + mockServer.requests.length.should.equal(1); + + const product1 = window.mParticle.eCommerce.createProduct( + 'iphone', + 'iphoneSKU', + 999, + ); + window.mParticle.eCommerce.logProductAction( + ProductActionType.AddToCart, + product1, + ); + // 1st request is /Identity call, 2nd request is /Event call + const batch = JSON.parse(mockServer.secondRequest.requestBody); + + batch.events[0].event_type.should.equal('session_start'); + batch.events[1].event_type.should.equal( + 'application_state_transition', + ); + batch.events[2].event_type.should.equal('custom_event'); + batch.events[2].data.event_name.should.equal('Test Event'); + batch.events[3].event_type.should.equal('commerce_event'); + batch.events[3].data.product_action.action.should.equal( + 'add_to_cart', + ); + + done(); + }); }); - it('should trigger an upload of batch when a UIC occurs', function(done) { + it('should trigger an upload of batch when a UIC occurs', function (done) { window.mParticle._resetForTests(MPConfig); // include an identify request so that it creates a UIC window.mParticle.config.identifyRequest = { userIdentities: { - customerid: 'foo-customer-id' - } + customerid: 'foo-customer-id', + }, }; window.mParticle.init(apiKey, window.mParticle.config); - waitForCondition(hasIdentifyReturned) - .then(() => { - // Requests sent should be identify call, then UIC event - // Session start, AST, and Test Event are queued, and don't appear - // in the mockServer.requests - mockServer.requests.length.should.equal(2); + waitForCondition(hasIdentifyReturned).then(() => { + // Requests sent should be identify call, then UIC event + // Session start, AST, and Test Event are queued, and don't appear + // in the mockServer.requests + mockServer.requests.length.should.equal(2); - // 1st request is /Identity call, 2nd request is events call - const batch = JSON.parse(mockServer.secondRequest.requestBody); - - batch.events[2].event_type.should.equal('user_identity_change'); + // 1st request is /Identity call, 2nd request is events call + const batch = JSON.parse(mockServer.secondRequest.requestBody); + batch.events[2].event_type.should.equal('user_identity_change'); - batch.events[0].event_type.should.equal('session_start'); - batch.events[1].event_type.should.equal('application_state_transition'); + batch.events[0].event_type.should.equal('session_start'); + batch.events[1].event_type.should.equal( + 'application_state_transition', + ); - done(); + done(); }); }); @@ -175,108 +188,117 @@ describe('batch uploader', () => { // was triggered. This feature was removed and we are including this test to // make sure the Web SDK does not regress. This test will be removed in a future // Web SDK update - // TODO: https://go.mparticle.com/work/SQDSDKS-5891 - it('should NOT trigger an upload of batch when a UAC occurs', function(done) { + // TODO: https://go.mparticle.com/work/SQDSDKS-5891 + it('should NOT trigger an upload of batch when a UAC occurs', function (done) { window.mParticle._resetForTests(MPConfig); window.mParticle.init(apiKey, window.mParticle.config); - waitForCondition(hasIdentifyReturned) - .then(() => { - - // Set a user attribute to trigger a UAC event - window.mParticle.Identity.getCurrentUser().setUserAttribute('age', 25); - - // Requests sent should be identify call - // Since we no longer force an upload for UAC, - // This request will contain a /Identity Call - // a future request will contain session start, AST, and UAC - mockServer.requests.length.should.equal(1); - - // Verifies that adding a UAC does not trigger an upload - expect(mockServer.secondRequest).to.equal(null); - - // Manually force an upload - window.mParticle.upload(); - - // Second request has now been made - expect(mockServer.secondRequest).to.be.ok; - - const batch = JSON.parse(mockServer.secondRequest.requestBody); - - // Batch should now contain the 3 events we expect - mockServer.requests.length.should.equal(2); - batch.events[0].event_type.should.equal('session_start'); - batch.events[1].event_type.should.equal('application_state_transition'); - batch.events[2].event_type.should.equal('user_attribute_change'); - - done(); - }); + waitForCondition(hasIdentifyReturned).then(() => { + // Set a user attribute to trigger a UAC event + window.mParticle.Identity.getCurrentUser().setUserAttribute( + 'age', + 25, + ); + + // Requests sent should be identify call + // Since we no longer force an upload for UAC, + // This request will contain a /Identity Call + // a future request will contain session start, AST, and UAC + mockServer.requests.length.should.equal(1); + + // Verifies that adding a UAC does not trigger an upload + expect(mockServer.secondRequest).to.equal(null); + + // Manually force an upload + window.mParticle.upload(); + + // Second request has now been made + expect(mockServer.secondRequest).to.be.ok; + + const batch = JSON.parse(mockServer.secondRequest.requestBody); + + // Batch should now contain the 3 events we expect + mockServer.requests.length.should.equal(2); + batch.events[0].event_type.should.equal('session_start'); + batch.events[1].event_type.should.equal( + 'application_state_transition', + ); + batch.events[2].event_type.should.equal( + 'user_attribute_change', + ); + + done(); + }); }); - it('should return pending uploads if a 500 is returned', function(done) { + it('should return pending uploads if a 500 is returned', function (done) { window.mParticle._resetForTests(MPConfig); mockServer.respondWith(urls.events, [ 500, {}, - JSON.stringify({ mpid: testMPID, Store: {}}) + JSON.stringify({ mpid: testMPID, Store: {} }), ]); window.mParticle.init(apiKey, window.mParticle.config); - waitForCondition(hasIdentifyReturned) - .then(() => { - window.mParticle.logEvent('Test Event'); - - const pendingEvents = window.mParticle.getInstance()._APIClient.uploader.eventsQueuedForProcessing; - - pendingEvents.length.should.equal(3) - pendingEvents[0].EventName.should.equal(1); - pendingEvents[1].EventName.should.equal(10); - pendingEvents[2].EventName.should.equal('Test Event'); - - window.mParticle.upload(); - - const nowPendingEvents = window.mParticle.getInstance()._APIClient.uploader.eventsQueuedForProcessing; - nowPendingEvents.length.should.equal(0); - - const batch = JSON.parse(mockServer.secondRequest.requestBody); - batch.events[0].event_type.should.equal('session_start'); - batch.events[1].event_type.should.equal('application_state_transition'); - batch.events[2].event_type.should.equal('custom_event'); - batch.events[2].data.event_name.should.equal('Test Event'); - done(); + waitForCondition(hasIdentifyReturned).then(() => { + window.mParticle.logEvent('Test Event'); + + const pendingEvents = + window.mParticle.getInstance()._APIClient.uploader + .eventsQueuedForProcessing; + + pendingEvents.length.should.equal(3); + pendingEvents[0].EventName.should.equal(1); + pendingEvents[1].EventName.should.equal(10); + pendingEvents[2].EventName.should.equal('Test Event'); + + window.mParticle.upload(); + + const nowPendingEvents = + window.mParticle.getInstance()._APIClient.uploader + .eventsQueuedForProcessing; + nowPendingEvents.length.should.equal(0); + + const batch = JSON.parse(mockServer.secondRequest.requestBody); + batch.events[0].event_type.should.equal('session_start'); + batch.events[1].event_type.should.equal( + 'application_state_transition', + ); + batch.events[2].event_type.should.equal('custom_event'); + batch.events[2].data.event_name.should.equal('Test Event'); + done(); }); }); - it('should add a modified boolean of true to a batch that has been modified via a config.onCreateBatch call', function(done) { + it('should add a modified boolean of true to a batch that has been modified via a config.onCreateBatch call', function (done) { window.mParticle._resetForTests(MPConfig); window.mParticle.config.onCreateBatch = function (batch: Batch) { - return batch + return batch; }; window.mParticle.init(apiKey, window.mParticle.config); - waitForCondition(hasIdentifyReturned) - .then(() => { - window.mParticle.logEvent('Test Event'); - - window.mParticle.upload() - - const batch = JSON.parse(mockServer.secondRequest.requestBody); - batch.modified.should.equal(true); - done(); - }); + waitForCondition(hasIdentifyReturned).then(() => { + window.mParticle.logEvent('Test Event'); + + window.mParticle.upload(); + const batch = JSON.parse(mockServer.secondRequest.requestBody); + batch.modified.should.equal(true); + done(); + }); }); - it('should respect rules for the batch modification', function(done) { + it('should respect rules for the batch modification', function (done) { window.mParticle._resetForTests(MPConfig); window.mParticle.config.onCreateBatch = function (batch) { - batch.events.map(event => { - if (event.event_type === "custom_event") { - (event.data as CustomEventData).event_name = 'Modified!' + batch.events.map((event) => { + if (event.event_type === 'custom_event') { + (event.data as CustomEventData).event_name = + 'Modified!'; } }); return batch; @@ -284,23 +306,24 @@ describe('batch uploader', () => { window.mParticle.init(apiKey, window.mParticle.config); - waitForCondition(hasIdentifyReturned) - .then(() => { - window.mParticle.logEvent('Test Event'); - - window.mParticle.upload(); - - const batch = JSON.parse(mockServer.secondRequest.requestBody); - batch.events.length.should.equal(3); - batch.events[0].event_type.should.equal('session_start'); - batch.events[1].event_type.should.equal('application_state_transition'); - batch.events[2].event_type.should.equal('custom_event'); - batch.events[2].data.event_name.should.equal('Modified!'); - done(); + waitForCondition(hasIdentifyReturned).then(() => { + window.mParticle.logEvent('Test Event'); + + window.mParticle.upload(); + + const batch = JSON.parse(mockServer.secondRequest.requestBody); + batch.events.length.should.equal(3); + batch.events[0].event_type.should.equal('session_start'); + batch.events[1].event_type.should.equal( + 'application_state_transition', + ); + batch.events[2].event_type.should.equal('custom_event'); + batch.events[2].data.event_name.should.equal('Modified!'); + done(); }); }); - it('should add a modified boolean of true to a batch that has been modified via a config.onCreateBatch call', function(done) { + it('should add a modified boolean of true to a batch that has been modified via a config.onCreateBatch call', function (done) { window.mParticle._resetForTests(MPConfig); window.mParticle.config.onCreateBatch = function (batch: Batch) { @@ -309,15 +332,14 @@ describe('batch uploader', () => { window.mParticle.init(apiKey, window.mParticle.config); - waitForCondition(hasIdentifyReturned) - .then(() => { - window.mParticle.logEvent('Test Event'); - - window.mParticle.upload(); - - (mockServer.secondRequest === null).should.equal(true); - done(); - }) + waitForCondition(hasIdentifyReturned).then(() => { + window.mParticle.logEvent('Test Event'); + + window.mParticle.upload(); + + (mockServer.secondRequest === null).should.equal(true); + done(); + }); }); }); -}); \ No newline at end of file +}); diff --git a/test/src/tests-beaconUpload.ts b/test/src/tests-beaconUpload.ts index f864e01bf..0ba50e965 100644 --- a/test/src/tests-beaconUpload.ts +++ b/test/src/tests-beaconUpload.ts @@ -7,7 +7,13 @@ import { batch1, batch2, batch3 } from '../fixtures/batches'; import _BatchValidator from '../../src/mockBatchCreator'; import Utils from './config/utils'; import { IMParticleInstanceManager } from '../../src/sdkRuntimeModels'; -const { findEventFromRequest, findBatch, waitForCondition, fetchMockSuccess, hasIdentifyReturned } = Utils; +const { + findEventFromRequest, + findBatch, + waitForCondition, + fetchMockSuccess, + hasIdentifyReturned, +} = Utils; declare global { interface Window { @@ -20,14 +26,13 @@ const enableBatchingConfigFlags = { eventBatchingIntervalMillis: 1000, }; - describe('Beacon Upload', () => { - before(function() { + before(function () { fetchMock.restore(); sinon.restore(); }); - beforeEach(function() { + beforeEach(function () { fetchMock.restore(); fetchMockSuccess(urls.identify, { mpid: testMPID, @@ -45,62 +50,56 @@ describe('Beacon Upload', () => { fetchMock.restore(); }); - it('should trigger beacon on page visibilitychange events', function(done) { + it('should trigger beacon on page visibilitychange events', function (done) { window.mParticle._resetForTests(MPConfig); const bond = sinon.spy(navigator, 'sendBeacon'); window.mParticle.init(apiKey, window.mParticle.config); - waitForCondition(hasIdentifyReturned) - .then(() => { - - // visibility change is a document property, not window - document.dispatchEvent(new Event('visibilitychange')); + waitForCondition(hasIdentifyReturned).then(() => { + // visibility change is a document property, not window + document.dispatchEvent(new Event('visibilitychange')); - bond.called.should.eql(true); - bond.lastCall.args[0].should.eql(urls.events); + bond.called.should.eql(true); + bond.lastCall.args[0].should.eql(urls.events); - done(); - }) + done(); + }); }); - it('should trigger beacon on page beforeunload events', function(done) { + it('should trigger beacon on page beforeunload events', function (done) { window.mParticle._resetForTests(MPConfig); const bond = sinon.spy(navigator, 'sendBeacon'); window.mParticle.init(apiKey, window.mParticle.config); - waitForCondition(hasIdentifyReturned) - .then(() => { - - // karma fails if onbeforeunload is not set to null - window.onbeforeunload = null; - window.dispatchEvent(new Event('beforeunload')); + waitForCondition(hasIdentifyReturned).then(() => { + // karma fails if onbeforeunload is not set to null + window.onbeforeunload = null; + window.dispatchEvent(new Event('beforeunload')); - bond.called.should.eql(true); - bond.getCalls()[0].args[0].should.eql(urls.events); + bond.called.should.eql(true); + bond.getCalls()[0].args[0].should.eql(urls.events); - done(); + done(); }); }); - it('should trigger beacon on pagehide events', function(done) { + it('should trigger beacon on pagehide events', function (done) { window.mParticle._resetForTests(MPConfig); const bond = sinon.spy(navigator, 'sendBeacon'); window.mParticle.init(apiKey, window.mParticle.config); - waitForCondition(hasIdentifyReturned) - .then(() => { - - window.dispatchEvent(new Event('pagehide')); + waitForCondition(hasIdentifyReturned).then(() => { + window.dispatchEvent(new Event('pagehide')); - bond.called.should.eql(true); - bond.getCalls()[0].args[0].should.eql(urls.events); + bond.called.should.eql(true); + bond.getCalls()[0].args[0].should.eql(urls.events); - (typeof bond.getCalls()[0].args[1]).should.eql('object'); + (typeof bond.getCalls()[0].args[1]).should.eql('object'); - done(); + done(); }); }); @@ -124,173 +123,168 @@ describe('Beacon Upload', () => { fetchMock.restore(); }); - it('`visibilitychange` should purge events and batches from Offline Storage after dispatch', function(done) { + it('`visibilitychange` should purge events and batches from Offline Storage after dispatch', function (done) { const eventStorageKey = 'mprtcl-v4_abcdef-events'; const batchStorageKey = 'mprtcl-v4_abcdef-batches'; window.mParticle._resetForTests(MPConfig); window.mParticle.init(apiKey, window.mParticle.config); - waitForCondition(hasIdentifyReturned) - .then(() => { - const mpInstance = window.mParticle.getInstance(); - const uploader = mpInstance._APIClient.uploader; - - // Add batches to queue so we can confirm they are purged later - uploader.batchesQueuedForProcessing.push(batch1); - uploader.batchesQueuedForProcessing.push(batch2); - uploader.batchesQueuedForProcessing.push(batch3); - uploader.queueEvent(event0); - - expect( - window.sessionStorage.getItem(eventStorageKey), - 'Stored Events should exist' - ).to.be.ok; - - expect( - JSON.parse(window.sessionStorage.getItem(eventStorageKey)) - .length, - 'Events should be populated before Before Dispatch' - ).to.equal(3); - - expect( - uploader.batchesQueuedForProcessing.length, - 'Batch Queue be populated before dispatch' - ).to.equal(3); - - // Dispatching event will trigger upload process - // visibility change is a document property, not window - document.dispatchEvent(new Event('visibilitychange')); - - expect( - window.sessionStorage.getItem(eventStorageKey), - 'Events should be empty after dispatch' - ).to.equal(''); - - expect( - window.localStorage.getItem(batchStorageKey), - 'Batches should be empty after dispatch' - ).to.equal(null); - - expect( - uploader.batchesQueuedForProcessing.length, - 'Batch Queue should be empty after dispatch' - ).to.equal(0); - - done(); + waitForCondition(hasIdentifyReturned).then(() => { + const mpInstance = window.mParticle.getInstance(); + const uploader = mpInstance._APIClient.uploader; + + // Add batches to queue so we can confirm they are purged later + uploader.batchesQueuedForProcessing.push(batch1); + uploader.batchesQueuedForProcessing.push(batch2); + uploader.batchesQueuedForProcessing.push(batch3); + uploader.queueEvent(event0); + + expect( + window.sessionStorage.getItem(eventStorageKey), + 'Stored Events should exist', + ).to.be.ok; + + expect( + JSON.parse(window.sessionStorage.getItem(eventStorageKey)) + .length, + 'Events should be populated before Before Dispatch', + ).to.equal(3); + + expect( + uploader.batchesQueuedForProcessing.length, + 'Batch Queue be populated before dispatch', + ).to.equal(3); + + // Dispatching event will trigger upload process + // visibility change is a document property, not window + document.dispatchEvent(new Event('visibilitychange')); + + expect( + window.sessionStorage.getItem(eventStorageKey), + 'Events should be empty after dispatch', + ).to.equal(''); + + expect( + window.localStorage.getItem(batchStorageKey), + 'Batches should be empty after dispatch', + ).to.equal(null); + + expect( + uploader.batchesQueuedForProcessing.length, + 'Batch Queue should be empty after dispatch', + ).to.equal(0); + + done(); }); }); - it('`beforeunload` should purge events and batches from Offline Storage after dispatch', function(done) { + it('`beforeunload` should purge events and batches from Offline Storage after dispatch', function (done) { const eventStorageKey = 'mprtcl-v4_abcdef-events'; const batchStorageKey = 'mprtcl-v4_abcdef-batches'; window.mParticle._resetForTests(MPConfig); window.mParticle.init(apiKey, window.mParticle.config); - waitForCondition(hasIdentifyReturned) - .then(() => { - - const mpInstance = window.mParticle.getInstance(); - const uploader = mpInstance._APIClient.uploader; - - // Add batches to queue so we can confirm they are purged later - uploader.batchesQueuedForProcessing.push(batch1); - uploader.batchesQueuedForProcessing.push(batch2); - uploader.batchesQueuedForProcessing.push(batch3); - - uploader.queueEvent(event0); - - expect( - window.sessionStorage.getItem(eventStorageKey), - 'Stored Events should exist' - ).to.be.ok; - - expect( - JSON.parse(window.sessionStorage.getItem(eventStorageKey)) - .length, - 'Events should be populated before Before Dispatch' - ).to.equal(3); - - expect( - uploader.batchesQueuedForProcessing.length, - 'Batch Queue be populated before dispatch' - ).to.equal(3); - - // Dispatching event will trigger upload process - window.dispatchEvent(new Event('beforeunload')); - - expect( - window.sessionStorage.getItem(eventStorageKey), - 'Events should be empty after dispatch' - ).to.equal(''); - - expect( - window.localStorage.getItem(batchStorageKey), - 'Batches should be empty after dispatch' - ).to.equal(null); - - expect( - uploader.batchesQueuedForProcessing.length, - 'Batch Queue should be empty after dispatch' - ).to.equal(0); - - done(); - }); + waitForCondition(hasIdentifyReturned).then(() => { + const mpInstance = window.mParticle.getInstance(); + const uploader = mpInstance._APIClient.uploader; + + // Add batches to queue so we can confirm they are purged later + uploader.batchesQueuedForProcessing.push(batch1); + uploader.batchesQueuedForProcessing.push(batch2); + uploader.batchesQueuedForProcessing.push(batch3); + + uploader.queueEvent(event0); + + expect( + window.sessionStorage.getItem(eventStorageKey), + 'Stored Events should exist', + ).to.be.ok; + + expect( + JSON.parse(window.sessionStorage.getItem(eventStorageKey)) + .length, + 'Events should be populated before Before Dispatch', + ).to.equal(3); + + expect( + uploader.batchesQueuedForProcessing.length, + 'Batch Queue be populated before dispatch', + ).to.equal(3); + + // Dispatching event will trigger upload process + window.dispatchEvent(new Event('beforeunload')); + + expect( + window.sessionStorage.getItem(eventStorageKey), + 'Events should be empty after dispatch', + ).to.equal(''); + + expect( + window.localStorage.getItem(batchStorageKey), + 'Batches should be empty after dispatch', + ).to.equal(null); + + expect( + uploader.batchesQueuedForProcessing.length, + 'Batch Queue should be empty after dispatch', + ).to.equal(0); + + done(); + }); }); - it('`pagehide` should purge events and batches from Offline Storage after dispatch', function(done) { + it('`pagehide` should purge events and batches from Offline Storage after dispatch', function (done) { const eventStorageKey = 'mprtcl-v4_abcdef-events'; const batchStorageKey = 'mprtcl-v4_abcdef-batches'; window.mParticle._resetForTests(MPConfig); window.mParticle.init(apiKey, window.mParticle.config); - waitForCondition(hasIdentifyReturned) - .then(() => { - - const mpInstance = window.mParticle.getInstance(); - const uploader = mpInstance._APIClient.uploader; - - // Add batches to queue so we can confirm they are purged later - uploader.batchesQueuedForProcessing.push(batch1); - uploader.batchesQueuedForProcessing.push(batch2); - uploader.batchesQueuedForProcessing.push(batch3); - - uploader.queueEvent(event0); - - expect( - window.sessionStorage.getItem(eventStorageKey), - 'Stored Events should exist' - ).to.be.ok; - - expect( - JSON.parse(window.sessionStorage.getItem(eventStorageKey)) - .length, - 'Events should be populated before Before Dispatch' - ).to.equal(3); - - expect( - uploader.batchesQueuedForProcessing.length, - 'Batch Queue be populated before dispatch' - ).to.equal(3); - - // Dispatching event will trigger upload process - window.dispatchEvent(new Event('pagehide')); - - expect( - window.sessionStorage.getItem(eventStorageKey), - 'Events should be empty after dispatch' - ).to.equal(''); - - expect( - window.localStorage.getItem(batchStorageKey), - 'Batches should be empty after dispatch' - ).to.equal(null); - - expect( - uploader.batchesQueuedForProcessing.length, - 'Batch Queue should be empty after dispatch' - ).to.equal(0); - - done(); + waitForCondition(hasIdentifyReturned).then(() => { + const mpInstance = window.mParticle.getInstance(); + const uploader = mpInstance._APIClient.uploader; + + // Add batches to queue so we can confirm they are purged later + uploader.batchesQueuedForProcessing.push(batch1); + uploader.batchesQueuedForProcessing.push(batch2); + uploader.batchesQueuedForProcessing.push(batch3); + + uploader.queueEvent(event0); + + expect( + window.sessionStorage.getItem(eventStorageKey), + 'Stored Events should exist', + ).to.be.ok; + + expect( + JSON.parse(window.sessionStorage.getItem(eventStorageKey)) + .length, + 'Events should be populated before Before Dispatch', + ).to.equal(3); + + expect( + uploader.batchesQueuedForProcessing.length, + 'Batch Queue be populated before dispatch', + ).to.equal(3); + + // Dispatching event will trigger upload process + window.dispatchEvent(new Event('pagehide')); + + expect( + window.sessionStorage.getItem(eventStorageKey), + 'Events should be empty after dispatch', + ).to.equal(''); + + expect( + window.localStorage.getItem(batchStorageKey), + 'Batches should be empty after dispatch', + ).to.equal(null); + + expect( + uploader.batchesQueuedForProcessing.length, + 'Batch Queue should be empty after dispatch', + ).to.equal(0); + + done(); }); }); }); -}); \ No newline at end of file +}); diff --git a/test/src/tests-config-api-client.ts b/test/src/tests-config-api-client.ts index 29a8d62a4..054f43e8a 100644 --- a/test/src/tests-config-api-client.ts +++ b/test/src/tests-config-api-client.ts @@ -2,7 +2,7 @@ import sinon from 'sinon'; import fetchMock from 'fetch-mock/esm/client'; import { urls, apiKey, MPConfig } from './config/constants'; import { expect } from 'chai'; -import ConfigAPIClient from '../../src/configAPIClient'; +import ConfigAPIClient from '../../src/configAPIClient'; import { DataPlanConfig, DataPlanResult, @@ -59,7 +59,7 @@ describe('ConfigAPIClient', () => { const configAPIClient = new ConfigAPIClient( apiKey, config, - window.mParticle.getInstance() + window.mParticle.getInstance(), ); const response = @@ -82,7 +82,7 @@ describe('ConfigAPIClient', () => { const configAPIClient = new ConfigAPIClient( apiKey, config, - window.mParticle.getInstance() + window.mParticle.getInstance(), ); const response = @@ -147,7 +147,7 @@ describe('ConfigAPIClient', () => { const configAPIClient = new ConfigAPIClient( apiKey, config, - window.mParticle.getInstance() + window.mParticle.getInstance(), ); const response = @@ -166,7 +166,7 @@ describe('ConfigAPIClient', () => { const configAPIClient = new ConfigAPIClient( apiKey, config, - window.mParticle.getInstance() + window.mParticle.getInstance(), ); const response = @@ -176,16 +176,15 @@ describe('ConfigAPIClient', () => { expect(response.appName).to.equal('Test App'); expect(response.kitConfigs).to.deep.equal([]); expect(response.dataPlanResult).to.deep.equal( - dataPlanResult + dataPlanResult, ); }); }); }); }); - describe('with XHRUploader', () => { - var fetchHolder = window.fetch; + const fetchHolder = window.fetch; beforeEach(() => { delete window.fetch; }); @@ -213,7 +212,7 @@ describe('ConfigAPIClient', () => { const configAPIClient = new ConfigAPIClient( apiKey, config, - window.mParticle.getInstance() + window.mParticle.getInstance(), ); const response = @@ -221,7 +220,7 @@ describe('ConfigAPIClient', () => { expect(mockServer.requests.length).to.equal(1); expect(mockServer.lastRequest).to.haveOwnProperty( - 'response' + 'response', ); expect(mockServer.lastRequest.url).to.equal(urls.config); @@ -237,7 +236,7 @@ describe('ConfigAPIClient', () => { const configAPIClient = new ConfigAPIClient( apiKey, config, - window.mParticle.getInstance() + window.mParticle.getInstance(), ); const response = @@ -245,7 +244,7 @@ describe('ConfigAPIClient', () => { expect(mockServer.requests.length).to.equal(1); expect(mockServer.lastRequest).to.haveOwnProperty( - 'response' + 'response', ); expect(mockServer.lastRequest.url).to.equal(urls.config); @@ -302,7 +301,7 @@ describe('ConfigAPIClient', () => { const configAPIClient = new ConfigAPIClient( apiKey, config, - window.mParticle.getInstance() + window.mParticle.getInstance(), ); const response = @@ -321,7 +320,7 @@ describe('ConfigAPIClient', () => { const configAPIClient = new ConfigAPIClient( apiKey, config, - window.mParticle.getInstance() + window.mParticle.getInstance(), ); const response = @@ -333,7 +332,7 @@ describe('ConfigAPIClient', () => { expect(response.appName).to.equal('Test App'); expect(response.kitConfigs).to.deep.equal([]); expect(response.dataPlanResult).to.deep.equal( - dataPlanResult + dataPlanResult, ); }); }); diff --git a/test/src/tests-consent.ts b/test/src/tests-consent.ts index 6f4c3de8b..6e22a4bcd 100644 --- a/test/src/tests-consent.ts +++ b/test/src/tests-consent.ts @@ -17,32 +17,33 @@ declare global { type GDPRConsentStateDictionary = Dictionary; -const BadBoolean = (0 as unknown) as boolean; -const BadNumberAsString = (10 as unknown) as string; -const BadStringBoolean = ('foo bar' as unknown) as boolean; -const EmptyObjectAsPrivacyConsentState = ({} as unknown) as PrivacyConsentState; -const EmptyStringAsPrivacyConsentState = ('' as unknown) as PrivacyConsentState; +const BadBoolean = 0 as unknown as boolean; +const BadNumberAsString = 10 as unknown as string; +const BadStringBoolean = 'foo bar' as unknown as boolean; +const EmptyObjectAsPrivacyConsentState = {} as unknown as PrivacyConsentState; +const EmptyStringAsPrivacyConsentState = '' as unknown as PrivacyConsentState; const findBatch = Utils.findBatch; const mParticle = window.mParticle; -describe('Consent', function() { - beforeEach(function() { +describe('Consent', function () { + beforeEach(function () { fetchMock.post(urls.events, 200); fetchMockSuccess(urls.identify, { - mpid: testMPID, is_logged_in: false + mpid: testMPID, + is_logged_in: false, }); mParticle.init(apiKey, window.mParticle.config); }); - afterEach(function() { + afterEach(function () { fetchMock.restore(); mParticle._resetForTests(MPConfig); }); - it('Should not create consent object without consented boolean', done => { + it('Should not create consent object without consented boolean', (done) => { let consent = mParticle.Consent.createGDPRConsent(null); expect(consent === null).to.be.ok; @@ -54,7 +55,7 @@ describe('Consent', function() { done(); }); - it('Should create basic consent object with only consented boolean', done => { + it('Should create basic consent object with only consented boolean', (done) => { let consent = mParticle.Consent.createGDPRConsent(true); expect(consent).to.be.ok; @@ -66,8 +67,8 @@ describe('Consent', function() { done(); }); - it('Should not create consent object with invalid document', done => { - const badDocument = (123 as unknown) as string; + it('Should not create consent object with invalid document', (done) => { + const badDocument = 123 as unknown as string; const consent = mParticle .getInstance() .Consent.createGDPRConsent(true, 123, badDocument); @@ -76,8 +77,8 @@ describe('Consent', function() { done(); }); - it('Should not create consent object with invalid location', done => { - const badLocation = (123 as unknown) as string; + it('Should not create consent object with invalid location', (done) => { + const badLocation = 123 as unknown as string; const consent = mParticle .getInstance() .Consent.createGDPRConsent(true, 123, 'foo document', badLocation); @@ -86,8 +87,8 @@ describe('Consent', function() { done(); }); - it('Should not create consent object with invalid hardware id', done => { - const badHardwareId = (123 as unknown) as string; + it('Should not create consent object with invalid hardware id', (done) => { + const badHardwareId = 123 as unknown as string; const consent = mParticle .getInstance() .Consent.createGDPRConsent( @@ -95,21 +96,21 @@ describe('Consent', function() { 123, 'foo document', 'foo location', - badHardwareId + badHardwareId, ); expect(consent === null).to.be.ok; done(); }); - it('Should set current timestamp if none given', done => { + it('Should set current timestamp if none given', (done) => { const date = Date.now(); const consent = mParticle.Consent.createGDPRConsent(true); expect(consent.Timestamp).to.be.greaterThanOrEqual(date); done(); }); - it('Should create complete object', done => { + it('Should create complete object', (done) => { const consent = mParticle .getInstance() .Consent.createGDPRConsent( @@ -117,7 +118,7 @@ describe('Consent', function() { 10, 'foo document', 'foo location', - 'foo hardware id' + 'foo hardware id', ); expect(consent).to.be.ok; consent.should.have.property('Consented', true); @@ -128,7 +129,7 @@ describe('Consent', function() { done(); }); - it('Should create basic ConsentState object', done => { + it('Should create basic ConsentState object', (done) => { const consentState = mParticle .getInstance() .Consent.createConsentState(); @@ -136,7 +137,7 @@ describe('Consent', function() { done(); }); - it('Should add GDPR ConsentState object', done => { + it('Should add GDPR ConsentState object', (done) => { const consentState = mParticle .getInstance() .Consent.createConsentState(); @@ -145,11 +146,11 @@ describe('Consent', function() { consentState .addGDPRConsentState( 'foo', - mParticle.Consent.createGDPRConsent(true) + mParticle.Consent.createGDPRConsent(true), ) .addGDPRConsentState( 'bar', - mParticle.Consent.createGDPRConsent(false) + mParticle.Consent.createGDPRConsent(false), ); expect(consentState.getGDPRConsentState()).to.have.property('foo'); @@ -158,7 +159,7 @@ describe('Consent', function() { // rather than a consent state expect(consentState.getGDPRConsentState().foo).to.have.property( 'Consented', - true + true, ); // Test is verifying that attribute GDPR does not exist in ConsentState @@ -168,13 +169,13 @@ describe('Consent', function() { expect(consentState.getGDPRConsentState()).to.have.property('bar'); expect(consentState.getGDPRConsentState().bar).to.have.property( 'Consented', - false + false, ); done(); }); - it('Should replace GDPR ConsentState object', done => { + it('Should replace GDPR ConsentState object', (done) => { const consentState = mParticle .getInstance() .Consent.createConsentState(); @@ -184,16 +185,16 @@ describe('Consent', function() { consentState.addGDPRConsentState( 'foo', - mParticle.Consent.createGDPRConsent(true) + mParticle.Consent.createGDPRConsent(true), ); consentState2.addGDPRConsentState( 'bar', - mParticle.Consent.createGDPRConsent(false) + mParticle.Consent.createGDPRConsent(false), ); consentState2.addGDPRConsentState( 'baz', - mParticle.Consent.createGDPRConsent(false) + mParticle.Consent.createGDPRConsent(false), ); consentState.getGDPRConsentState().should.have.property('foo'); @@ -209,7 +210,7 @@ describe('Consent', function() { done(); }); - it('should not be able to modify GDPR ConsentState object', done => { + it('should not be able to modify GDPR ConsentState object', (done) => { const consentState = mParticle .getInstance() .Consent.createConsentState(); @@ -218,11 +219,11 @@ describe('Consent', function() { consentState .addGDPRConsentState( 'foo', - mParticle.Consent.createGDPRConsent(true) + mParticle.Consent.createGDPRConsent(true), ) .addGDPRConsentState( 'bar', - mParticle.Consent.createGDPRConsent(false) + mParticle.Consent.createGDPRConsent(false), ); consentState.getGDPRConsentState().should.have.property('foo'); @@ -234,7 +235,7 @@ describe('Consent', function() { done(); }); - it('Should copy GDPR ConsentState object', done => { + it('Should copy GDPR ConsentState object', (done) => { const consentState = mParticle .getInstance() .Consent.createConsentState(); @@ -243,11 +244,11 @@ describe('Consent', function() { consentState .addGDPRConsentState( 'foo', - mParticle.Consent.createGDPRConsent(true) + mParticle.Consent.createGDPRConsent(true), ) .addGDPRConsentState( 'bar', - mParticle.Consent.createGDPRConsent(false) + mParticle.Consent.createGDPRConsent(false), ); const consentState2 = mParticle @@ -256,41 +257,41 @@ describe('Consent', function() { consentState2.addGDPRConsentState( 'baz', - mParticle.Consent.createGDPRConsent(false) + mParticle.Consent.createGDPRConsent(false), ); expect(consentState.getGDPRConsentState()).to.have.property('foo'); expect(consentState.getGDPRConsentState().foo).to.have.property( 'Consented', - true + true, ); consentState.getGDPRConsentState().should.have.property('bar'); expect(consentState.getGDPRConsentState().bar).to.have.property( 'Consented', - false + false, ); consentState.getGDPRConsentState().should.not.have.property('baz'); consentState2.getGDPRConsentState().should.have.property('foo'); expect(consentState2.getGDPRConsentState().foo).to.have.property( 'Consented', - true + true, ); consentState2.getGDPRConsentState().should.have.property('bar'); expect(consentState2.getGDPRConsentState().bar).to.have.property( 'Consented', - false + false, ); consentState2.getGDPRConsentState().should.have.property('baz'); expect(consentState2.getGDPRConsentState().baz).to.have.property( 'Consented', - false + false, ); done(); }); - it('Should remove GDPR ConsentState object', done => { + it('Should remove GDPR ConsentState object', (done) => { const consentState = mParticle .getInstance() .Consent.createConsentState(); @@ -299,11 +300,11 @@ describe('Consent', function() { consentState .addGDPRConsentState( 'foo', - mParticle.Consent.createGDPRConsent(true) + mParticle.Consent.createGDPRConsent(true), ) .addGDPRConsentState( 'bar', - mParticle.Consent.createGDPRConsent(false) + mParticle.Consent.createGDPRConsent(false), ); consentState.getGDPRConsentState().should.have.property('foo'); @@ -316,7 +317,7 @@ describe('Consent', function() { done(); }); - it('Should normalize GDPR consent purposes on add', done => { + it('Should normalize GDPR consent purposes on add', (done) => { const consentState = mParticle .getInstance() .Consent.createConsentState(); @@ -325,19 +326,19 @@ describe('Consent', function() { consentState .addGDPRConsentState( 'foo', - mParticle.Consent.createGDPRConsent(true, 1) + mParticle.Consent.createGDPRConsent(true, 1), ) .addGDPRConsentState( 'bar ', - mParticle.Consent.createGDPRConsent(true, 2) + mParticle.Consent.createGDPRConsent(true, 2), ) .addGDPRConsentState( 'BAZ ', - mParticle.Consent.createGDPRConsent(false, 3) + mParticle.Consent.createGDPRConsent(false, 3), ) .addGDPRConsentState( ' ', - mParticle.Consent.createGDPRConsent(false, 4) + mParticle.Consent.createGDPRConsent(false, 4), ); const gdprConsentState = consentState.getGDPRConsentState(); @@ -355,7 +356,7 @@ describe('Consent', function() { done(); }); - it('Should normalize GDPR consent purposes on remove', done => { + it('Should normalize GDPR consent purposes on remove', (done) => { const consentState = mParticle .getInstance() .Consent.createConsentState(); @@ -364,15 +365,15 @@ describe('Consent', function() { consentState .addGDPRConsentState( 'foo', - mParticle.Consent.createGDPRConsent(true, 1) + mParticle.Consent.createGDPRConsent(true, 1), ) .addGDPRConsentState( 'bar ', - mParticle.Consent.createGDPRConsent(true, 2) + mParticle.Consent.createGDPRConsent(true, 2), ) .addGDPRConsentState( 'BAZ ', - mParticle.Consent.createGDPRConsent(false, 3) + mParticle.Consent.createGDPRConsent(false, 3), ); const gdprConsentState = consentState.getGDPRConsentState(); @@ -395,7 +396,7 @@ describe('Consent', function() { done(); }); - it('Should not set junk GDPR object', done => { + it('Should not set junk GDPR object', (done) => { const consentState = mParticle .getInstance() .Consent.createConsentState(); @@ -404,26 +405,26 @@ describe('Consent', function() { consentState .addGDPRConsentState( 'foo', - mParticle.Consent.createGDPRConsent(true) + mParticle.Consent.createGDPRConsent(true), ) .addGDPRConsentState('bar', EmptyObjectAsPrivacyConsentState) .addGDPRConsentState('baz', EmptyStringAsPrivacyConsentState) .addGDPRConsentState( BadNumberAsString, - EmptyObjectAsPrivacyConsentState + EmptyObjectAsPrivacyConsentState, ); expect(consentState.getGDPRConsentState()).to.have.property('foo'); expect(consentState.getGDPRConsentState()).to.not.have.property('bar'); expect(consentState.getGDPRConsentState()).to.not.have.property('baz'); expect(consentState.getGDPRConsentState()).to.not.have.property( - (10 as unknown) as string + 10 as unknown as string, ); done(); }); - it('Should toJson/fromJson complete Consent State object', done => { + it('Should toJson/fromJson complete Consent State object', (done) => { const consent1 = mParticle .getInstance() .Consent.createGDPRConsent( @@ -431,7 +432,7 @@ describe('Consent', function() { 10, 'foo document', 'foo location', - 'foo hardware id' + 'foo hardware id', ); const consent2 = mParticle @@ -441,7 +442,7 @@ describe('Consent', function() { 5, 'foo document 2', 'foo location 2', - 'foo hardware id 2' + 'foo hardware id 2', ); const consentState = mParticle @@ -456,13 +457,14 @@ describe('Consent', function() { mParticle .getInstance() ._Consent.ConsentSerialization.toMinifiedJsonObject( - consentState - ) + consentState, + ), ); consentStateCopy.getGDPRConsentState().should.have.property('foo'); - const consentCopy1 = ((consentStateCopy.getGDPRConsentState() as unknown) as GDPRConsentStateDictionary) - .foo; + const consentCopy1 = ( + consentStateCopy.getGDPRConsentState() as unknown as GDPRConsentStateDictionary + ).foo; consentCopy1.should.have.property('Consented', true); consentCopy1.should.have.property('Timestamp', 10); @@ -471,8 +473,9 @@ describe('Consent', function() { consentCopy1.should.have.property('HardwareId', 'foo hardware id'); consentStateCopy.getGDPRConsentState().should.have.property('bar'); - const consentCopy2 = ((consentStateCopy.getGDPRConsentState() as unknown) as GDPRConsentStateDictionary) - .bar; + const consentCopy2 = ( + consentStateCopy.getGDPRConsentState() as unknown as GDPRConsentStateDictionary + ).bar; consentCopy2.should.have.property('Consented', false); consentCopy2.should.have.property('Timestamp', 5); @@ -483,7 +486,7 @@ describe('Consent', function() { done(); }); - it('Should not create a CCPA consent object without consented boolean', done => { + it('Should not create a CCPA consent object without consented boolean', (done) => { let consent = mParticle.Consent.createCCPAConsent(null); expect(consent === null).to.be.ok; @@ -495,7 +498,7 @@ describe('Consent', function() { done(); }); - it('Should create basic consent object with only consented boolean', done => { + it('Should create basic consent object with only consented boolean', (done) => { let consent = mParticle.Consent.createCCPAConsent(true); expect(consent).to.be.ok; @@ -507,8 +510,8 @@ describe('Consent', function() { done(); }); - it('Should not create consent object with invalid document', done => { - const badDocument = (123 as unknown) as string; + it('Should not create consent object with invalid document', (done) => { + const badDocument = 123 as unknown as string; const consent = mParticle .getInstance() .Consent.createCCPAConsent(true, 123, badDocument); @@ -517,8 +520,8 @@ describe('Consent', function() { done(); }); - it('Should not create consent object with invalid location', done => { - const badLocation = (123 as unknown) as string; + it('Should not create consent object with invalid location', (done) => { + const badLocation = 123 as unknown as string; const consent = mParticle .getInstance() .Consent.createCCPAConsent(true, 123, 'foo document', badLocation); @@ -527,8 +530,8 @@ describe('Consent', function() { done(); }); - it('Should not create consent object with invalid hardware id', done => { - const badHardwareId = (123 as unknown) as string; + it('Should not create consent object with invalid hardware id', (done) => { + const badHardwareId = 123 as unknown as string; const consent = mParticle .getInstance() .Consent.createCCPAConsent( @@ -536,21 +539,21 @@ describe('Consent', function() { 123, 'foo document', 'foo location', - badHardwareId + badHardwareId, ); expect(consent === null).to.be.ok; done(); }); - it('Should set current timestamp if none given', done => { + it('Should set current timestamp if none given', (done) => { const date = Date.now(); const consent = mParticle.Consent.createCCPAConsent(true); expect(consent.Timestamp).to.be.greaterThanOrEqual(date); done(); }); - it('Should create complete CCPA consent object', done => { + it('Should create complete CCPA consent object', (done) => { const consent = mParticle .getInstance() .Consent.createCCPAConsent( @@ -558,7 +561,7 @@ describe('Consent', function() { 10, 'foo document', 'foo location', - 'foo hardware id' + 'foo hardware id', ); expect(consent).to.be.ok; consent.should.have.property('Consented', true); @@ -570,55 +573,55 @@ describe('Consent', function() { done(); }); - it('Should set CCPA ConsentState object', done => { + it('Should set CCPA ConsentState object', (done) => { const consentState = mParticle .getInstance() .Consent.createConsentState(); expect(consentState).to.be.ok; consentState.setCCPAConsentState( - mParticle.Consent.createCCPAConsent(false) + mParticle.Consent.createCCPAConsent(false), ); expect(consentState.getCCPAConsentState()).to.have.property( - 'Consented' + 'Consented', ); expect(consentState.getCCPAConsentState()).to.have.property( - 'ConsentDocument' + 'ConsentDocument', ); expect(consentState.getCCPAConsentState()).to.have.property( - 'HardwareId' + 'HardwareId', ); expect(consentState.getCCPAConsentState()).to.have.property('Location'); expect(consentState.getCCPAConsentState()).to.have.property( - 'Timestamp' + 'Timestamp', ); done(); }); - it('Should remove CCPA ConsentState object', done => { + it('Should remove CCPA ConsentState object', (done) => { const consentState = mParticle .getInstance() .Consent.createConsentState(); expect(consentState).to.be.ok; consentState.setCCPAConsentState( - mParticle.Consent.createCCPAConsent(false) + mParticle.Consent.createCCPAConsent(false), ); expect(consentState.getCCPAConsentState()).to.have.property( - 'Consented' + 'Consented', ); expect(consentState.getCCPAConsentState()).to.have.property( - 'ConsentDocument' + 'ConsentDocument', ); expect(consentState.getCCPAConsentState()).to.have.property( - 'HardwareId' + 'HardwareId', ); expect(consentState.getCCPAConsentState()).to.have.property('Location'); expect(consentState.getCCPAConsentState()).to.have.property( - 'Timestamp' + 'Timestamp', ); consentState.removeCCPAConsentState(); @@ -627,7 +630,7 @@ describe('Consent', function() { done(); }); - it('should have CCPA in payload', done => { + it('should have CCPA in payload', (done) => { const consentState = mParticle.Consent.createConsentState(); const timestamp = new Date().getTime(); const ccpaConsent = mParticle.Consent.createCCPAConsent( @@ -635,32 +638,48 @@ describe('Consent', function() { timestamp, 'consentDoc', 'location', - 'hardware' + 'hardware', ); consentState.setCCPAConsentState(ccpaConsent); - waitForCondition(hasIdentifyReturned) - .then(() => { - const user = mParticle.Identity.getCurrentUser(); - user.setConsentState(consentState); + waitForCondition(hasIdentifyReturned).then(() => { + const user = mParticle.Identity.getCurrentUser(); + user.setConsentState(consentState); - mParticle.logEvent('Test Event'); - const testEvent = findBatch(fetchMock.calls(), 'Test Event'); + mParticle.logEvent('Test Event'); + const testEvent = findBatch(fetchMock.calls(), 'Test Event'); - testEvent.should.have.property('consent_state'); - testEvent.consent_state.should.have.property('ccpa'); - testEvent.consent_state.ccpa.should.have.property('data_sale_opt_out'); - testEvent.consent_state.ccpa.data_sale_opt_out.should.have.property('consented', true); - testEvent.consent_state.ccpa.data_sale_opt_out.should.have.property('timestamp_unixtime_ms', timestamp); - testEvent.consent_state.ccpa.data_sale_opt_out.should.have.property('document', 'consentDoc'); - testEvent.consent_state.ccpa.data_sale_opt_out.should.have.property('location', 'location'); - testEvent.consent_state.ccpa.data_sale_opt_out.should.have.property('hardware_id', 'hardware'); + testEvent.should.have.property('consent_state'); + testEvent.consent_state.should.have.property('ccpa'); + testEvent.consent_state.ccpa.should.have.property( + 'data_sale_opt_out', + ); + testEvent.consent_state.ccpa.data_sale_opt_out.should.have.property( + 'consented', + true, + ); + testEvent.consent_state.ccpa.data_sale_opt_out.should.have.property( + 'timestamp_unixtime_ms', + timestamp, + ); + testEvent.consent_state.ccpa.data_sale_opt_out.should.have.property( + 'document', + 'consentDoc', + ); + testEvent.consent_state.ccpa.data_sale_opt_out.should.have.property( + 'location', + 'location', + ); + testEvent.consent_state.ccpa.data_sale_opt_out.should.have.property( + 'hardware_id', + 'hardware', + ); - done(); - }) + done(); + }); }); - it('should have CCPA and GDPR in payload', done => { + it('should have CCPA and GDPR in payload', (done) => { const consentState = mParticle.Consent.createConsentState(); const timestamp = new Date().getTime(); const ccpaConsent = mParticle.Consent.createCCPAConsent( @@ -668,51 +687,80 @@ describe('Consent', function() { timestamp, 'consentDoc', 'location', - 'hardware' + 'hardware', ); const gdprConsent = mParticle.Consent.createGDPRConsent( false, timestamp, 'consentDoc', 'location', - 'hardware' + 'hardware', ); consentState.setCCPAConsentState(ccpaConsent); consentState.addGDPRConsentState('test purpose', gdprConsent); - waitForCondition(hasIdentifyReturned) - .then(() => { - - const user = mParticle.Identity.getCurrentUser(); - user.setConsentState(consentState); - - - mParticle.logEvent('Test Event'); - - const testEvent = findBatch(fetchMock.calls(), 'Test Event'); - - testEvent.should.have.property('consent_state'); - testEvent.consent_state.should.have.property('ccpa'); - testEvent.consent_state.ccpa.should.have.property('data_sale_opt_out'); - testEvent.consent_state.ccpa.data_sale_opt_out.should.have.property('consented', true); - testEvent.consent_state.ccpa.data_sale_opt_out.should.have.property('timestamp_unixtime_ms', timestamp); - testEvent.consent_state.ccpa.data_sale_opt_out.should.have.property('document', 'consentDoc'); - testEvent.consent_state.ccpa.data_sale_opt_out.should.have.property('location', 'location'); - testEvent.consent_state.ccpa.data_sale_opt_out.should.have.property('hardware_id', 'hardware'); - - testEvent.consent_state.should.have.property('gdpr'); - testEvent.consent_state.gdpr.should.have.property('test purpose'); - testEvent.consent_state.gdpr['test purpose'].should.have.property('consented', false); - testEvent.consent_state.gdpr['test purpose'].should.have.property('timestamp_unixtime_ms', timestamp); - testEvent.consent_state.gdpr['test purpose'].should.have.property('document', 'consentDoc'); - testEvent.consent_state.gdpr['test purpose'].should.have.property('location', 'location'); - testEvent.consent_state.gdpr['test purpose'].should.have.property('hardware_id', 'hardware'); - - done(); - }) + waitForCondition(hasIdentifyReturned).then(() => { + const user = mParticle.Identity.getCurrentUser(); + user.setConsentState(consentState); + + mParticle.logEvent('Test Event'); + + const testEvent = findBatch(fetchMock.calls(), 'Test Event'); + + testEvent.should.have.property('consent_state'); + testEvent.consent_state.should.have.property('ccpa'); + testEvent.consent_state.ccpa.should.have.property( + 'data_sale_opt_out', + ); + testEvent.consent_state.ccpa.data_sale_opt_out.should.have.property( + 'consented', + true, + ); + testEvent.consent_state.ccpa.data_sale_opt_out.should.have.property( + 'timestamp_unixtime_ms', + timestamp, + ); + testEvent.consent_state.ccpa.data_sale_opt_out.should.have.property( + 'document', + 'consentDoc', + ); + testEvent.consent_state.ccpa.data_sale_opt_out.should.have.property( + 'location', + 'location', + ); + testEvent.consent_state.ccpa.data_sale_opt_out.should.have.property( + 'hardware_id', + 'hardware', + ); + + testEvent.consent_state.should.have.property('gdpr'); + testEvent.consent_state.gdpr.should.have.property('test purpose'); + testEvent.consent_state.gdpr['test purpose'].should.have.property( + 'consented', + false, + ); + testEvent.consent_state.gdpr['test purpose'].should.have.property( + 'timestamp_unixtime_ms', + timestamp, + ); + testEvent.consent_state.gdpr['test purpose'].should.have.property( + 'document', + 'consentDoc', + ); + testEvent.consent_state.gdpr['test purpose'].should.have.property( + 'location', + 'location', + ); + testEvent.consent_state.gdpr['test purpose'].should.have.property( + 'hardware_id', + 'hardware', + ); + + done(); + }); }); // TODO: Deprecate in next major version - it('Should log deprecated message when using removeCCPAState', done => { + it('Should log deprecated message when using removeCCPAState', (done) => { const bond = sinon.spy(mParticle.getInstance().Logger, 'warning'); const consentState = mParticle .getInstance() @@ -720,32 +768,32 @@ describe('Consent', function() { expect(consentState).to.be.ok; consentState.setCCPAConsentState( - mParticle.Consent.createCCPAConsent(false) + mParticle.Consent.createCCPAConsent(false), ); expect(consentState.getCCPAConsentState()).to.have.property( - 'Consented' + 'Consented', ); expect(consentState.getCCPAConsentState()).to.have.property( - 'ConsentDocument' + 'ConsentDocument', ); expect(consentState.getCCPAConsentState()).to.have.property( - 'HardwareId' + 'HardwareId', ); expect(consentState.getCCPAConsentState()).to.have.property('Location'); expect(consentState.getCCPAConsentState()).to.have.property( - 'Timestamp' + 'Timestamp', ); // FIXME: Remove when deprecating removeCCPAState - ((consentState as unknown) as any).removeCCPAState(); + (consentState as unknown as any).removeCCPAState(); (consentState.getCCPAConsentState() === undefined).should.equal(true); bond.called.should.eql(true); bond.getCalls()[0].args[0].should.eql( - 'removeCCPAState is deprecated and will be removed in a future release; use removeCCPAConsentState instead' + 'removeCCPAState is deprecated and will be removed in a future release; use removeCCPAConsentState instead', ); done(); }); -}); \ No newline at end of file +}); diff --git a/test/src/tests-cookie-syncing.ts b/test/src/tests-cookie-syncing.ts index 6f144795f..2f8216310 100644 --- a/test/src/tests-cookie-syncing.ts +++ b/test/src/tests-cookie-syncing.ts @@ -10,7 +10,7 @@ const { fetchMockSuccess, waitForCondition, hasIdentifyReturned, - hasConfigurationReturned + hasConfigurationReturned, } = Utils; const { setLocalStorage, MockForwarder, getLocalStorage } = Utils; @@ -36,42 +36,45 @@ declare global { const mParticle = window.mParticle; -describe('cookie syncing', function() { +describe('cookie syncing', function () { // Have a reference to createElement function to reset after all cookie sync // tests have run const originalCreateElementFunction = window.document.createElement; - before(function() { + before(function () { // Mock the img create onload method // https://raminmousavi.medium.com/mock-img-element-in-jest-3341c495ca8b - window.document.createElement = (function(create) { - return function(this: Document) { - const element = create.apply(this, arguments as unknown as [string, ElementCreationOptions?]); + window.document.createElement = (function (create) { + return function (this: Document) { + const element = create.apply( + this, + arguments as unknown as [string, ElementCreationOptions?], + ); if (element.tagName === 'IMG') { // Add an `onload` mock that simulates the browser loading the image Object.defineProperty(element, 'onload', { set(callback) { - // Automatically invoke the callback to simulate the `load` event + // Automatically invoke the callback to simulate the `load` event callback(new Event('load')); }, }); } return element; - }; })(document.createElement); }); - after(function() { + after(function () { // Reset the mock window.document.createElement = originalCreateElementFunction; }); - beforeEach(function() { + beforeEach(function () { fetchMockSuccess(urls.identify, { - mpid: testMPID, is_logged_in: false + mpid: testMPID, + is_logged_in: false, }); fetchMock.post(urls.events, 200); @@ -79,7 +82,7 @@ describe('cookie syncing', function() { mParticle.init(apiKey, window.mParticle.config); }); - afterEach(function() { + afterEach(function () { fetchMock.restore(); mParticle._resetForTests(MPConfig); }); @@ -89,10 +92,10 @@ describe('cookie syncing', function() { window.mParticle.config.pixelConfigs = [pixelSettings]; mParticle.init(apiKey, window.mParticle.config); - await waitForCondition(hasIdentifyReturned) + await waitForCondition(hasIdentifyReturned); expect( - mParticle.getInstance()._Store.pixelConfigurations.length + mParticle.getInstance()._Store.pixelConfigurations.length, ).to.equal(1); const data = mParticle.getInstance()._Persistence.getLocalStorage(); data[testMPID].csd.should.have.property('5'); @@ -111,10 +114,10 @@ describe('cookie syncing', function() { ie: true, }); mParticle.init(apiKey, window.mParticle.config); - await waitForCondition(hasIdentifyReturned) + await waitForCondition(hasIdentifyReturned); expect( - mParticle.getInstance()._Store.pixelConfigurations.length + mParticle.getInstance()._Store.pixelConfigurations.length, ).to.equal(1); const data = mParticle.getInstance()._Persistence.getLocalStorage(); @@ -131,16 +134,17 @@ describe('cookie syncing', function() { setLocalStorage(); mParticle.init(apiKey, window.mParticle.config); - await waitForCondition(hasIdentifyReturned) + await waitForCondition(hasIdentifyReturned); const data = mParticle.getInstance()._Persistence.getLocalStorage(); data[testMPID].csd.should.have.property( 5, - mParticle.getInstance()._Persistence.getLocalStorage().testMPID - .csd['5'] + mParticle.getInstance()._Persistence.getLocalStorage().testMPID.csd[ + '5' + ], ); expect( - mParticle.getInstance()._Store.pixelConfigurations.length + mParticle.getInstance()._Store.pixelConfigurations.length, ).to.equal(1); }); @@ -150,25 +154,25 @@ describe('cookie syncing', function() { mParticle.init(apiKey, window.mParticle.config); - await waitForCondition(hasIdentifyReturned) + await waitForCondition(hasIdentifyReturned); - const data1 = mParticle - .getInstance() - ._Persistence.getLocalStorage(); + const data1 = mParticle.getInstance()._Persistence.getLocalStorage(); fetchMockSuccess(urls.login, { - mpid: 'otherMPID', is_logged_in: false + mpid: 'otherMPID', + is_logged_in: false, }); - + mParticle.Identity.login(); - await waitForCondition(() => mParticle.Identity.getCurrentUser()?.getMPID() === 'otherMPID') - const data2 = mParticle - .getInstance() - ._Persistence.getLocalStorage(); + await waitForCondition( + () => + mParticle.Identity.getCurrentUser()?.getMPID() === 'otherMPID', + ); + const data2 = mParticle.getInstance()._Persistence.getLocalStorage(); expect(data1[testMPID].csd[5]).to.be.ok; expect(data2['otherMPID'].csd[5]).to.be.ok; - expect( - mParticle.getInstance()._Store.pixelConfigurations.length + expect( + mParticle.getInstance()._Store.pixelConfigurations.length, ).to.equal(1); }); @@ -190,15 +194,13 @@ describe('cookie syncing', function() { window.mParticle.config.pixelConfigs = [pixelSettings]; mParticle.init(apiKey, window.mParticle.config); - await waitForCondition(hasIdentifyReturned) + await waitForCondition(hasIdentifyReturned); - const data1 = mParticle - .getInstance() - ._Persistence.getLocalStorage(); + const data1 = mParticle.getInstance()._Persistence.getLocalStorage(); Object.keys(data1[testMPID]).should.not.have.property('csd'); - expect( - mParticle.getInstance()._Store.pixelConfigurations.length + expect( + mParticle.getInstance()._Store.pixelConfigurations.length, ).to.equal(0); }); @@ -220,16 +222,14 @@ describe('cookie syncing', function() { window.mParticle.config.pixelConfigs = [pixelSettings]; mParticle.init(apiKey, window.mParticle.config); - await waitForCondition(hasIdentifyReturned) + await waitForCondition(hasIdentifyReturned); - const data1 = mParticle - .getInstance() - ._Persistence.getLocalStorage(); + const data1 = mParticle.getInstance()._Persistence.getLocalStorage(); data1[testMPID].should.not.have.property('csd'); - expect( - mParticle.getInstance()._Store.pixelConfigurations.length + expect( + mParticle.getInstance()._Store.pixelConfigurations.length, ).to.equal(0); - }) + }); it('parse and capture pixel settings properly from backend', async () => { mParticle._resetForTests(MPConfig); @@ -264,34 +264,37 @@ describe('cookie syncing', function() { body: JSON.stringify(forwarderConfigurationResult), }); - await waitForCondition(hasIdentifyReturned) + await waitForCondition(hasIdentifyReturned); // add pixels to preInitConfig mParticle.init(apiKey, window.mParticle.config); - + await waitForCondition(hasConfigurationReturned); mParticle .getInstance() ._Store.pixelConfigurations.length.should.equal(1); fetchMockSuccess(urls.login, { - mpid: 'MPID1', is_logged_in: false - }); + mpid: 'MPID1', + is_logged_in: false, + }); // force the preInit cookie configurations to fire mParticle.Identity.login({ userIdentities: { customerid: 'abc' }, }); - await waitForCondition(() => mParticle.Identity.getCurrentUser()?.getMPID() === 'MPID1'); + await waitForCondition( + () => mParticle.Identity.getCurrentUser()?.getMPID() === 'MPID1', + ); const cookies = getLocalStorage(); Object.keys(cookies['MPID1'].csd).length.should.equal(1); }); - - const MockUser = function() { + + const MockUser = function () { let consentState = null; return { - setConsentState: function(state) { + setConsentState: function (state) { consentState = state; }, - getConsentState: function() { + getConsentState: function () { return consentState; }, }; @@ -300,15 +303,16 @@ describe('cookie syncing', function() { it('should perform a cookiesync when consent is not configured on the cookiesync setting', async () => { mParticle._resetForTests(MPConfig); - pixelSettings.filteringConsentRuleValues = {} as unknown as IConsentRules; + pixelSettings.filteringConsentRuleValues = + {} as unknown as IConsentRules; window.mParticle.config.pixelConfigs = [pixelSettings]; mParticle.init(apiKey, window.mParticle.config); await waitForCondition(hasIdentifyReturned); - expect( - mParticle.getInstance()._Store.pixelConfigurations.length + expect( + mParticle.getInstance()._Store.pixelConfigurations.length, ).to.equal(1); const data = mParticle.getInstance()._Persistence.getLocalStorage(); data[testMPID].csd.should.have.property('5'); @@ -337,7 +341,7 @@ describe('cookie syncing', function() { expect(enabled).to.not.be.ok; }); - it("should disable cookie sync if 'Do Not Forward' when 'Consent Rejected' is selected and user consent is rejected", function() { + it("should disable cookie sync if 'Do Not Forward' when 'Consent Rejected' is selected and user consent is rejected", function () { const includeOnMatch = false; // 'Do Not Forward' chosen in UI, 'includeOnMatch' in config const consented = false; const userConsent = false; @@ -349,7 +353,7 @@ describe('cookie syncing', function() { values: [ { consentPurpose: mParticle.generateHash( - '1' + 'foo purpose 1' + '1' + 'foo purpose 1', ), hasConsented: consented, }, @@ -361,7 +365,7 @@ describe('cookie syncing', function() { .Consent.createConsentState() .addGDPRConsentState( 'foo purpose 1', - mParticle.getInstance().Consent.createGDPRConsent(userConsent) + mParticle.getInstance().Consent.createGDPRConsent(userConsent), ); const user = MockUser() as IMParticleUser; user.setConsentState(consentState); @@ -371,7 +375,7 @@ describe('cookie syncing', function() { expect(enabled).to.not.be.ok; }); - it("should disable cookie sync if 'Do Not Forward' when 'Consent Accepted' is selected and user consent is given", function() { + it("should disable cookie sync if 'Do Not Forward' when 'Consent Accepted' is selected and user consent is given", function () { const includeOnMatch = false; // 'Do Not Forward' chosen in UI, 'includeOnMatch' in config const consented = true; const userConsent = true; @@ -382,7 +386,7 @@ describe('cookie syncing', function() { values: [ { consentPurpose: mParticle.generateHash( - '1' + 'foo purpose 1' + '1' + 'foo purpose 1', ), hasConsented: consented, }, @@ -394,7 +398,7 @@ describe('cookie syncing', function() { .Consent.createConsentState() .addGDPRConsentState( 'foo purpose 1', - mParticle.getInstance().Consent.createGDPRConsent(userConsent) + mParticle.getInstance().Consent.createGDPRConsent(userConsent), ); const user = MockUser() as IMParticleUser; user.setConsentState(consentState); @@ -405,7 +409,7 @@ describe('cookie syncing', function() { expect(enabled).to.not.be.ok; }); - it("should enable cookie sync if 'Only Forward' when 'Consent Rejected' is selected and user consent is rejected", function() { + it("should enable cookie sync if 'Only Forward' when 'Consent Rejected' is selected and user consent is rejected", function () { const includeOnMatch = true; // 'Only Forward' chosen in UI, 'includeOnMatch' in config const consented = false; const userConsent = false; @@ -417,7 +421,7 @@ describe('cookie syncing', function() { values: [ { consentPurpose: mParticle.generateHash( - '1' + 'foo purpose 1' + '1' + 'foo purpose 1', ), hasConsented: consented, }, @@ -429,7 +433,7 @@ describe('cookie syncing', function() { .Consent.createConsentState() .addGDPRConsentState( 'foo purpose 1', - mParticle.getInstance().Consent.createGDPRConsent(userConsent) + mParticle.getInstance().Consent.createGDPRConsent(userConsent), ); const user = MockUser() as IMParticleUser; user.setConsentState(consentState); @@ -440,7 +444,7 @@ describe('cookie syncing', function() { expect(enabled).to.be.ok; }); - it("should enable cookie sync if 'Only Forward' when 'Consent Given'is selected and user consent is given", function() { + it("should enable cookie sync if 'Only Forward' when 'Consent Given'is selected and user consent is given", function () { const includeOnMatch = true; // 'Do Not Forward' chosen in UI, 'includeOnMatch' in config const consented = true; const userConsent = true; @@ -452,7 +456,7 @@ describe('cookie syncing', function() { values: [ { consentPurpose: mParticle.generateHash( - '1' + 'foo purpose 1' + '1' + 'foo purpose 1', ), hasConsented: consented, }, @@ -464,7 +468,7 @@ describe('cookie syncing', function() { .Consent.createConsentState() .addGDPRConsentState( 'foo purpose 1', - mParticle.getInstance().Consent.createGDPRConsent(userConsent) + mParticle.getInstance().Consent.createGDPRConsent(userConsent), ); const user = MockUser() as IMParticleUser; user.setConsentState(consentState); @@ -474,7 +478,7 @@ describe('cookie syncing', function() { expect(enabled).to.be.ok; }); - it("should disable cookie sync if 'Only Forward' on 'Consent Given' is selected and user consent is not given", function() { + it("should disable cookie sync if 'Only Forward' on 'Consent Given' is selected and user consent is not given", function () { const includeOnMatch = true; // 'Do Not Forward' chosen in UI, 'includeOnMatch' in config const consented = true; const userConsented = false; @@ -486,7 +490,7 @@ describe('cookie syncing', function() { values: [ { consentPurpose: mParticle.generateHash( - '1' + 'foo purpose 1' + '1' + 'foo purpose 1', ), hasConsented: consented, }, @@ -498,7 +502,9 @@ describe('cookie syncing', function() { .Consent.createConsentState() .addGDPRConsentState( 'foo purpose 1', - mParticle.getInstance().Consent.createGDPRConsent(userConsented) + mParticle + .getInstance() + .Consent.createGDPRConsent(userConsented), ); const user = MockUser() as IMParticleUser; user.setConsentState(consentState); @@ -508,7 +514,7 @@ describe('cookie syncing', function() { expect(enabled).to.not.be.ok; }); - it("should perform a cookie sync if 'Do Not Forward' when 'Consent Rejected' is selected and user consent is given", function() { + it("should perform a cookie sync if 'Do Not Forward' when 'Consent Rejected' is selected and user consent is given", function () { const includeOnMatch = false; // 'Do Not Forward' chosen in UI, 'includeOnMatch' in config const consented = false; const userConsented = true; @@ -520,7 +526,7 @@ describe('cookie syncing', function() { values: [ { consentPurpose: mParticle.generateHash( - '1' + 'foo purpose 1' + '1' + 'foo purpose 1', ), hasConsented: consented, }, @@ -532,7 +538,9 @@ describe('cookie syncing', function() { .Consent.createConsentState() .addGDPRConsentState( 'foo purpose 1', - mParticle.getInstance().Consent.createGDPRConsent(userConsented) + mParticle + .getInstance() + .Consent.createGDPRConsent(userConsented), ); const user = MockUser() as IMParticleUser; user.setConsentState(consentState); @@ -542,7 +550,7 @@ describe('cookie syncing', function() { expect(enabled).to.be.ok; }); - it("should perform a cookie sync if 'Do Not Forward' when 'Consent Given' is selected and user consent is rejected", function() { + it("should perform a cookie sync if 'Do Not Forward' when 'Consent Given' is selected and user consent is rejected", function () { const includeOnMatch = false; // 'Do Not Forward' chosen in UI, 'includeOnMatch' in config const consented = true; const userConsented = false; @@ -554,7 +562,7 @@ describe('cookie syncing', function() { values: [ { consentPurpose: mParticle.generateHash( - '1' + 'foo purpose 1' + '1' + 'foo purpose 1', ), hasConsented: consented, }, @@ -566,7 +574,9 @@ describe('cookie syncing', function() { .Consent.createConsentState() .addGDPRConsentState( 'foo purpose 1', - mParticle.getInstance().Consent.createGDPRConsent(userConsented) + mParticle + .getInstance() + .Consent.createGDPRConsent(userConsented), ); const user = MockUser() as IMParticleUser; user.setConsentState(consentState); @@ -576,7 +586,7 @@ describe('cookie syncing', function() { expect(enabled).to.be.ok; }); - it("should perform a cookie sync if 'Do Not Forward' when 'Consent Rejected' is selected and user consent is given", function() { + it("should perform a cookie sync if 'Do Not Forward' when 'Consent Rejected' is selected and user consent is given", function () { const includeOnMatch = false; // 'Do Not Forward' chosen in UI, 'includeOnMatch' in config const consented = false; const userConsented = true; @@ -588,7 +598,7 @@ describe('cookie syncing', function() { values: [ { consentPurpose: mParticle.generateHash( - '1' + 'foo purpose 1' + '1' + 'foo purpose 1', ), hasConsented: consented, }, @@ -600,7 +610,9 @@ describe('cookie syncing', function() { .Consent.createConsentState() .addGDPRConsentState( 'foo purpose 1', - mParticle.getInstance().Consent.createGDPRConsent(userConsented) + mParticle + .getInstance() + .Consent.createGDPRConsent(userConsented), ); const user = MockUser() as IMParticleUser; user.setConsentState(consentState); @@ -610,7 +622,7 @@ describe('cookie syncing', function() { expect(enabled).to.be.ok; }); - it("should not perform a cookie sync if 'Do Not Forward' if CCPA is 'Not Present' is selected and user CCPA is not present", function() { + it("should not perform a cookie sync if 'Do Not Forward' if CCPA is 'Not Present' is selected and user CCPA is not present", function () { const includeOnMatch = false; // 'Do Not Forward' chosen in UI, 'includeOnMatch' in config const consented = false; const ccpaPresent = false; @@ -622,7 +634,7 @@ describe('cookie syncing', function() { values: [ { consentPurpose: mParticle.generateHash( - '2' + 'data_sale_opt_out' + '2' + 'data_sale_opt_out', ), hasConsented: consented, }, @@ -633,7 +645,7 @@ describe('cookie syncing', function() { .getInstance() .Consent.createConsentState() .setCCPAConsentState( - mParticle.getInstance().Consent.createCCPAConsent(ccpaPresent) + mParticle.getInstance().Consent.createCCPAConsent(ccpaPresent), ); const user = MockUser() as IMParticleUser; user.setConsentState(consentState); @@ -643,7 +655,7 @@ describe('cookie syncing', function() { expect(enabled).to.not.be.ok; }); - it("should not perform a cookie sync if 'Do Not Forward' if CCPA is 'Present' is selected and user CCPA is present", function() { + it("should not perform a cookie sync if 'Do Not Forward' if CCPA is 'Present' is selected and user CCPA is present", function () { const includeOnMatch = false; // 'Do Not Forward' chosen in UI, 'includeOnMatch' in config const consented = true; const ccpaPresent = true; @@ -655,7 +667,7 @@ describe('cookie syncing', function() { values: [ { consentPurpose: mParticle.generateHash( - '2' + 'data_sale_opt_out' + '2' + 'data_sale_opt_out', ), hasConsented: consented, }, @@ -666,7 +678,7 @@ describe('cookie syncing', function() { .getInstance() .Consent.createConsentState() .setCCPAConsentState( - mParticle.getInstance().Consent.createCCPAConsent(ccpaPresent) + mParticle.getInstance().Consent.createCCPAConsent(ccpaPresent), ); const user = MockUser() as IMParticleUser; user.setConsentState(consentState); @@ -676,7 +688,7 @@ describe('cookie syncing', function() { expect(enabled).to.not.be.ok; }); - it("should perform a cookie sync if 'Only Forward' if CCPA is 'Not Present' is selected and user CCPA is not present", function() { + it("should perform a cookie sync if 'Only Forward' if CCPA is 'Not Present' is selected and user CCPA is not present", function () { const includeOnMatch = true; // 'Do Not Forward' chosen in UI, 'includeOnMatch' in config const consented = false; const ccpaPresent = false; @@ -688,7 +700,7 @@ describe('cookie syncing', function() { values: [ { consentPurpose: mParticle.generateHash( - '2' + 'data_sale_opt_out' + '2' + 'data_sale_opt_out', ), hasConsented: consented, }, @@ -699,7 +711,7 @@ describe('cookie syncing', function() { .getInstance() .Consent.createConsentState() .setCCPAConsentState( - mParticle.getInstance().Consent.createCCPAConsent(ccpaPresent) + mParticle.getInstance().Consent.createCCPAConsent(ccpaPresent), ); const user = MockUser() as IMParticleUser; user.setConsentState(consentState); @@ -709,7 +721,7 @@ describe('cookie syncing', function() { expect(enabled).to.be.ok; }); - it("should perform a cookie sync if 'Only Forward' when CCPA is 'Present' is selected and user CCPA is present", function() { + it("should perform a cookie sync if 'Only Forward' when CCPA is 'Present' is selected and user CCPA is present", function () { const includeOnMatch = true; // 'Do Not Forward' chosen in UI, 'includeOnMatch' in config const consented = true; const ccpaPresent = true; @@ -721,7 +733,7 @@ describe('cookie syncing', function() { values: [ { consentPurpose: mParticle.generateHash( - '2' + 'data_sale_opt_out' + '2' + 'data_sale_opt_out', ), hasConsented: consented, }, @@ -732,7 +744,7 @@ describe('cookie syncing', function() { .getInstance() .Consent.createConsentState() .setCCPAConsentState( - mParticle.getInstance().Consent.createCCPAConsent(ccpaPresent) + mParticle.getInstance().Consent.createCCPAConsent(ccpaPresent), ); const user = MockUser() as IMParticleUser; user.setConsentState(consentState); @@ -742,7 +754,7 @@ describe('cookie syncing', function() { expect(enabled).to.be.ok; }); - it("should not perform a cookie sync if 'Only Forward' when CCPA is 'Present' is selected and CCPA is not present", function() { + it("should not perform a cookie sync if 'Only Forward' when CCPA is 'Present' is selected and CCPA is not present", function () { const includeOnMatch = true; // 'Do Not Forward' chosen in UI, 'includeOnMatch' in config const consented = true; const ccpaPresent = false; @@ -754,7 +766,7 @@ describe('cookie syncing', function() { values: [ { consentPurpose: mParticle.generateHash( - '2' + 'data_sale_opt_out' + '2' + 'data_sale_opt_out', ), hasConsented: consented, }, @@ -765,7 +777,7 @@ describe('cookie syncing', function() { .getInstance() .Consent.createConsentState() .setCCPAConsentState( - mParticle.getInstance().Consent.createCCPAConsent(ccpaPresent) + mParticle.getInstance().Consent.createCCPAConsent(ccpaPresent), ); const user = MockUser() as IMParticleUser; user.setConsentState(consentState); @@ -775,7 +787,7 @@ describe('cookie syncing', function() { expect(enabled).to.not.be.ok; }); - it("should perform a cookie sync if 'Do Not Forward' if CCPA is 'Present' is selected and user CCPA is not present", function() { + it("should perform a cookie sync if 'Do Not Forward' if CCPA is 'Present' is selected and user CCPA is not present", function () { const includeOnMatch = false; // 'Do Not Forward' chosen in UI, 'includeOnMatch' in config const consented = true; const ccpaPresent = false; @@ -787,7 +799,7 @@ describe('cookie syncing', function() { values: [ { consentPurpose: mParticle.generateHash( - '2' + 'data_sale_opt_out' + '2' + 'data_sale_opt_out', ), hasConsented: consented, }, @@ -798,7 +810,7 @@ describe('cookie syncing', function() { .getInstance() .Consent.createConsentState() .setCCPAConsentState( - mParticle.getInstance().Consent.createCCPAConsent(ccpaPresent) + mParticle.getInstance().Consent.createCCPAConsent(ccpaPresent), ); const user = MockUser() as IMParticleUser; user.setConsentState(consentState); @@ -808,7 +820,7 @@ describe('cookie syncing', function() { expect(enabled).to.be.ok; }); - it("should perform a cookie sync if 'Do Not Forward' if CCPA is 'Not Present' is selected and user CCPA is present", function() { + it("should perform a cookie sync if 'Do Not Forward' if CCPA is 'Not Present' is selected and user CCPA is present", function () { const includeOnMatch = false; // 'Do Not Forward' chosen in UI, 'includeOnMatch' in config const consented = false; const ccpaPresent = true; @@ -820,7 +832,7 @@ describe('cookie syncing', function() { values: [ { consentPurpose: mParticle.generateHash( - '2' + 'data_sale_opt_out' + '2' + 'data_sale_opt_out', ), hasConsented: consented, }, @@ -831,7 +843,7 @@ describe('cookie syncing', function() { .getInstance() .Consent.createConsentState() .setCCPAConsentState( - mParticle.getInstance().Consent.createCCPAConsent(ccpaPresent) + mParticle.getInstance().Consent.createCCPAConsent(ccpaPresent), ); const user = MockUser() as IMParticleUser; user.setConsentState(consentState); @@ -852,7 +864,7 @@ describe('cookie syncing', function() { values: [ { consentPurpose: mParticle.generateHash( - '1' + 'foo purpose 1' + '1' + 'foo purpose 1', ), hasConsented: consented, }, @@ -873,12 +885,10 @@ describe('cookie syncing', function() { .Consent.createConsentState() .addGDPRConsentState( 'foo purpose 1', - mParticle.getInstance().Consent.createGDPRConsent(false) + mParticle.getInstance().Consent.createGDPRConsent(false), ); - mParticle.Identity.getCurrentUser().setConsentState( - falseConsentState - ); + mParticle.Identity.getCurrentUser().setConsentState(falseConsentState); const noCookieSyncLS = mParticle .getInstance() ._Persistence.getLocalStorage(); @@ -889,12 +899,10 @@ describe('cookie syncing', function() { .Consent.createConsentState() .addGDPRConsentState( 'foo purpose 1', - mParticle.getInstance().Consent.createGDPRConsent(true) + mParticle.getInstance().Consent.createGDPRConsent(true), ); - mParticle.Identity.getCurrentUser().setConsentState( - trueConsentState - ); + mParticle.Identity.getCurrentUser().setConsentState(trueConsentState); const cookieSyncLS = mParticle .getInstance() @@ -916,7 +924,7 @@ describe('cookie syncing', function() { values: [ { consentPurpose: mParticle.generateHash( - '1' + 'foo purpose 1' + '1' + 'foo purpose 1', ), hasConsented: consented, }, @@ -936,12 +944,10 @@ describe('cookie syncing', function() { .Consent.createConsentState() .addGDPRConsentState( 'foo purpose 1', - mParticle.getInstance().Consent.createGDPRConsent(false) + mParticle.getInstance().Consent.createGDPRConsent(false), ); - mParticle.Identity.getCurrentUser().setConsentState( - falseConsentState - ); + mParticle.Identity.getCurrentUser().setConsentState(falseConsentState); let newLocalStorage = mParticle .getInstance() @@ -953,12 +959,10 @@ describe('cookie syncing', function() { .Consent.createConsentState() .addGDPRConsentState( 'foo purpose 1', - mParticle.getInstance().Consent.createGDPRConsent(true) + mParticle.getInstance().Consent.createGDPRConsent(true), ); - mParticle.Identity.getCurrentUser().setConsentState( - trueConsentState - ); + mParticle.Identity.getCurrentUser().setConsentState(trueConsentState); newLocalStorage = mParticle .getInstance() @@ -978,7 +982,7 @@ describe('cookie syncing', function() { values: [ { consentPurpose: mParticle.generateHash( - '2' + 'data_sale_opt_out' + '2' + 'data_sale_opt_out', ), hasConsented: consented, }, @@ -999,12 +1003,10 @@ describe('cookie syncing', function() { .Consent.createConsentState() .setCCPAConsentState( // false to show that it doesn't perform a cookie sync - mParticle.getInstance().Consent.createCCPAConsent(false) + mParticle.getInstance().Consent.createCCPAConsent(false), ); - mParticle.Identity.getCurrentUser().setConsentState( - falseConsentState - ); + mParticle.Identity.getCurrentUser().setConsentState(falseConsentState); const noCookieSyncLS = mParticle .getInstance() @@ -1016,12 +1018,10 @@ describe('cookie syncing', function() { .Consent.createConsentState() .setCCPAConsentState( // false to show that it doesn't perform a cookie sync - mParticle.getInstance().Consent.createCCPAConsent(true) + mParticle.getInstance().Consent.createCCPAConsent(true), ); - mParticle.Identity.getCurrentUser().setConsentState( - trueConsentState - ); + mParticle.Identity.getCurrentUser().setConsentState(trueConsentState); const cookieSyncLS = mParticle .getInstance() @@ -1043,7 +1043,7 @@ describe('cookie syncing', function() { values: [ { consentPurpose: mParticle.generateHash( - '2' + 'data_sale_opt_out' + '2' + 'data_sale_opt_out', ), hasConsented: consented, }, @@ -1062,12 +1062,10 @@ describe('cookie syncing', function() { .getInstance() .Consent.createConsentState() .setCCPAConsentState( - mParticle.getInstance().Consent.createCCPAConsent(false) + mParticle.getInstance().Consent.createCCPAConsent(false), ); - mParticle.Identity.getCurrentUser().setConsentState( - falseConsentState - ); + mParticle.Identity.getCurrentUser().setConsentState(falseConsentState); let newLocalStorage = mParticle .getInstance() @@ -1078,12 +1076,10 @@ describe('cookie syncing', function() { .getInstance() .Consent.createConsentState() .setCCPAConsentState( - mParticle.getInstance().Consent.createCCPAConsent(true) + mParticle.getInstance().Consent.createCCPAConsent(true), ); - mParticle.Identity.getCurrentUser().setConsentState( - trueConsentState - ); + mParticle.Identity.getCurrentUser().setConsentState(trueConsentState); newLocalStorage = mParticle .getInstance() @@ -1119,7 +1115,7 @@ describe('cookie syncing', function() { values: [ { consentPurpose: mParticle.generateHash( - '2' + 'data_sale_opt_out' + '2' + 'data_sale_opt_out', ), hasConsented: consented, }, @@ -1158,12 +1154,10 @@ describe('cookie syncing', function() { .getInstance() .Consent.createConsentState() .setCCPAConsentState( - mParticle.getInstance().Consent.createCCPAConsent(true) + mParticle.getInstance().Consent.createCCPAConsent(true), ); - mParticle.Identity.getCurrentUser().setConsentState( - trueConsentState - ); + mParticle.Identity.getCurrentUser().setConsentState(trueConsentState); const newLocalStorage = mParticle .getInstance() ._Persistence.getLocalStorage(); @@ -1172,4 +1166,4 @@ describe('cookie syncing', function() { newLocalStorage.testMPID.csd.should.have.property(2); newLocalStorage.testMPID.csd.should.have.property(1); }); -}); \ No newline at end of file +}); diff --git a/test/src/tests-core-sdk.js b/test/src/tests-core-sdk.js index b2a8e0531..ce795d1be 100644 --- a/test/src/tests-core-sdk.js +++ b/test/src/tests-core-sdk.js @@ -4,7 +4,14 @@ import Store from '../../src/store'; import Constants, { HTTP_ACCEPTED, HTTP_OK } from '../../src/constants'; import sinon from 'sinon'; import fetchMock from 'fetch-mock/esm/client'; -import { urls, apiKey, das, MPConfig, testMPID, workspaceCookieName } from './config/constants'; +import { + urls, + apiKey, + das, + MPConfig, + testMPID, + workspaceCookieName, +} from './config/constants'; const DefaultConfig = Constants.DefaultConfig, setLocalStorage = Utils.setLocalStorage, @@ -17,11 +24,11 @@ const { fetchMockSuccess, hasIdentifyReturned, hasIdentityCallInflightReturned, - hasConfigurationReturned + hasConfigurationReturned, } = Utils; -describe('core SDK', function() { - beforeEach(function() { +describe('core SDK', function () { + beforeEach(function () { fetchMock.post(urls.events, 200); fetchMockSuccess(urls.identify, { mpid: testMPID, @@ -30,27 +37,29 @@ describe('core SDK', function() { mParticle.init(apiKey, window.mParticle.config); }); - afterEach(function() { + afterEach(function () { mParticle._resetForTests(MPConfig); fetchMock.restore(); sinon.restore(); }); - it('starts new session', function(done) { - waitForCondition(hasIdentifyReturned) - .then(() => { - mParticle.startNewSession(); + it('starts new session', function (done) { + waitForCondition(hasIdentifyReturned).then(() => { + mParticle.startNewSession(); - const sessionStartEvent = findEventFromRequest(fetchMock.calls(), 'session_start'); + const sessionStartEvent = findEventFromRequest( + fetchMock.calls(), + 'session_start', + ); - sessionStartEvent.should.be.ok(); - sessionStartEvent.data.should.have.property('session_uuid'); + sessionStartEvent.should.be.ok(); + sessionStartEvent.data.should.have.property('session_uuid'); - done(); - }) + done(); + }); }); - it('sessionIds are all capital letters', function(done) { + it('sessionIds are all capital letters', function (done) { const lowercaseLetters = [ 'a', 'b', @@ -80,7 +89,7 @@ describe('core SDK', function() { ]; const sessionId = mParticle.sessionManager.getSession(); let lowercaseLetterExists; - sessionId.split('').forEach(function(letter) { + sessionId.split('').forEach(function (letter) { if (lowercaseLetters.indexOf(letter) > -1) { lowercaseLetterExists = true; } @@ -91,40 +100,53 @@ describe('core SDK', function() { done(); }); - it('ends existing session with an event that includes SessionLength', function(done) { - waitForCondition(hasIdentifyReturned) - .then(() => { + it('ends existing session with an event that includes SessionLength', function (done) { + waitForCondition(hasIdentifyReturned).then(() => { + mParticle.startNewSession(); + mParticle.endSession(); - mParticle.startNewSession(); - mParticle.endSession(); - - const sessionEndEvent = findEventFromRequest(fetchMock.calls(), 'session_end'); + const sessionEndEvent = findEventFromRequest( + fetchMock.calls(), + 'session_end', + ); - sessionEndEvent.should.be.ok(); + sessionEndEvent.should.be.ok(); - sessionEndEvent.data.should.have.property('session_duration_ms'); + sessionEndEvent.data.should.have.property('session_duration_ms'); - done(); - }) + done(); + }); }); - it('creates a new dateLastEventSent when logging an event, and retains the previous one when ending session', function(done) { - waitForCondition(hasIdentifyReturned) - .then(() => { - const clock = sinon.useFakeTimers(); - mParticle.logEvent('Test Event1'); - const testEvent1 = findEventFromRequest(fetchMock.calls(), 'Test Event1'); - clock.tick(100); + it('creates a new dateLastEventSent when logging an event, and retains the previous one when ending session', function (done) { + waitForCondition(hasIdentifyReturned).then(() => { + const clock = sinon.useFakeTimers(); + mParticle.logEvent('Test Event1'); + const testEvent1 = findEventFromRequest( + fetchMock.calls(), + 'Test Event1', + ); + clock.tick(100); - mParticle.logEvent('Test Event2'); - const testEvent2 = findEventFromRequest(fetchMock.calls(), 'Test Event2'); + mParticle.logEvent('Test Event2'); + const testEvent2 = findEventFromRequest( + fetchMock.calls(), + 'Test Event2', + ); - mParticle.endSession(); - const sessionEndEvent = findEventFromRequest(fetchMock.calls(), 'session_end'); - Should(testEvent1.data.timestamp_unixtime_ms).not.equal(testEvent2.data.timestamp_unixtime_ms); - Should(testEvent2.data.timestamp_unixtime_ms).equal(sessionEndEvent.data.timestamp_unixtime_ms); + mParticle.endSession(); + const sessionEndEvent = findEventFromRequest( + fetchMock.calls(), + 'session_end', + ); + Should(testEvent1.data.timestamp_unixtime_ms).not.equal( + testEvent2.data.timestamp_unixtime_ms, + ); + Should(testEvent2.data.timestamp_unixtime_ms).equal( + sessionEndEvent.data.timestamp_unixtime_ms, + ); - done(); + done(); }); }); @@ -133,7 +155,7 @@ describe('core SDK', function() { mParticle._resetForTests(MPConfig); - mParticle.ready(function() { + mParticle.ready(function () { readyFuncCalled = true; }); mParticle.init(apiKey, window.mParticle.config); @@ -142,18 +164,22 @@ describe('core SDK', function() { expect(readyFuncCalled).equal(true); }); - it('should set app version on the payload', function(done) { - waitForCondition(hasIdentifyReturned) - .then(() => { - - mParticle.setAppVersion('1.0'); + it('should set app version on the payload', function (done) { + waitForCondition(hasIdentifyReturned).then(() => { + mParticle.setAppVersion('1.0'); - window.mParticle.logEvent('Test Event', mParticle.EventType.Navigation); - const testEventBatch = findBatch(fetchMock.calls(), 'Test Event'); - testEventBatch.application_info.should.have.property('application_version', '1.0'); + window.mParticle.logEvent( + 'Test Event', + mParticle.EventType.Navigation, + ); + const testEventBatch = findBatch(fetchMock.calls(), 'Test Event'); + testEventBatch.application_info.should.have.property( + 'application_version', + '1.0', + ); - done(); - }) + done(); + }); }); it('should get app version', async () => { @@ -164,7 +190,7 @@ describe('core SDK', function() { expect(appVersion).to.equal('2.0'); }); - it('should get environment setting when set to `production`', function(done) { + it('should get environment setting when set to `production`', function (done) { mParticle._resetForTests(MPConfig); mParticle.init(apiKey, { ...window.mParticle.config, @@ -176,7 +202,7 @@ describe('core SDK', function() { done(); }); - it('should get environment setting when set to `development`', function(done) { + it('should get environment setting when set to `development`', function (done) { mParticle._resetForTests(MPConfig); mParticle.init(apiKey, { ...window.mParticle.config, @@ -188,9 +214,9 @@ describe('core SDK', function() { done(); }); - it('should get app version from config', function(done) { + it('should get app version from config', function (done) { mParticle._resetForTests(MPConfig); - window.mParticle.config.appName = "testAppName"; + window.mParticle.config.appName = 'testAppName'; mParticle.init(apiKey, window.mParticle.config); const appName = mParticle.getAppName(); @@ -200,213 +226,256 @@ describe('core SDK', function() { }); it('should send new appName via event payload', function (done) { - waitForCondition(hasIdentifyReturned) - .then(() => { - mParticle.config.flags = { - eventBatchingIntervalMillis: 0, - } + waitForCondition(hasIdentifyReturned).then(() => { + mParticle.config.flags = { + eventBatchingIntervalMillis: 0, + }; - mParticle.config.appName = 'newAppName'; + mParticle.config.appName = 'newAppName'; - mParticle.init(apiKey, mParticle.config); + mParticle.init(apiKey, mParticle.config); - waitForCondition(() => { - return ( - window.mParticle.getInstance()?._Store?.identityCallInFlight === false - ); - }) - .then(() => { - window.mParticle.logEvent('Test Event'); + waitForCondition(() => { + return ( + window.mParticle.getInstance()?._Store + ?.identityCallInFlight === false + ); + }).then(() => { + window.mParticle.logEvent('Test Event'); - const batch = JSON.parse(fetchMock.lastOptions().body); + const batch = JSON.parse(fetchMock.lastOptions().body); - batch.application_info.should.have.property('application_name', 'newAppName'); - - done(); - }) - }) + batch.application_info.should.have.property( + 'application_name', + 'newAppName', + ); + + done(); + }); + }); }); it('should allow app name to be changed via setAppName', function (done) { - waitForCondition(hasIdentifyReturned) - .then(() => { - mParticle._resetForTests(MPConfig); - - const newConfig = { ...window.mParticle.config, appName: 'OverrideTestName'}; - - mParticle.init(apiKey, newConfig); - waitForCondition(() => { - return ( - window.mParticle.getInstance()?._Store?.identityCallInFlight === false - ); - }) - .then(() => { - - const appName = mParticle.getAppName(); - appName.should.equal('OverrideTestName'); + waitForCondition(hasIdentifyReturned).then(() => { + mParticle._resetForTests(MPConfig); + const newConfig = { + ...window.mParticle.config, + appName: 'OverrideTestName', + }; - done(); - }) - }) - }) + mParticle.init(apiKey, newConfig); + waitForCondition(() => { + return ( + window.mParticle.getInstance()?._Store + ?.identityCallInFlight === false + ); + }).then(() => { + const appName = mParticle.getAppName(); + appName.should.equal('OverrideTestName'); + + done(); + }); + }); + }); it('should set Package Name on Batch Payload', function (done) { - waitForCondition(hasIdentifyReturned) - .then(() => { + waitForCondition(hasIdentifyReturned).then(() => { + mParticle.config.package = 'my-web-package'; + + mParticle.init(apiKey, mParticle.config); + waitForCondition(() => { + return ( + window.mParticle.getInstance()?._Store + ?.identityCallInFlight === false + ); + }).then(() => { + window.mParticle.logEvent('Test Event'); + + const batch = JSON.parse(fetchMock.lastOptions().body); + + batch.should.have.property('application_info'); + batch.application_info.should.have.property( + 'package', + 'my-web-package', + ); + done(); + }); + }); + }); - mParticle.config.package = 'my-web-package'; + it('should sanitize event attributes', function (done) { + waitForCondition(hasIdentifyReturned).then(() => { + mParticle.logEvent('sanitized event', 1, { + key1: 'value1', + mydate: new Date(), + ishouldberemoved: { + test: 'test', + }, + ishouldalsoberemoved: ['test'], + removeme: new Error(), + }); - mParticle.init(apiKey, mParticle.config); - waitForCondition(() => { - return ( - window.mParticle.getInstance()?._Store?.identityCallInFlight === false + const sanitizedEvent = findEventFromRequest( + fetchMock.calls(), + 'sanitized event', ); - }) - .then(() => { - - window.mParticle.logEvent('Test Event'); - - const batch = JSON.parse(fetchMock.lastOptions().body); - - batch.should.have.property('application_info'); - batch.application_info.should.have.property('package', 'my-web-package'); - done(); - }) - }) - }); - it('should sanitize event attributes', function(done) { - waitForCondition(hasIdentifyReturned) - .then(() => { - mParticle.logEvent('sanitized event', 1, { - key1: 'value1', - mydate: new Date(), - ishouldberemoved: { - test: 'test', - }, - ishouldalsoberemoved: ['test'], - removeme: new Error(), + sanitizedEvent.data.custom_attributes.should.have.property( + 'key1', + 'value1', + ); + sanitizedEvent.data.custom_attributes.should.have.property( + 'mydate', + ); + sanitizedEvent.data.custom_attributes.should.not.have.property( + 'ishouldberemoved', + ); + sanitizedEvent.data.custom_attributes.should.not.have.property( + 'ishouldalsoberemoved', + ); + sanitizedEvent.data.custom_attributes.should.not.have.property( + 'removeme', + ); }); - const sanitizedEvent = findEventFromRequest(fetchMock.calls(), 'sanitized event'); - - sanitizedEvent.data.custom_attributes.should.have.property('key1', 'value1'); - sanitizedEvent.data.custom_attributes.should.have.property('mydate'); - sanitizedEvent.data.custom_attributes.should.not.have.property('ishouldberemoved'); - sanitizedEvent.data.custom_attributes.should.not.have.property('ishouldalsoberemoved'); - sanitizedEvent.data.custom_attributes.should.not.have.property('removeme'); - }) - done(); }); - it('sanitizes attributes when attrs are provided', function(done) { - waitForCondition(hasIdentifyReturned) - .then(() => { - const attrs = { - valid: '123', - invalid: ['123', '345'], - }; - - const product = mParticle.eCommerce.createProduct( - 'name', - 'sku', - 100, - 1, - 'variant', - 'category', - 'brand', - 'position', - 'coupon', - attrs - ); - product.Attributes.should.not.have.property('invalid'); - product.Attributes.should.have.property('valid'); - - fetchMock.resetHistory(); - mParticle.eCommerce.logCheckout(1, 'visa', attrs); - const checkoutEvent = findEventFromRequest(fetchMock.calls(), 'checkout'); - - checkoutEvent.data.custom_attributes.should.not.have.property('invalid'); - checkoutEvent.data.custom_attributes.should.have.property('valid'); - - mParticle.eCommerce.logProductAction(mParticle.ProductActionType.AddToCart, product, attrs); - const addToCartEvent = findEventFromRequest(fetchMock.calls(), 'add_to_cart'); + it('sanitizes attributes when attrs are provided', function (done) { + waitForCondition(hasIdentifyReturned).then(() => { + const attrs = { + valid: '123', + invalid: ['123', '345'], + }; - addToCartEvent.data.custom_attributes.should.not.have.property('invalid'); - addToCartEvent.data.custom_attributes.should.have.property('valid'); + const product = mParticle.eCommerce.createProduct( + 'name', + 'sku', + 100, + 1, + 'variant', + 'category', + 'brand', + 'position', + 'coupon', + attrs, + ); + product.Attributes.should.not.have.property('invalid'); + product.Attributes.should.have.property('valid'); + + fetchMock.resetHistory(); + mParticle.eCommerce.logCheckout(1, 'visa', attrs); + const checkoutEvent = findEventFromRequest( + fetchMock.calls(), + 'checkout', + ); - const transactionAttributes = mParticle.eCommerce.createTransactionAttributes( - '12345', - 'test-affiliation', - 'coupon-code', - 44334, - 600, - 200 - ); + checkoutEvent.data.custom_attributes.should.not.have.property( + 'invalid', + ); + checkoutEvent.data.custom_attributes.should.have.property('valid'); - fetchMock.resetHistory(); + mParticle.eCommerce.logProductAction( + mParticle.ProductActionType.AddToCart, + product, + attrs, + ); + const addToCartEvent = findEventFromRequest( + fetchMock.calls(), + 'add_to_cart', + ); - mParticle.eCommerce.logPurchase( - transactionAttributes, - product, - false, - attrs - ); - const purchaseEvent = findEventFromRequest(fetchMock.calls(), 'purchase'); - purchaseEvent.data.custom_attributes.should.not.have.property('invalid'); - purchaseEvent.data.custom_attributes.should.have.property('valid'); - - const promotion = mParticle.eCommerce.createPromotion( - 'id', - 'creative', - 'name', - 'position' - ); + addToCartEvent.data.custom_attributes.should.not.have.property( + 'invalid', + ); + addToCartEvent.data.custom_attributes.should.have.property('valid'); + + const transactionAttributes = + mParticle.eCommerce.createTransactionAttributes( + '12345', + 'test-affiliation', + 'coupon-code', + 44334, + 600, + 200, + ); + + fetchMock.resetHistory(); + + mParticle.eCommerce.logPurchase( + transactionAttributes, + product, + false, + attrs, + ); + const purchaseEvent = findEventFromRequest( + fetchMock.calls(), + 'purchase', + ); + purchaseEvent.data.custom_attributes.should.not.have.property( + 'invalid', + ); + purchaseEvent.data.custom_attributes.should.have.property('valid'); - fetchMock.resetHistory(); + const promotion = mParticle.eCommerce.createPromotion( + 'id', + 'creative', + 'name', + 'position', + ); - mParticle.eCommerce.logPromotion(1, promotion, attrs); - const promotionViewEvent = findEventFromRequest(fetchMock.calls(), 'view'); - promotionViewEvent.data.custom_attributes.should.not.have.property('invalid'); - promotionViewEvent.data.custom_attributes.should.have.property('valid'); + fetchMock.resetHistory(); - fetchMock.resetHistory(); + mParticle.eCommerce.logPromotion(1, promotion, attrs); + const promotionViewEvent = findEventFromRequest( + fetchMock.calls(), + 'view', + ); + promotionViewEvent.data.custom_attributes.should.not.have.property( + 'invalid', + ); + promotionViewEvent.data.custom_attributes.should.have.property( + 'valid', + ); - mParticle.eCommerce.logRefund( - transactionAttributes, - product, - false, - attrs - ); - const refundEvent = findEventFromRequest(fetchMock.calls(), 'refund'); + fetchMock.resetHistory(); - refundEvent.data.custom_attributes.should.not.have.property('invalid'); - refundEvent.data.custom_attributes.should.have.property('valid'); + mParticle.eCommerce.logRefund( + transactionAttributes, + product, + false, + attrs, + ); + const refundEvent = findEventFromRequest( + fetchMock.calls(), + 'refund', + ); - done(); - }) + refundEvent.data.custom_attributes.should.not.have.property( + 'invalid', + ); + refundEvent.data.custom_attributes.should.have.property('valid'); + done(); + }); }); - it('should not generate a new device ID if a deviceId exists in localStorage', function(done) { - waitForCondition(hasIdentifyReturned) - .then(() => { - - mParticle._resetForTests(MPConfig); + it('should not generate a new device ID if a deviceId exists in localStorage', function (done) { + waitForCondition(hasIdentifyReturned).then(() => { + mParticle._resetForTests(MPConfig); - setLocalStorage(); - mParticle.init(apiKey, window.mParticle.config); + setLocalStorage(); + mParticle.init(apiKey, window.mParticle.config); - const deviceId = mParticle.getDeviceId(); + const deviceId = mParticle.getDeviceId(); - deviceId.should.equal(das); - done(); - }) + deviceId.should.equal(das); + done(); + }); }); - it('should return the deviceId when requested', function(done) { + it('should return the deviceId when requested', function (done) { const deviceId = mParticle.getDeviceId(); Should(deviceId).be.ok(); @@ -415,14 +484,16 @@ describe('core SDK', function() { done(); }); - it('will create a cgid when no previous cgid exists after initializing storage, and no sid', function(done) { + it('will create a cgid when no previous cgid exists after initializing storage, and no sid', function (done) { mParticle._resetForTests(MPConfig); mParticle.getInstance()._Store.storageName = Utils.workspaceCookieName; mParticle.getInstance()._Persistence.initializeStorage(); mParticle.getInstance()._Persistence.update(); - const cookieData = mParticle.getInstance()._Persistence.getLocalStorage(); + const cookieData = mParticle + .getInstance() + ._Persistence.getLocalStorage(); cookieData.gs.should.have.properties(['cgid']); cookieData.gs.should.not.have.property('sid'); @@ -430,254 +501,330 @@ describe('core SDK', function() { done(); }); - it('creates a new session when elapsed time between actions is greater than session timeout', function(done) { - waitForCondition(hasIdentifyReturned) - .then(() => { - mParticle._resetForTests(MPConfig); - mParticle.config.sessionTimeout = 1; - mParticle.init(apiKey, window.mParticle.config); - waitForCondition(() => { - return ( - window.mParticle.getInstance()?._Store?.identityCallInFlight === false - ); - }) - .then(() => { - const clock = sinon.useFakeTimers(); - clock.tick(100); - mParticle.logEvent('Test Event'); - const testEvent = findEventFromRequest(fetchMock.calls(), 'Test Event'); - - clock.tick(70000); - - mParticle.logEvent('Test Event2'); - const testEvent2 = findEventFromRequest(fetchMock.calls(), 'Test Event2'); - testEvent.data.session_uuid.should.not.equal(testEvent2.data.session_uuid); - mParticle.getInstance()._SessionManager.clearSessionTimeout(); clock.restore(); - - done(); - }) - }) + it('creates a new session when elapsed time between actions is greater than session timeout', function (done) { + waitForCondition(hasIdentifyReturned).then(() => { + mParticle._resetForTests(MPConfig); + mParticle.config.sessionTimeout = 1; + mParticle.init(apiKey, window.mParticle.config); + waitForCondition(() => { + return ( + window.mParticle.getInstance()?._Store + ?.identityCallInFlight === false + ); + }).then(() => { + const clock = sinon.useFakeTimers(); + clock.tick(100); + mParticle.logEvent('Test Event'); + const testEvent = findEventFromRequest( + fetchMock.calls(), + 'Test Event', + ); + + clock.tick(70000); + + mParticle.logEvent('Test Event2'); + const testEvent2 = findEventFromRequest( + fetchMock.calls(), + 'Test Event2', + ); + testEvent.data.session_uuid.should.not.equal( + testEvent2.data.session_uuid, + ); + mParticle.getInstance()._SessionManager.clearSessionTimeout(); + clock.restore(); + + done(); + }); + }); }); - it('should end session when last event sent is outside of sessionTimeout', function(done) { - waitForCondition(hasIdentifyReturned) - .then(() => { - mParticle._resetForTests(MPConfig); - mParticle.config.sessionTimeout = 1; - mParticle.init(apiKey, window.mParticle.config); - waitForCondition(() => { - return ( - window.mParticle.getInstance()?._Store?.identityCallInFlight === false - ); - }) - .then(() => { - const clock = sinon.useFakeTimers(); - clock.tick(100); - mParticle.logEvent('Test Event'); - - clock.tick(10000); - mParticle.logEvent('Test Event2'); - - clock.tick(120000); - mParticle.logEvent('Test Event3'); - - clock.tick(150000); - - const testEvent = findEventFromRequest(fetchMock.calls(), 'Test Event'); - const testEvent2 = findEventFromRequest(fetchMock.calls(), 'Test Event2'); - const testEvent3 = findEventFromRequest(fetchMock.calls(), 'Test Event3'); - - testEvent2.data.session_uuid.should.equal(testEvent.data.session_uuid); - testEvent3.data.session_uuid.should.not.equal(testEvent.data.session_uuid); - clock.restore(); - done(); - }) - }) + it('should end session when last event sent is outside of sessionTimeout', function (done) { + waitForCondition(hasIdentifyReturned).then(() => { + mParticle._resetForTests(MPConfig); + mParticle.config.sessionTimeout = 1; + mParticle.init(apiKey, window.mParticle.config); + waitForCondition(() => { + return ( + window.mParticle.getInstance()?._Store + ?.identityCallInFlight === false + ); + }).then(() => { + const clock = sinon.useFakeTimers(); + clock.tick(100); + mParticle.logEvent('Test Event'); + + clock.tick(10000); + mParticle.logEvent('Test Event2'); + + clock.tick(120000); + mParticle.logEvent('Test Event3'); + + clock.tick(150000); + + const testEvent = findEventFromRequest( + fetchMock.calls(), + 'Test Event', + ); + const testEvent2 = findEventFromRequest( + fetchMock.calls(), + 'Test Event2', + ); + const testEvent3 = findEventFromRequest( + fetchMock.calls(), + 'Test Event3', + ); + + testEvent2.data.session_uuid.should.equal( + testEvent.data.session_uuid, + ); + testEvent3.data.session_uuid.should.not.equal( + testEvent.data.session_uuid, + ); + clock.restore(); + done(); + }); + }); }); - it('should not end session when end session is called within sessionTimeout timeframe', function(done) { + it('should not end session when end session is called within sessionTimeout timeframe', function (done) { // This test mimics if another tab is open and events are sent, but previous tab's sessionTimeout is still ongoing - waitForCondition(hasIdentifyReturned) - .then(() => { - mParticle._resetForTests(MPConfig); - mParticle.config.sessionTimeout = 1; - mParticle.init(apiKey, window.mParticle.config); - waitForCondition(() => { - return ( - window.mParticle.getInstance()?._Store?.identityCallInFlight === false - ); - }) - .then(() => { - const clock = sinon.useFakeTimers(); - - fetchMock.resetHistory(); - - clock.tick(100); - mParticle.logEvent('Test Event'); - - // This clock tick initiates a session end event that is successful - clock.tick(70000); - - let sessionEndEvent = findEventFromRequest(fetchMock.calls(), 'session_end'); - Should(sessionEndEvent).be.ok(); - - fetchMock.resetHistory(); - clock.tick(100); - - mParticle.logEvent('Test Event2'); - - const sid = mParticle.getInstance()._Persistence.getLocalStorage().gs.sid; - - const new_Persistence = { - gs: { - sid: sid, - ie: 1, - les: 120000, - }, - }; - setLocalStorage(workspaceCookieName, new_Persistence); - // // This clock tick initiates a session end event that is not successful - clock.tick(70000); - sessionEndEvent = findEventFromRequest(fetchMock.calls(), 'session_end'); - - Should(sessionEndEvent).not.be.ok(); - const testEvent2 = findEventFromRequest(fetchMock.calls(), 'Test Event2'); - - mParticle.logEvent('Test Event3'); - - const testEvent3 = findEventFromRequest(fetchMock.calls(), 'Test Event3'); - testEvent3.data.session_uuid.should.equal(testEvent2.data.session_uuid); - - clock.restore(); - done(); - }) - }) + waitForCondition(hasIdentifyReturned).then(() => { + mParticle._resetForTests(MPConfig); + mParticle.config.sessionTimeout = 1; + mParticle.init(apiKey, window.mParticle.config); + waitForCondition(() => { + return ( + window.mParticle.getInstance()?._Store + ?.identityCallInFlight === false + ); + }).then(() => { + const clock = sinon.useFakeTimers(); + + fetchMock.resetHistory(); + + clock.tick(100); + mParticle.logEvent('Test Event'); + + // This clock tick initiates a session end event that is successful + clock.tick(70000); + + let sessionEndEvent = findEventFromRequest( + fetchMock.calls(), + 'session_end', + ); + Should(sessionEndEvent).be.ok(); + + fetchMock.resetHistory(); + clock.tick(100); + + mParticle.logEvent('Test Event2'); + + const sid = mParticle + .getInstance() + ._Persistence.getLocalStorage().gs.sid; + + const new_Persistence = { + gs: { + sid: sid, + ie: 1, + les: 120000, + }, + }; + setLocalStorage(workspaceCookieName, new_Persistence); + // // This clock tick initiates a session end event that is not successful + clock.tick(70000); + sessionEndEvent = findEventFromRequest( + fetchMock.calls(), + 'session_end', + ); + + Should(sessionEndEvent).not.be.ok(); + const testEvent2 = findEventFromRequest( + fetchMock.calls(), + 'Test Event2', + ); + + mParticle.logEvent('Test Event3'); + + const testEvent3 = findEventFromRequest( + fetchMock.calls(), + 'Test Event3', + ); + testEvent3.data.session_uuid.should.equal( + testEvent2.data.session_uuid, + ); + + clock.restore(); + done(); + }); + }); }); - it('should set the sessionId from memory on the payload', function(done) { - waitForCondition(hasIdentifyReturned) - .then(() => { - mParticle.logEvent('Test Event'); - const testEvent = findEventFromRequest(fetchMock.calls(), 'Test Event'); + it('should set the sessionId from memory on the payload', function (done) { + waitForCondition(hasIdentifyReturned).then(() => { + mParticle.logEvent('Test Event'); + const testEvent = findEventFromRequest( + fetchMock.calls(), + 'Test Event', + ); - const sessionId = mParticle.getInstance()._SessionManager.getSession(); + const sessionId = mParticle + .getInstance() + ._SessionManager.getSession(); - testEvent.data.session_uuid.should.equal(sessionId); + testEvent.data.session_uuid.should.equal(sessionId); - done(); - }) + done(); + }); }); - it('should set session start date in dto', function(done) { - waitForCondition(hasIdentifyReturned) - .then(() => { - mParticle.logEvent('Test Event'); + it('should set session start date in dto', function (done) { + waitForCondition(hasIdentifyReturned).then(() => { + mParticle.logEvent('Test Event'); - const testEvent = findEventFromRequest(fetchMock.calls(), 'Test Event'); + const testEvent = findEventFromRequest( + fetchMock.calls(), + 'Test Event', + ); - testEvent.data.session_start_unixtime_ms.should.be.above(0); + testEvent.data.session_start_unixtime_ms.should.be.above(0); - done(); + done(); }); }); - it('should update session start date when manually ending session then starting a new one', function(done) { - waitForCondition(hasIdentifyReturned) - .then(() => { - mParticle.logEvent('Test Event'); - - const testEvent = findEventFromRequest(fetchMock.calls(), 'Test Event'); - const testEventSessionStartTime = testEvent.data.session_start_unixtime_ms; - - mParticle.endSession(); - - const sessionEndEvent = findEventFromRequest(fetchMock.calls(), 'session_end'); - const sessionEndEventSessionStartDate = sessionEndEvent.data.session_start_unixtime_ms; - sessionEndEventSessionStartDate.should.equal(testEventSessionStartTime); - - mParticle.logEvent('Test Event2'); - - const testEvent2 = findEventFromRequest(fetchMock.calls(), 'Test Event2'); - - const testEvent2SessionStartDate = testEvent2.data.session_start_unixtime_ms; - testEvent2SessionStartDate.should.be.above(sessionEndEventSessionStartDate); + it('should update session start date when manually ending session then starting a new one', function (done) { + waitForCondition(hasIdentifyReturned).then(() => { + mParticle.logEvent('Test Event'); - done(); - }) - }); + const testEvent = findEventFromRequest( + fetchMock.calls(), + 'Test Event', + ); + const testEventSessionStartTime = + testEvent.data.session_start_unixtime_ms; - it('should update session start date when session times out, then start a new one', function(done) { - waitForCondition(hasIdentifyReturned) - .then(() => { - mParticle._resetForTests(MPConfig); - mParticle.config.sessionTimeout = 1; + mParticle.endSession(); - mParticle.init(apiKey, mParticle.config); - waitForCondition(() => { - return ( - window.mParticle.getInstance()?._Store?.identityCallInFlight === false + const sessionEndEvent = findEventFromRequest( + fetchMock.calls(), + 'session_end', + ); + const sessionEndEventSessionStartDate = + sessionEndEvent.data.session_start_unixtime_ms; + sessionEndEventSessionStartDate.should.equal( + testEventSessionStartTime, ); - }) - .then(() => { - const clock = sinon.useFakeTimers(); - clock.tick(10); - - mParticle.logEvent('Test Event'); - const testEvent = findEventFromRequest(fetchMock.calls(), 'Test Event'); - const testEventSessionStartDate = testEvent.data.session_start_unixtime_ms; - // trigger session timeout which ends session automatically - clock.tick(60000); - // note to self - session end event not being triggered, could be the same bug - const sessionEndEvent = findEventFromRequest(fetchMock.calls(), 'session_end'); - const sessionEndEventSessionStartDate = sessionEndEvent.data.session_start_unixtime_ms; - sessionEndEventSessionStartDate.should.equal(testEventSessionStartDate); + mParticle.logEvent('Test Event2'); - clock.restore(); - mParticle.logEvent('Test Event2'); - const testEvent2 = findEventFromRequest(fetchMock.calls(), 'Test Event2'); + const testEvent2 = findEventFromRequest( + fetchMock.calls(), + 'Test Event2', + ); - const testEvent2SessionStartDate = testEvent2.data.session_start_unixtime_ms; - testEvent2SessionStartDate.should.be.above(sessionEndEventSessionStartDate); + const testEvent2SessionStartDate = + testEvent2.data.session_start_unixtime_ms; + testEvent2SessionStartDate.should.be.above( + sessionEndEventSessionStartDate, + ); - done(); - }) - }) + done(); + }); }); - it('should load SDK with the included api on init and not send events to previous apikey in persistence', function(done) { - waitForCondition(hasIdentifyReturned) - .then(() => { - mParticle.logEvent('Test Event1'); - - const testEvent1URL = findRequestURL(fetchMock.calls(), 'Test Event1'); - testEvent1URL.should.equal(urls.events); + it('should update session start date when session times out, then start a new one', function (done) { + waitForCondition(hasIdentifyReturned).then(() => { + mParticle._resetForTests(MPConfig); + mParticle.config.sessionTimeout = 1; + + mParticle.init(apiKey, mParticle.config); + waitForCondition(() => { + return ( + window.mParticle.getInstance()?._Store + ?.identityCallInFlight === false + ); + }).then(() => { + const clock = sinon.useFakeTimers(); + clock.tick(10); + + mParticle.logEvent('Test Event'); + const testEvent = findEventFromRequest( + fetchMock.calls(), + 'Test Event', + ); + const testEventSessionStartDate = + testEvent.data.session_start_unixtime_ms; + + // trigger session timeout which ends session automatically + clock.tick(60000); + // note to self - session end event not being triggered, could be the same bug + const sessionEndEvent = findEventFromRequest( + fetchMock.calls(), + 'session_end', + ); + const sessionEndEventSessionStartDate = + sessionEndEvent.data.session_start_unixtime_ms; + sessionEndEventSessionStartDate.should.equal( + testEventSessionStartDate, + ); + + clock.restore(); + mParticle.logEvent('Test Event2'); + const testEvent2 = findEventFromRequest( + fetchMock.calls(), + 'Test Event2', + ); + + const testEvent2SessionStartDate = + testEvent2.data.session_start_unixtime_ms; + testEvent2SessionStartDate.should.be.above( + sessionEndEventSessionStartDate, + ); + + done(); + }); + }); + }); - fetchMock.post( - 'https://jssdks.mparticle.com/v3/JS/new-api-key/events', - 200 - ); + it('should load SDK with the included api on init and not send events to previous apikey in persistence', function (done) { + waitForCondition(hasIdentifyReturned).then(() => { + mParticle.logEvent('Test Event1'); - mParticle.init('new-api-key', window.mParticle.config); - waitForCondition(() => { - return ( - window.mParticle.getInstance()?._Store?.identityCallInFlight === false + const testEvent1URL = findRequestURL( + fetchMock.calls(), + 'Test Event1', ); - }) - .then(() => { - mParticle.logEvent('Test Event2'); + testEvent1URL.should.equal(urls.events); - const testEvent2URL = findRequestURL(fetchMock.calls(), 'Test Event2'); - testEvent2URL.should.equal( - 'https://jssdks.mparticle.com/v3/JS/new-api-key/events' - ); + fetchMock.post( + 'https://jssdks.mparticle.com/v3/JS/new-api-key/events', + 200, + ); - done(); - }); + mParticle.init('new-api-key', window.mParticle.config); + waitForCondition(() => { + return ( + window.mParticle.getInstance()?._Store + ?.identityCallInFlight === false + ); + }).then(() => { + mParticle.logEvent('Test Event2'); + + const testEvent2URL = findRequestURL( + fetchMock.calls(), + 'Test Event2', + ); + testEvent2URL.should.equal( + 'https://jssdks.mparticle.com/v3/JS/new-api-key/events', + ); + + done(); + }); }); }); - it('should have default options as well as configured options on configuration object, overwriting when appropriate', function(done) { + it('should have default options as well as configured options on configuration object, overwriting when appropriate', function (done) { const defaults = new Store({}, mParticle.getInstance(), apiKey); // all items here should be the default values for (const key in DefaultConfig) { @@ -698,7 +845,7 @@ describe('core SDK', function() { customerid: 'test', }, }, - identityCallback: function() { + identityCallback: function () { return 'identityCallback'; }, appVersion: 'v2.0.0', @@ -751,10 +898,10 @@ describe('core SDK', function() { mp.SDKConfig.maxCookieSize.should.equal(config.maxCookieSize); mp.SDKConfig.appName.should.equal(config.appName); mp.SDKConfig.integrationDelayTimeout.should.equal( - config.integrationDelayTimeout + config.integrationDelayTimeout, ); JSON.stringify(mp.SDKConfig.identifyRequest).should.equal( - JSON.stringify(config.identifyRequest) + JSON.stringify(config.identifyRequest), ); mp.SDKConfig.identityCallback().should.equal(config.identityCallback()); mp.SDKConfig.appVersion.should.equal(config.appVersion); @@ -763,10 +910,10 @@ describe('core SDK', function() { mp.SDKConfig.customFlags.should.equal(config.customFlags); mp.SDKConfig.workspaceToken.should.equal(config.workspaceToken); mp.SDKConfig.requiredWebviewBridgeName.should.equal( - config.requiredWebviewBridgeName + config.requiredWebviewBridgeName, ); mp.SDKConfig.minWebviewBridgeVersion.should.equal( - config.minWebviewBridgeVersion + config.minWebviewBridgeVersion, ); mp.SDKConfig.aliasMaxWindow.should.equal(config.aliasMaxWindow); @@ -775,122 +922,120 @@ describe('core SDK', function() { done(); }); - it('should use custom loggers when provided', function(done) { - waitForCondition(hasIdentifyReturned) - .then(() => { - mParticle.config.logLevel = 'verbose'; - let errorMessage; - let warnMessage; - let infoMessage; - - mParticle.config.logger = { - error: function(msg) { - errorMessage = msg; - }, - warning: function(msg) { - warnMessage = msg; - }, - verbose: function(msg) { - infoMessage = msg; - }, - }; + it('should use custom loggers when provided', function (done) { + waitForCondition(hasIdentifyReturned).then(() => { + mParticle.config.logLevel = 'verbose'; + let errorMessage; + let warnMessage; + let infoMessage; - mParticle.init(apiKey, window.mParticle.config); - waitForCondition(() => { - return ( - window.mParticle.getInstance()?._Store?.identityCallInFlight === false - ); - }) - .then(() => { - infoMessage.should.equal( - 'Batch count: 1' - ); - - mParticle.eCommerce.createProduct(); - errorMessage.should.equal('Name is required when creating a product'); - - mParticle.startTrackingLocation(); - warnMessage.should.equal( - 'Warning: Location tracking is triggered, but not including a callback into the `startTrackingLocation` may result in events logged too quickly and not being associated with a location.' - ); + mParticle.config.logger = { + error: function (msg) { + errorMessage = msg; + }, + warning: function (msg) { + warnMessage = msg; + }, + verbose: function (msg) { + infoMessage = msg; + }, + }; - done(); - }) - }) + mParticle.init(apiKey, window.mParticle.config); + waitForCondition(() => { + return ( + window.mParticle.getInstance()?._Store + ?.identityCallInFlight === false + ); + }).then(() => { + infoMessage.should.equal('Batch count: 1'); + + mParticle.eCommerce.createProduct(); + errorMessage.should.equal( + 'Name is required when creating a product', + ); + + mParticle.startTrackingLocation(); + warnMessage.should.equal( + 'Warning: Location tracking is triggered, but not including a callback into the `startTrackingLocation` may result in events logged too quickly and not being associated with a location.', + ); + + done(); + }); + }); }); - it('should be able to change logLevel on the fly, postuse custom loggers when provided', function(done) { + it('should be able to change logLevel on the fly, postuse custom loggers when provided', function (done) { const infoMessages = []; mParticle.config.logger = { - verbose: function(msg) { + verbose: function (msg) { infoMessages.push(msg); }, }; mParticle.init(apiKey, window.mParticle.config); - waitForCondition(hasIdentifyReturned) - .then(() => { + waitForCondition(hasIdentifyReturned).then(() => { + infoMessages.length.should.equal(0); - infoMessages.length.should.equal(0); + mParticle.setLogLevel('verbose'); - mParticle.setLogLevel('verbose'); + mParticle.logEvent('hi'); + infoMessages[0].should.equal('Starting to log event: hi'); - mParticle.logEvent('hi'); - infoMessages[0].should.equal('Starting to log event: hi'); - - done(); - }) + done(); + }); }); - it("should not log anything to console when logLevel = 'none'", function(done) { - waitForCondition(hasIdentifyReturned) - .then(() => { - const infoMessages = []; - const warnMessages = []; - const errorMessages = []; - - mParticle.config.logger = { - error: function(msg) { - errorMessages.push(msg); - }, - warning: function(msg) { - warnMessages.push(msg); - }, - verbose: function(msg) { - infoMessages.push(msg); - }, - }; - - mParticle.init(apiKey, window.mParticle.config); - waitForCondition(() => { - return ( - window.mParticle.getInstance()?._Store?.identityCallInFlight === false - ); - }) - .then(() => { - infoMessages.length.should.equal(0); - warnMessages.length.should.equal(0); - errorMessages.length.should.equal(0); + it("should not log anything to console when logLevel = 'none'", function (done) { + waitForCondition(hasIdentifyReturned).then(() => { + const infoMessages = []; + const warnMessages = []; + const errorMessages = []; - mParticle.setLogLevel('none'); - - mParticle.logEvent('Test Event'); - - infoMessages.length.should.equal(0); - warnMessages.length.should.equal(0); - errorMessages.length.should.equal(0); - - const testEvent = findEventFromRequest(fetchMock.calls(), 'Test Event'); - Should(testEvent).be.ok(); - - done(); - }) - }) + mParticle.config.logger = { + error: function (msg) { + errorMessages.push(msg); + }, + warning: function (msg) { + warnMessages.push(msg); + }, + verbose: function (msg) { + infoMessages.push(msg); + }, + }; + mParticle.init(apiKey, window.mParticle.config); + waitForCondition(() => { + return ( + window.mParticle.getInstance()?._Store + ?.identityCallInFlight === false + ); + }).then(() => { + infoMessages.length.should.equal(0); + warnMessages.length.should.equal(0); + errorMessages.length.should.equal(0); + + mParticle.setLogLevel('none'); + + mParticle.logEvent('Test Event'); + + infoMessages.length.should.equal(0); + warnMessages.length.should.equal(0); + errorMessages.length.should.equal(0); + + const testEvent = findEventFromRequest( + fetchMock.calls(), + 'Test Event', + ); + Should(testEvent).be.ok(); + + done(); + }); + }); }); - it('should not error when logger custom loggers when provided', function(done) { + it('should not error when logger custom loggers when provided', function (done) { /* Previously the Store was initialized before Logger, and since Store contains Logger, and it would throw. This no longer throws because Store takes the Logger as an argument, which is now initialized first. */ @@ -900,7 +1045,7 @@ describe('core SDK', function() { let warnMessage; mParticle.config.logger = { - warning: function(msg) { + warning: function (msg) { warnMessage = msg; }, }; @@ -908,96 +1053,155 @@ describe('core SDK', function() { mParticle.init(apiKey, window.mParticle.config); warnMessage.should.equal( - 'You should have a workspaceToken on your config object for security purposes.' + 'You should have a workspaceToken on your config object for security purposes.', ); done(); }); - it('should use default urls if no custom urls are set in config object', function(done) { + it('should use default urls if no custom urls are set in config object', function (done) { mParticle._resetForTests(MPConfig); mParticle.init(apiKey, window.mParticle.config); - mParticle.getInstance()._Store.SDKConfig.v1SecureServiceUrl.should.equal(Constants.DefaultBaseUrls.v1SecureServiceUrl); - mParticle.getInstance()._Store.SDKConfig.v2SecureServiceUrl.should.equal(Constants.DefaultBaseUrls.v2SecureServiceUrl) - mParticle.getInstance()._Store.SDKConfig.v3SecureServiceUrl.should.equal(Constants.DefaultBaseUrls.v3SecureServiceUrl) - mParticle.getInstance()._Store.SDKConfig.configUrl.should.equal(Constants.DefaultBaseUrls.configUrl) - mParticle.getInstance()._Store.SDKConfig.identityUrl.should.equal(Constants.DefaultBaseUrls.identityUrl) - mParticle.getInstance()._Store.SDKConfig.aliasUrl.should.equal(Constants.DefaultBaseUrls.aliasUrl) + mParticle + .getInstance() + ._Store.SDKConfig.v1SecureServiceUrl.should.equal( + Constants.DefaultBaseUrls.v1SecureServiceUrl, + ); + mParticle + .getInstance() + ._Store.SDKConfig.v2SecureServiceUrl.should.equal( + Constants.DefaultBaseUrls.v2SecureServiceUrl, + ); + mParticle + .getInstance() + ._Store.SDKConfig.v3SecureServiceUrl.should.equal( + Constants.DefaultBaseUrls.v3SecureServiceUrl, + ); + mParticle + .getInstance() + ._Store.SDKConfig.configUrl.should.equal( + Constants.DefaultBaseUrls.configUrl, + ); + mParticle + .getInstance() + ._Store.SDKConfig.identityUrl.should.equal( + Constants.DefaultBaseUrls.identityUrl, + ); + mParticle + .getInstance() + ._Store.SDKConfig.aliasUrl.should.equal( + Constants.DefaultBaseUrls.aliasUrl, + ); done(); }); - it('should have default urls if no custom urls are set in config object, but use custom urls when they are set', function(done) { - waitForCondition(hasIdentifyReturned) - .then(() => { - window.mParticle.config.v3SecureServiceUrl = - 'testtesttest-custom-v3secureserviceurl/v3/JS/'; - window.mParticle.config.configUrl = - 'foo-custom-configUrl/v2/JS/'; - window.mParticle.config.identityUrl = 'custom-identityurl/'; - window.mParticle.config.aliasUrl = 'custom-alias/'; - - fetchMock.post('https://testtesttest-custom-v3secureserviceurl/v3/JS/test_key/events', HTTP_OK) - - mParticle.init(apiKey, window.mParticle.config); - waitForCondition(() => { - return ( - window.mParticle.getInstance()?._Store?.identityCallInFlight === false + it('should have default urls if no custom urls are set in config object, but use custom urls when they are set', function (done) { + waitForCondition(hasIdentifyReturned).then(() => { + window.mParticle.config.v3SecureServiceUrl = + 'testtesttest-custom-v3secureserviceurl/v3/JS/'; + window.mParticle.config.configUrl = 'foo-custom-configUrl/v2/JS/'; + window.mParticle.config.identityUrl = 'custom-identityurl/'; + window.mParticle.config.aliasUrl = 'custom-alias/'; + + fetchMock.post( + 'https://testtesttest-custom-v3secureserviceurl/v3/JS/test_key/events', + HTTP_OK, ); - }) - .then(() => { - mParticle.getInstance()._Store.SDKConfig.v3SecureServiceUrl.should.equal(window.mParticle.config.v3SecureServiceUrl) - mParticle.getInstance()._Store.SDKConfig.configUrl.should.equal(window.mParticle.config.configUrl) - mParticle.getInstance()._Store.SDKConfig.identityUrl.should.equal(window.mParticle.config.identityUrl) - mParticle.getInstance()._Store.SDKConfig.aliasUrl.should.equal(window.mParticle.config.aliasUrl) - - // test events endpoint - mParticle.logEvent('Test Event'); - - const testEventURL = findRequestURL(fetchMock.calls(), 'Test Event'); - testEventURL.should.equal( - 'https://' + - window.mParticle.config.v3SecureServiceUrl + - 'test_key/events' - ); - // test Identity endpoint - fetchMock.resetHistory(); - fetchMockSuccess('https://custom-identityurl/login', { - mpid: 'loginMPID', is_logged_in: true - }); - mParticle.Identity.login({ userIdentities: { customerid: 'test1' } }); - - waitForCondition(() => { - return ( - mParticle.Identity.getCurrentUser()?.getMPID() === 'loginMPID' - ); - }) - .then(() => { - fetchMock.calls()[0][0].should.equal('https://' + window.mParticle.config.identityUrl + 'login'); - // test alias endpoint - // https://go.mparticle.com/work/SQDSDKS-6751 - fetchMock.post('https://custom-alias/test_key/Alias', HTTP_ACCEPTED); - - mParticle.Identity.aliasUsers({ - destinationMpid: 1, - sourceMpid: 2, - startTime: 3, - endTime: 4, - }, aliasCallback); - - function aliasCallback() { - const lastFetchCallUrl = fetchMock.lastCall()[0]; - const expectedUrl = `https://${window.mParticle.config.aliasUrl}test_key/Alias`; - - lastFetchCallUrl.should.equal(expectedUrl); - - done(); - } - }) - }); + mParticle.init(apiKey, window.mParticle.config); + waitForCondition(() => { + return ( + window.mParticle.getInstance()?._Store + ?.identityCallInFlight === false + ); + }).then(() => { + mParticle + .getInstance() + ._Store.SDKConfig.v3SecureServiceUrl.should.equal( + window.mParticle.config.v3SecureServiceUrl, + ); + mParticle + .getInstance() + ._Store.SDKConfig.configUrl.should.equal( + window.mParticle.config.configUrl, + ); + mParticle + .getInstance() + ._Store.SDKConfig.identityUrl.should.equal( + window.mParticle.config.identityUrl, + ); + mParticle + .getInstance() + ._Store.SDKConfig.aliasUrl.should.equal( + window.mParticle.config.aliasUrl, + ); + + // test events endpoint + mParticle.logEvent('Test Event'); + + const testEventURL = findRequestURL( + fetchMock.calls(), + 'Test Event', + ); + testEventURL.should.equal( + 'https://' + + window.mParticle.config.v3SecureServiceUrl + + 'test_key/events', + ); + + // test Identity endpoint + fetchMock.resetHistory(); + fetchMockSuccess('https://custom-identityurl/login', { + mpid: 'loginMPID', + is_logged_in: true, + }); + mParticle.Identity.login({ + userIdentities: { customerid: 'test1' }, + }); + + waitForCondition(() => { + return ( + mParticle.Identity.getCurrentUser()?.getMPID() === + 'loginMPID' + ); + }).then(() => { + fetchMock + .calls()[0][0] + .should.equal( + 'https://' + + window.mParticle.config.identityUrl + + 'login', + ); + // test alias endpoint + // https://go.mparticle.com/work/SQDSDKS-6751 + fetchMock.post( + 'https://custom-alias/test_key/Alias', + HTTP_ACCEPTED, + ); + + mParticle.Identity.aliasUsers( + { + destinationMpid: 1, + sourceMpid: 2, + startTime: 3, + endTime: 4, + }, + aliasCallback, + ); + + function aliasCallback() { + const lastFetchCallUrl = fetchMock.lastCall()[0]; + const expectedUrl = `https://${window.mParticle.config.aliasUrl}test_key/Alias`; + + lastFetchCallUrl.should.equal(expectedUrl); + + done(); + } + }); + }); }); }); @@ -1017,46 +1221,48 @@ describe('core SDK', function() { done(); }); - it('should use custom v3 endpoint when specified on config object', function(done) { + it('should use custom v3 endpoint when specified on config object', function (done) { mParticle.config.v3SecureServiceUrl = 'def-v3SecureServiceUrl/v3/JS/'; mParticle.config.flags = { eventBatchingIntervalMillis: 0, - } + }; fetchMock.post( 'https://def-v3SecureServiceUrl/v3/JS/test_key/events', - 200 + 200, ); mParticle.init(apiKey, mParticle.config); - waitForCondition(hasIdentifyReturned) - .then(() => { - - window.mParticle.logEvent('Test Event'); + waitForCondition(hasIdentifyReturned).then(() => { + window.mParticle.logEvent('Test Event'); - fetchMock.lastOptions().body.should.be.ok() + fetchMock.lastOptions().body.should.be.ok(); - done(); - }) + done(); + }); }); - it('should add onCreateBatch to _Store.SDKConfig if onCreateBatch is provide on mParticle.config object', function(done) { + it('should add onCreateBatch to _Store.SDKConfig if onCreateBatch is provide on mParticle.config object', function (done) { window.mParticle._resetForTests(); - mParticle.config.onCreateBatch = function(batch) { return batch}; + mParticle.config.onCreateBatch = function (batch) { + return batch; + }; mParticle.init(apiKey, mParticle.config); - (typeof mParticle.getInstance()._Store.SDKConfig.onCreateBatch).should.equal('function'); + (typeof mParticle.getInstance()._Store.SDKConfig + .onCreateBatch).should.equal('function'); done(); }); - it('should not add onCreateBatch to _Store.SDKConfig if it is not a function', function(done) { + it('should not add onCreateBatch to _Store.SDKConfig if it is not a function', function (done) { window.mParticle._resetForTests(); mParticle.config.onCreateBatch = 'not a function'; mParticle.init(apiKey, mParticle.config); - (typeof mParticle.getInstance()._Store.SDKConfig.onCreateBatch).should.equal('undefined'); + (typeof mParticle.getInstance()._Store.SDKConfig + .onCreateBatch).should.equal('undefined'); done(); }); @@ -1069,14 +1275,12 @@ describe('core SDK', function() { fetchMock.get( 'https://jssdkcdns.mparticle.com/JS/v2/test_key/config?env=1', - { status: 200 } + { status: 200 }, ); mParticle.init(apiKey, window.mParticle.config); // While config fetch is async, we are only testing what endpoint is hit here, and so we do not need to wait for anything to return - (fetchMock.calls()[0][0].indexOf('?env=1') > 0).should.equal( - true - ); + (fetchMock.calls()[0][0].indexOf('?env=1') > 0).should.equal(true); done(); }); @@ -1085,17 +1289,13 @@ describe('core SDK', function() { mParticle.config.isDevelopmentMode = false; mParticle.config.requestConfig = true; - fetchMock.get(urls.config, - { status: 200 } - ); + fetchMock.get(urls.config, { status: 200 }); fetchMock.resetHistory(); mParticle.init(apiKey, window.mParticle.config); // rob note - while config fetch is async, we are only testing what endpoint is hit here, and so we do not need to wait for anything to return - (fetchMock.calls()[0][0].indexOf('?env=0') > 0).should.equal( - true - ); - + (fetchMock.calls()[0][0].indexOf('?env=0') > 0).should.equal(true); + done(); }); @@ -1120,7 +1320,8 @@ describe('core SDK', function() { mParticle.getInstance()._Store.SDKConfig.appName = config.appName; mParticle.getInstance()._Store.SDKConfig.minWebviewBridgeVersion = config.minWebviewBridgeVersion; - mParticle.getInstance()._Store.SDKConfig.workspaceToken = config.workspaceToken; + mParticle.getInstance()._Store.SDKConfig.workspaceToken = + config.workspaceToken; localStorage.removeItem(config.workspaceToken); }); @@ -1137,9 +1338,12 @@ describe('core SDK', function() { status: 200, body: JSON.stringify({ config }), }); - + fetchMock.config.overwriteRoutes = true; - fetchMock.post(urls.identify, {status: 400, body: JSON.stringify('')}); + fetchMock.post(urls.identify, { + status: 400, + body: JSON.stringify(''), + }); // force config to be only requestConfig = true; delete window.mParticle.config.kitConfigs; @@ -1164,13 +1368,12 @@ describe('core SDK', function() { userIdentities: { customerid: 'test' }, }); - await waitForCondition(() => mParticle.Identity.getCurrentUser()?.getMPID() === 'MPID1'); + await waitForCondition( + () => mParticle.Identity.getCurrentUser()?.getMPID() === 'MPID1', + ); mParticle.logEvent('Test Event'); - const testEvent = findEventFromRequest( - fetchMock.calls(), - 'Test Event' - ); + const testEvent = findEventFromRequest(fetchMock.calls(), 'Test Event'); testEvent.should.be.ok(); }); @@ -1185,7 +1388,7 @@ describe('core SDK', function() { mParticle.getInstance()._Store.isInitialized.should.equal(true); }); - it('should generate hash both on the mparticle instance and the mparticle instance manager', function(done) { + it('should generate hash both on the mparticle instance and the mparticle instance manager', function (done) { const hashValue = -1146196832; const hash1 = mParticle.generateHash('TestHash'); const hash2 = mParticle.getInstance().generateHash('TestHash'); @@ -1196,42 +1399,42 @@ describe('core SDK', function() { done(); }); - it('should remove localstorage when calling reset', function(done) { + it('should remove localstorage when calling reset', function (done) { mParticle._resetForTests(MPConfig); window.mParticle.config.workspaceToken = 'defghi'; - mParticle.init(apiKey, window.mParticle.config) + mParticle.init(apiKey, window.mParticle.config); let ls = localStorage.getItem('mprtcl-v4_defghi'); ls.should.be.ok(); mParticle.reset(); - + ls = localStorage.getItem('mprtcl-v4_defghi'); - (ls === null).should.equal(true) - + (ls === null).should.equal(true); + done(); }); - - it('should remove cookies when calling reset', function(done) { + + it('should remove cookies when calling reset', function (done) { mParticle._resetForTests(MPConfig); window.mParticle.config.useCookieStorage = true; window.mParticle.config.workspaceToken = 'defghi'; - mParticle.init(apiKey, window.mParticle.config) + mParticle.init(apiKey, window.mParticle.config); let cookie = document.cookie; cookie.includes('mprtcl-v4_defghi').should.equal(true); mParticle.reset(); cookie = document.cookie; - + cookie.includes('mprtcl-v4_defghi').should.equal(false); - + window.mParticle.config.useCookieStorage = false; done(); }); - it('should queue setCurrencyCode successfully when SDK is not yet initialized, and then later initialized', function(done) { + it('should queue setCurrencyCode successfully when SDK is not yet initialized, and then later initialized', function (done) { mParticle._resetForTests(MPConfig); // mock a non-initialized state mParticle.getInstance()._Store.isInitialized = false; @@ -1240,25 +1443,25 @@ describe('core SDK', function() { mParticle.eCommerce.setCurrencyCode('USD'); // initializing SDK will flush the ready queue and setCurrencyCode should not throw an error - mParticle.init(apiKey, window.mParticle.config) + mParticle.init(apiKey, window.mParticle.config); done(); }); it('should set a device id when calling setDeviceId', async () => { mParticle._resetForTests(MPConfig); - + mParticle.init(apiKey, window.mParticle.config); await waitForCondition(hasIdentityCallInflightReturned); // this das should be the SDK auto generated one, which is 36 characters long mParticle.getDeviceId().length.should.equal(36); mParticle.setDeviceId('foo-guid'); - + mParticle.getDeviceId().should.equal('foo-guid'); }); - it('should set a device id when set on mParticle.config', function(done) { + it('should set a device id when set on mParticle.config', function (done) { mParticle._resetForTests(MPConfig); window.mParticle.config.deviceId = 'foo-guid'; mParticle.init(apiKey, window.mParticle.config); @@ -1268,26 +1471,34 @@ describe('core SDK', function() { done(); }); - it('should not set the wrapper sdk info in Store when mParticle._setWrapperSDKInfo() method is called if init not called', function(done) { + it('should not set the wrapper sdk info in Store when mParticle._setWrapperSDKInfo() method is called if init not called', function (done) { mParticle._resetForTests(MPConfig); mParticle._setWrapperSDKInfo('flutter', '1.0.3'); mParticle.getInstance()._Store.wrapperSDKInfo.name.should.equal('none'); - (mParticle.getInstance()._Store.wrapperSDKInfo.version === null).should.equal(true); - mParticle.getInstance()._Store.wrapperSDKInfo.isInfoSet.should.equal(false); - + ( + mParticle.getInstance()._Store.wrapperSDKInfo.version === null + ).should.equal(true); + mParticle + .getInstance() + ._Store.wrapperSDKInfo.isInfoSet.should.equal(false); + done(); }); - it('should have the correct wrapper sdk info default values when init is called', function(done) { + it('should have the correct wrapper sdk info default values when init is called', function (done) { mParticle._resetForTests(MPConfig); - + mParticle.init(apiKey, window.mParticle.config); mParticle.getInstance()._Store.wrapperSDKInfo.name.should.equal('none'); - (mParticle.getInstance()._Store.wrapperSDKInfo.version === null).should.equal(true); - mParticle.getInstance()._Store.wrapperSDKInfo.isInfoSet.should.equal(false); + ( + mParticle.getInstance()._Store.wrapperSDKInfo.version === null + ).should.equal(true); + mParticle + .getInstance() + ._Store.wrapperSDKInfo.isInfoSet.should.equal(false); done(); }); @@ -1300,9 +1511,15 @@ describe('core SDK', function() { mParticle.init(apiKey, window.mParticle.config); await waitForCondition(hasIdentityCallInflightReturned); - mParticle.getInstance()._Store.wrapperSDKInfo.name.should.equal('flutter'); - mParticle.getInstance()._Store.wrapperSDKInfo.version.should.equal('1.0.3'); - mParticle.getInstance()._Store.wrapperSDKInfo.isInfoSet.should.equal(true); + mParticle + .getInstance() + ._Store.wrapperSDKInfo.name.should.equal('flutter'); + mParticle + .getInstance() + ._Store.wrapperSDKInfo.version.should.equal('1.0.3'); + mParticle + .getInstance() + ._Store.wrapperSDKInfo.isInfoSet.should.equal(true); }); it('should not set the wrapper sdk info in Store after it has previously been set', async () => { @@ -1315,12 +1532,18 @@ describe('core SDK', function() { mParticle._setWrapperSDKInfo('none', '2.0.5'); - mParticle.getInstance()._Store.wrapperSDKInfo.name.should.equal('flutter'); - mParticle.getInstance()._Store.wrapperSDKInfo.version.should.equal('1.0.3'); - mParticle.getInstance()._Store.wrapperSDKInfo.isInfoSet.should.equal(true); + mParticle + .getInstance() + ._Store.wrapperSDKInfo.name.should.equal('flutter'); + mParticle + .getInstance() + ._Store.wrapperSDKInfo.version.should.equal('1.0.3'); + mParticle + .getInstance() + ._Store.wrapperSDKInfo.isInfoSet.should.equal(true); }); - describe('pod feature flag', function() { + describe('pod feature flag', function () { const endpoints = Constants.DefaultBaseUrls; // set up URLs object for each silo const URLs = { @@ -1329,7 +1552,7 @@ describe('core SDK', function() { eu1: {}, au1: {}, st1: {}, - xy1: {} // this is a fake silo used to show that there is no logic that is based on a pre-determined set of silos + xy1: {}, // this is a fake silo used to show that there is no logic that is based on a pre-determined set of silos }; // The below function builds out the above URLs object to have silo-specific urls, ie: @@ -1337,23 +1560,27 @@ describe('core SDK', function() { // URLs.us2.aliasUrl = 'jssdks.us2.mparticle.com/v1/identity/'; // etc, etc for each silo, and each endpoint Object.keys(URLs).forEach((key) => { - for (let endpointKey in endpoints) { + for (const endpointKey in endpoints) { if (endpointKey === 'configUrl') { // Do not route config url to silo, use the default instead URLs[key][endpointKey] = endpoints[endpointKey]; } const endpointParts = endpoints[endpointKey].split('.'); - URLs[key][endpointKey] = [endpointParts[0], key, ...endpointParts.slice(1)].join('.') + URLs[key][endpointKey] = [ + endpointParts[0], + key, + ...endpointParts.slice(1), + ].join('.'); } }); - beforeEach(function() { + beforeEach(function () { window.mParticle.config.flags = { - directURLRouting: 'True' + directURLRouting: 'True', }; }); - it('should use US1 endpoints for apiKeys that do not start with a prefix', function(done) { + it('should use US1 endpoints for apiKeys that do not start with a prefix', function (done) { const silo = 'us1'; const apiKey = 'noSiloPrefixApiKey'; const eventsEndpoint = `https://${URLs[silo].v3SecureServiceUrl}${apiKey}/events`; @@ -1361,17 +1588,39 @@ describe('core SDK', function() { fetchMock.post(eventsEndpoint, 200); mParticle.init(apiKey, window.mParticle.config); - mParticle.getInstance()._Store.SDKConfig.aliasUrl.should.equal(URLs[silo].aliasUrl); - mParticle.getInstance()._Store.SDKConfig.configUrl.should.equal(Constants.DefaultBaseUrls.configUrl); - mParticle.getInstance()._Store.SDKConfig.identityUrl.should.equal(URLs[silo].identityUrl); - mParticle.getInstance()._Store.SDKConfig.v1SecureServiceUrl.should.equal(URLs[silo].v1SecureServiceUrl); - mParticle.getInstance()._Store.SDKConfig.v2SecureServiceUrl.should.equal(URLs[silo].v2SecureServiceUrl); - mParticle.getInstance()._Store.SDKConfig.v3SecureServiceUrl.should.equal(URLs[silo].v3SecureServiceUrl); + mParticle + .getInstance() + ._Store.SDKConfig.aliasUrl.should.equal(URLs[silo].aliasUrl); + mParticle + .getInstance() + ._Store.SDKConfig.configUrl.should.equal( + Constants.DefaultBaseUrls.configUrl, + ); + mParticle + .getInstance() + ._Store.SDKConfig.identityUrl.should.equal( + URLs[silo].identityUrl, + ); + mParticle + .getInstance() + ._Store.SDKConfig.v1SecureServiceUrl.should.equal( + URLs[silo].v1SecureServiceUrl, + ); + mParticle + .getInstance() + ._Store.SDKConfig.v2SecureServiceUrl.should.equal( + URLs[silo].v2SecureServiceUrl, + ); + mParticle + .getInstance() + ._Store.SDKConfig.v3SecureServiceUrl.should.equal( + URLs[silo].v3SecureServiceUrl, + ); done(); }); - it('should use US1 endpoints for apiKeys with prefix `us1`', function(done) { + it('should use US1 endpoints for apiKeys with prefix `us1`', function (done) { const silo = 'us1'; const apiKey = 'us1-apiKey'; const eventsEndpoint = `https://${URLs.us1.v3SecureServiceUrl}${apiKey}/events`; @@ -1379,17 +1628,39 @@ describe('core SDK', function() { fetchMock.post(eventsEndpoint, 200); mParticle.init(apiKey, window.mParticle.config); - mParticle.getInstance()._Store.SDKConfig.aliasUrl.should.equal(URLs[silo].aliasUrl); - mParticle.getInstance()._Store.SDKConfig.configUrl.should.equal(Constants.DefaultBaseUrls.configUrl); - mParticle.getInstance()._Store.SDKConfig.identityUrl.should.equal(URLs[silo].identityUrl); - mParticle.getInstance()._Store.SDKConfig.v1SecureServiceUrl.should.equal(URLs[silo].v1SecureServiceUrl); - mParticle.getInstance()._Store.SDKConfig.v2SecureServiceUrl.should.equal(URLs[silo].v2SecureServiceUrl); - mParticle.getInstance()._Store.SDKConfig.v3SecureServiceUrl.should.equal(URLs[silo].v3SecureServiceUrl); + mParticle + .getInstance() + ._Store.SDKConfig.aliasUrl.should.equal(URLs[silo].aliasUrl); + mParticle + .getInstance() + ._Store.SDKConfig.configUrl.should.equal( + Constants.DefaultBaseUrls.configUrl, + ); + mParticle + .getInstance() + ._Store.SDKConfig.identityUrl.should.equal( + URLs[silo].identityUrl, + ); + mParticle + .getInstance() + ._Store.SDKConfig.v1SecureServiceUrl.should.equal( + URLs[silo].v1SecureServiceUrl, + ); + mParticle + .getInstance() + ._Store.SDKConfig.v2SecureServiceUrl.should.equal( + URLs[silo].v2SecureServiceUrl, + ); + mParticle + .getInstance() + ._Store.SDKConfig.v3SecureServiceUrl.should.equal( + URLs[silo].v3SecureServiceUrl, + ); done(); }); - it('should use US2 endpoints for apiKeys with prefix `us2`', function(done) { + it('should use US2 endpoints for apiKeys with prefix `us2`', function (done) { const silo = 'us2'; const apiKey = 'us2-apiKey'; const eventsEndpoint = `https://${URLs[silo].v3SecureServiceUrl}${apiKey}/events`; @@ -1397,17 +1668,39 @@ describe('core SDK', function() { fetchMock.post(eventsEndpoint, 200); mParticle.init(apiKey, window.mParticle.config); - mParticle.getInstance()._Store.SDKConfig.aliasUrl.should.equal(URLs[silo].aliasUrl); - mParticle.getInstance()._Store.SDKConfig.configUrl.should.equal(Constants.DefaultBaseUrls.configUrl); - mParticle.getInstance()._Store.SDKConfig.identityUrl.should.equal(URLs[silo].identityUrl); - mParticle.getInstance()._Store.SDKConfig.v1SecureServiceUrl.should.equal(URLs[silo].v1SecureServiceUrl); - mParticle.getInstance()._Store.SDKConfig.v2SecureServiceUrl.should.equal(URLs[silo].v2SecureServiceUrl); - mParticle.getInstance()._Store.SDKConfig.v3SecureServiceUrl.should.equal(URLs[silo].v3SecureServiceUrl); + mParticle + .getInstance() + ._Store.SDKConfig.aliasUrl.should.equal(URLs[silo].aliasUrl); + mParticle + .getInstance() + ._Store.SDKConfig.configUrl.should.equal( + Constants.DefaultBaseUrls.configUrl, + ); + mParticle + .getInstance() + ._Store.SDKConfig.identityUrl.should.equal( + URLs[silo].identityUrl, + ); + mParticle + .getInstance() + ._Store.SDKConfig.v1SecureServiceUrl.should.equal( + URLs[silo].v1SecureServiceUrl, + ); + mParticle + .getInstance() + ._Store.SDKConfig.v2SecureServiceUrl.should.equal( + URLs[silo].v2SecureServiceUrl, + ); + mParticle + .getInstance() + ._Store.SDKConfig.v3SecureServiceUrl.should.equal( + URLs[silo].v3SecureServiceUrl, + ); done(); }); - it('should use EU1 endpoints for apiKeys with prefix `eu1`', function(done) { + it('should use EU1 endpoints for apiKeys with prefix `eu1`', function (done) { const silo = 'eu1'; const apiKey = 'eu1-apiKey'; const eventsEndpoint = `https://${URLs[silo].v3SecureServiceUrl}${apiKey}/events`; @@ -1415,17 +1708,39 @@ describe('core SDK', function() { fetchMock.post(eventsEndpoint, 200); mParticle.init(apiKey, window.mParticle.config); - mParticle.getInstance()._Store.SDKConfig.aliasUrl.should.equal(URLs[silo].aliasUrl); - mParticle.getInstance()._Store.SDKConfig.configUrl.should.equal(Constants.DefaultBaseUrls.configUrl); - mParticle.getInstance()._Store.SDKConfig.identityUrl.should.equal(URLs[silo].identityUrl); - mParticle.getInstance()._Store.SDKConfig.v1SecureServiceUrl.should.equal(URLs[silo].v1SecureServiceUrl); - mParticle.getInstance()._Store.SDKConfig.v2SecureServiceUrl.should.equal(URLs[silo].v2SecureServiceUrl); - mParticle.getInstance()._Store.SDKConfig.v3SecureServiceUrl.should.equal(URLs[silo].v3SecureServiceUrl); + mParticle + .getInstance() + ._Store.SDKConfig.aliasUrl.should.equal(URLs[silo].aliasUrl); + mParticle + .getInstance() + ._Store.SDKConfig.configUrl.should.equal( + Constants.DefaultBaseUrls.configUrl, + ); + mParticle + .getInstance() + ._Store.SDKConfig.identityUrl.should.equal( + URLs[silo].identityUrl, + ); + mParticle + .getInstance() + ._Store.SDKConfig.v1SecureServiceUrl.should.equal( + URLs[silo].v1SecureServiceUrl, + ); + mParticle + .getInstance() + ._Store.SDKConfig.v2SecureServiceUrl.should.equal( + URLs[silo].v2SecureServiceUrl, + ); + mParticle + .getInstance() + ._Store.SDKConfig.v3SecureServiceUrl.should.equal( + URLs[silo].v3SecureServiceUrl, + ); done(); }); - it('should use AU1 endpoints for apiKeys with prefix `au1`', function(done) { + it('should use AU1 endpoints for apiKeys with prefix `au1`', function (done) { const silo = 'au1'; const apiKey = 'au1-apiKey'; const eventsEndpoint = `https://${URLs[silo].v3SecureServiceUrl}${apiKey}/events`; @@ -1433,17 +1748,39 @@ describe('core SDK', function() { fetchMock.post(eventsEndpoint, 200); mParticle.init(apiKey, window.mParticle.config); - mParticle.getInstance()._Store.SDKConfig.aliasUrl.should.equal(URLs[silo].aliasUrl); - mParticle.getInstance()._Store.SDKConfig.configUrl.should.equal(Constants.DefaultBaseUrls.configUrl); - mParticle.getInstance()._Store.SDKConfig.identityUrl.should.equal(URLs[silo].identityUrl); - mParticle.getInstance()._Store.SDKConfig.v1SecureServiceUrl.should.equal(URLs[silo].v1SecureServiceUrl); - mParticle.getInstance()._Store.SDKConfig.v2SecureServiceUrl.should.equal(URLs[silo].v2SecureServiceUrl); - mParticle.getInstance()._Store.SDKConfig.v3SecureServiceUrl.should.equal(URLs[silo].v3SecureServiceUrl); + mParticle + .getInstance() + ._Store.SDKConfig.aliasUrl.should.equal(URLs[silo].aliasUrl); + mParticle + .getInstance() + ._Store.SDKConfig.configUrl.should.equal( + Constants.DefaultBaseUrls.configUrl, + ); + mParticle + .getInstance() + ._Store.SDKConfig.identityUrl.should.equal( + URLs[silo].identityUrl, + ); + mParticle + .getInstance() + ._Store.SDKConfig.v1SecureServiceUrl.should.equal( + URLs[silo].v1SecureServiceUrl, + ); + mParticle + .getInstance() + ._Store.SDKConfig.v2SecureServiceUrl.should.equal( + URLs[silo].v2SecureServiceUrl, + ); + mParticle + .getInstance() + ._Store.SDKConfig.v3SecureServiceUrl.should.equal( + URLs[silo].v3SecureServiceUrl, + ); done(); }); - it('should use ST1 endpoints for apiKeys with prefix `st1`', function(done) { + it('should use ST1 endpoints for apiKeys with prefix `st1`', function (done) { const silo = 'st1'; const apiKey = 'st1-apiKey'; const eventsEndpoint = `https://${URLs[silo].v3SecureServiceUrl}${apiKey}/events`; @@ -1451,17 +1788,39 @@ describe('core SDK', function() { fetchMock.post(eventsEndpoint, 200); mParticle.init(apiKey, window.mParticle.config); - mParticle.getInstance()._Store.SDKConfig.aliasUrl.should.equal(URLs[silo].aliasUrl); - mParticle.getInstance()._Store.SDKConfig.configUrl.should.equal(Constants.DefaultBaseUrls.configUrl); - mParticle.getInstance()._Store.SDKConfig.identityUrl.should.equal(URLs[silo].identityUrl); - mParticle.getInstance()._Store.SDKConfig.v1SecureServiceUrl.should.equal(URLs[silo].v1SecureServiceUrl); - mParticle.getInstance()._Store.SDKConfig.v2SecureServiceUrl.should.equal(URLs[silo].v2SecureServiceUrl); - mParticle.getInstance()._Store.SDKConfig.v3SecureServiceUrl.should.equal(URLs[silo].v3SecureServiceUrl); + mParticle + .getInstance() + ._Store.SDKConfig.aliasUrl.should.equal(URLs[silo].aliasUrl); + mParticle + .getInstance() + ._Store.SDKConfig.configUrl.should.equal( + Constants.DefaultBaseUrls.configUrl, + ); + mParticle + .getInstance() + ._Store.SDKConfig.identityUrl.should.equal( + URLs[silo].identityUrl, + ); + mParticle + .getInstance() + ._Store.SDKConfig.v1SecureServiceUrl.should.equal( + URLs[silo].v1SecureServiceUrl, + ); + mParticle + .getInstance() + ._Store.SDKConfig.v2SecureServiceUrl.should.equal( + URLs[silo].v2SecureServiceUrl, + ); + mParticle + .getInstance() + ._Store.SDKConfig.v3SecureServiceUrl.should.equal( + URLs[silo].v3SecureServiceUrl, + ); done(); }); - it('should use xy1 endpoints for apiKeys with prefix `xy1`', function(done) { + it('should use xy1 endpoints for apiKeys with prefix `xy1`', function (done) { const silo = 'xy1'; const apiKey = 'xy1-apiKey'; const eventsEndpoint = `https://${URLs[silo].v3SecureServiceUrl}${apiKey}/events`; @@ -1469,39 +1828,81 @@ describe('core SDK', function() { fetchMock.post(eventsEndpoint, 200); mParticle.init(apiKey, window.mParticle.config); - mParticle.getInstance()._Store.SDKConfig.aliasUrl.should.equal(URLs[silo].aliasUrl); - mParticle.getInstance()._Store.SDKConfig.configUrl.should.equal(Constants.DefaultBaseUrls.configUrl); - mParticle.getInstance()._Store.SDKConfig.identityUrl.should.equal(URLs[silo].identityUrl); - mParticle.getInstance()._Store.SDKConfig.v1SecureServiceUrl.should.equal(URLs[silo].v1SecureServiceUrl); - mParticle.getInstance()._Store.SDKConfig.v2SecureServiceUrl.should.equal(URLs[silo].v2SecureServiceUrl); - mParticle.getInstance()._Store.SDKConfig.v3SecureServiceUrl.should.equal(URLs[silo].v3SecureServiceUrl); + mParticle + .getInstance() + ._Store.SDKConfig.aliasUrl.should.equal(URLs[silo].aliasUrl); + mParticle + .getInstance() + ._Store.SDKConfig.configUrl.should.equal( + Constants.DefaultBaseUrls.configUrl, + ); + mParticle + .getInstance() + ._Store.SDKConfig.identityUrl.should.equal( + URLs[silo].identityUrl, + ); + mParticle + .getInstance() + ._Store.SDKConfig.v1SecureServiceUrl.should.equal( + URLs[silo].v1SecureServiceUrl, + ); + mParticle + .getInstance() + ._Store.SDKConfig.v2SecureServiceUrl.should.equal( + URLs[silo].v2SecureServiceUrl, + ); + mParticle + .getInstance() + ._Store.SDKConfig.v3SecureServiceUrl.should.equal( + URLs[silo].v3SecureServiceUrl, + ); done(); }); - it('should prioritize configured URLs over direct URL mapping', function(done) { - window.mParticle.config.v3SecureServiceUrl = 'testtesttest-custom-v3secureserviceurl/v3/JS/'; - window.mParticle.config.configUrl ='foo-custom-configUrl/v2/JS/'; + it('should prioritize configured URLs over direct URL mapping', function (done) { + window.mParticle.config.v3SecureServiceUrl = + 'testtesttest-custom-v3secureserviceurl/v3/JS/'; + window.mParticle.config.configUrl = 'foo-custom-configUrl/v2/JS/'; window.mParticle.config.identityUrl = 'custom-identityUrl/'; window.mParticle.config.aliasUrl = 'custom-aliasUrl/'; - const {configUrl, v3SecureServiceUrl, identityUrl, aliasUrl} = window.mParticle.config + const { configUrl, v3SecureServiceUrl, identityUrl, aliasUrl } = + window.mParticle.config; const silo = 'us1'; const apiKey = 'noSiloPrefixApiKey'; const eventsEndpoint = `https://${v3SecureServiceUrl}${apiKey}/events`; - fetchMock.post(eventsEndpoint, 200) + fetchMock.post(eventsEndpoint, 200); mParticle.init(apiKey, window.mParticle.config); - mParticle.getInstance()._Store.SDKConfig.aliasUrl.should.equal(aliasUrl); - mParticle.getInstance()._Store.SDKConfig.configUrl.should.equal(configUrl); - mParticle.getInstance()._Store.SDKConfig.identityUrl.should.equal(identityUrl); - mParticle.getInstance()._Store.SDKConfig.v1SecureServiceUrl.should.equal(URLs[silo].v1SecureServiceUrl); - mParticle.getInstance()._Store.SDKConfig.v2SecureServiceUrl.should.equal(URLs[silo].v2SecureServiceUrl); - mParticle.getInstance()._Store.SDKConfig.v3SecureServiceUrl.should.equal(v3SecureServiceUrl); + mParticle + .getInstance() + ._Store.SDKConfig.aliasUrl.should.equal(aliasUrl); + mParticle + .getInstance() + ._Store.SDKConfig.configUrl.should.equal(configUrl); + mParticle + .getInstance() + ._Store.SDKConfig.identityUrl.should.equal(identityUrl); + mParticle + .getInstance() + ._Store.SDKConfig.v1SecureServiceUrl.should.equal( + URLs[silo].v1SecureServiceUrl, + ); + mParticle + .getInstance() + ._Store.SDKConfig.v2SecureServiceUrl.should.equal( + URLs[silo].v2SecureServiceUrl, + ); + mParticle + .getInstance() + ._Store.SDKConfig.v3SecureServiceUrl.should.equal( + v3SecureServiceUrl, + ); done(); }); }); -}); \ No newline at end of file +}); diff --git a/test/src/tests-eCommerce.js b/test/src/tests-eCommerce.js index 8c3e1dc8e..8b8de16f2 100644 --- a/test/src/tests-eCommerce.js +++ b/test/src/tests-eCommerce.js @@ -1,7 +1,15 @@ import Utils from './config/utils'; import sinon from 'sinon'; import fetchMock from 'fetch-mock/esm/client'; -import { urls, apiKey, workspaceToken, MPConfig, testMPID, ProductActionType, PromotionActionType } from './config/constants'; +import { + urls, + apiKey, + workspaceToken, + MPConfig, + testMPID, + ProductActionType, + PromotionActionType, +} from './config/constants'; const { waitForCondition, fetchMockSuccess, hasIdentifyReturned } = Utils; const getLocalStorageProducts = Utils.getLocalStorageProducts, @@ -9,31 +17,31 @@ const getLocalStorageProducts = Utils.getLocalStorageProducts, findEventFromRequest = Utils.findEventFromRequest, MockForwarder = Utils.MockForwarder; -describe('eCommerce', function() { - beforeEach(function() { +describe('eCommerce', function () { + beforeEach(function () { mParticle._resetForTests(MPConfig); delete mParticle._instances['default_instance']; fetchMock.post(urls.events, 200); fetchMockSuccess(urls.identify, { - mpid: testMPID, is_logged_in: false + mpid: testMPID, + is_logged_in: false, }); - mParticle.init(apiKey, window.mParticle.config); }); - afterEach(function() { + afterEach(function () { fetchMock.restore(); mParticle._resetForTests(MPConfig); }); - it('should create ecommerce product', function(done) { + it('should create ecommerce product', function (done) { const product = mParticle.eCommerce.createProduct( 'iPhone', '12345', 400, - 2 + 2, ); product.should.have.property('Name', 'iPhone'); @@ -44,20 +52,21 @@ describe('eCommerce', function() { done(); }); - it('should create transaction attributes', function(done) { - const transactionAttributes = mParticle.eCommerce.createTransactionAttributes( - '12345', - 'test-affiliation', - 'coupon-code', - 44334, - 600, - 200 - ); + it('should create transaction attributes', function (done) { + const transactionAttributes = + mParticle.eCommerce.createTransactionAttributes( + '12345', + 'test-affiliation', + 'coupon-code', + 44334, + 600, + 200, + ); transactionAttributes.should.have.property('Id', '12345'); transactionAttributes.should.have.property( 'Affiliation', - 'test-affiliation' + 'test-affiliation', ); transactionAttributes.should.have.property('CouponCode', 'coupon-code'); transactionAttributes.should.have.property('Revenue', 44334); @@ -67,80 +76,142 @@ describe('eCommerce', function() { done(); }); - it('should log ecommerce event', function(done) { - waitForCondition(hasIdentifyReturned) - .then(() => { - const product = mParticle.eCommerce.createProduct( - 'iPhone', + it('should log ecommerce event', function (done) { + waitForCondition(hasIdentifyReturned).then(() => { + const product = mParticle.eCommerce.createProduct( + 'iPhone', + '12345', + '400', + 2, + 'Plus', + 'Phones', + 'Apple', + 1, + 'my-coupon-code', + { customkey: 'customvalue' }, + ), + transactionAttributes = + mParticle.eCommerce.createTransactionAttributes( + '12345', + 'test-affiliation', + 'coupon-code', + 44334, + 600, + 200, + ); + + mParticle.eCommerce.logPurchase(transactionAttributes, product); + + const purchaseEvent = findEventFromRequest( + fetchMock.calls(), + 'purchase', + ); + + purchaseEvent.data.should.have.property('product_action'); + purchaseEvent.data.product_action.should.have.property( + 'action', + 'purchase', + ); + purchaseEvent.data.product_action.should.have.property( + 'transaction_id', '12345', - '400', + ); + purchaseEvent.data.product_action.should.have.property( + 'affiliation', + 'test-affiliation', + ); + purchaseEvent.data.product_action.should.have.property( + 'coupon_code', + 'coupon-code', + ); + purchaseEvent.data.product_action.should.have.property( + 'total_amount', + 44334, + ); + purchaseEvent.data.product_action.should.have.property( + 'shipping_amount', + 600, + ); + purchaseEvent.data.product_action.should.have.property( + 'tax_amount', + 200, + ); + purchaseEvent.data.product_action.should.have + .property('products') + .with.lengthOf(1); + + purchaseEvent.data.product_action.products[0].should.have.property( + 'id', + '12345', + ); + purchaseEvent.data.product_action.products[0].should.have.property( + 'name', + 'iPhone', + ); + purchaseEvent.data.product_action.products[0].should.have.property( + 'price', + 400, + ); + purchaseEvent.data.product_action.products[0].should.have.property( + 'quantity', 2, + ); + purchaseEvent.data.product_action.products[0].should.have.property( + 'brand', + 'Apple', + ); + purchaseEvent.data.product_action.products[0].should.have.property( + 'variant', 'Plus', + ); + purchaseEvent.data.product_action.products[0].should.have.property( + 'category', 'Phones', - 'Apple', + ); + purchaseEvent.data.product_action.products[0].should.have.property( + 'total_product_amount', + 800, + ); + purchaseEvent.data.product_action.products[0].should.have.property( + 'position', 1, + ); + purchaseEvent.data.product_action.products[0].should.have.property( + 'coupon_code', 'my-coupon-code', - { customkey: 'customvalue' } - ), - transactionAttributes = mParticle.eCommerce.createTransactionAttributes( - '12345', - 'test-affiliation', - 'coupon-code', - 44334, - 600, - 200 - ); - - mParticle.eCommerce.logPurchase(transactionAttributes, product); - - const purchaseEvent = findEventFromRequest(fetchMock.calls(), 'purchase'); - - purchaseEvent.data.should.have.property('product_action'); - purchaseEvent.data.product_action.should.have.property('action', 'purchase'); - purchaseEvent.data.product_action.should.have.property('transaction_id', '12345'); - purchaseEvent.data.product_action.should.have.property('affiliation', 'test-affiliation'); - purchaseEvent.data.product_action.should.have.property('coupon_code', 'coupon-code'); - purchaseEvent.data.product_action.should.have.property('total_amount', 44334); - purchaseEvent.data.product_action.should.have.property('shipping_amount', 600); - purchaseEvent.data.product_action.should.have.property('tax_amount', 200); - purchaseEvent.data.product_action.should.have.property('products').with.lengthOf(1); - - purchaseEvent.data.product_action.products[0].should.have.property('id', '12345'); - purchaseEvent.data.product_action.products[0].should.have.property('name', 'iPhone'); - purchaseEvent.data.product_action.products[0].should.have.property('price', 400); - purchaseEvent.data.product_action.products[0].should.have.property('quantity', 2); - purchaseEvent.data.product_action.products[0].should.have.property('brand', 'Apple'); - purchaseEvent.data.product_action.products[0].should.have.property('variant', 'Plus'); - purchaseEvent.data.product_action.products[0].should.have.property('category', 'Phones'); - purchaseEvent.data.product_action.products[0].should.have.property('total_product_amount', 800); - purchaseEvent.data.product_action.products[0].should.have.property('position', 1); - purchaseEvent.data.product_action.products[0].should.have.property('coupon_code', 'my-coupon-code'); - purchaseEvent.data.product_action.products[0].should.have.property('custom_attributes'); - - purchaseEvent.data.product_action.products[0].custom_attributes.should.have.property('customkey', 'customvalue'); + ); + purchaseEvent.data.product_action.products[0].should.have.property( + 'custom_attributes', + ); - done(); - }) + purchaseEvent.data.product_action.products[0].custom_attributes.should.have.property( + 'customkey', + 'customvalue', + ); + + done(); + }); }); - it('should not log an ecommerce event if there is a typo in the product action type', function(done) { + it('should not log an ecommerce event if there is a typo in the product action type', function (done) { // fetchMock calls will have session start and AST events, we want to reset so that we can prove the product action type does not go through (length remains 0 after logging) fetchMock.resetHistory(); const product = mParticle.eCommerce.createProduct( - 'iPhone', - '12345', - '400'); + 'iPhone', + '12345', + '400', + ); mParticle.eCommerce.logProductAction( mParticle.ProductActionType.Typo, // <------ will result in a null when converting the product action type as this is not a real value - [product] + [product], ); fetchMock.calls().length.should.equal(0); done(); }); - it('should log badly formed ecommerce event', function(done) { + it('should log badly formed ecommerce event', function (done) { const product = mParticle.eCommerce.createProduct( 'iPhone', '12345', @@ -151,52 +222,113 @@ describe('eCommerce', function() { 'Apple', '1-foo', 'my-coupon-code', - { customkey: 'customvalue' } + { customkey: 'customvalue' }, ), - transactionAttributes = mParticle.eCommerce.createTransactionAttributes( + transactionAttributes = + mParticle.eCommerce.createTransactionAttributes( + '12345', + 'test-affiliation', + 'coupon-code', + '44334-foo', + '600-foo', + '200-foo', + ); + + waitForCondition(hasIdentifyReturned).then(() => { + mParticle.eCommerce.logPurchase(transactionAttributes, product); + + const purchaseEvent = findEventFromRequest( + fetchMock.calls(), + 'purchase', + ); + + purchaseEvent.data.should.have.property('product_action'); + purchaseEvent.data.product_action.should.have.property( + 'action', + 'purchase', + ); + purchaseEvent.data.product_action.should.have.property( + 'transaction_id', '12345', + ); + purchaseEvent.data.product_action.should.have.property( + 'affiliation', 'test-affiliation', + ); + purchaseEvent.data.product_action.should.have.property( + 'coupon_code', 'coupon-code', - '44334-foo', - '600-foo', - '200-foo' - ); - - waitForCondition(hasIdentifyReturned) - .then(() => { - mParticle.eCommerce.logPurchase(transactionAttributes, product); - - const purchaseEvent = findEventFromRequest(fetchMock.calls(), 'purchase'); - - purchaseEvent.data.should.have.property('product_action'); - purchaseEvent.data.product_action.should.have.property('action', 'purchase'); - purchaseEvent.data.product_action.should.have.property('transaction_id', '12345'); - purchaseEvent.data.product_action.should.have.property('affiliation', 'test-affiliation'); - purchaseEvent.data.product_action.should.have.property('coupon_code', 'coupon-code'); - purchaseEvent.data.product_action.should.have.property('total_amount', 0); - purchaseEvent.data.product_action.should.have.property('shipping_amount', 0); - purchaseEvent.data.product_action.should.have.property('tax_amount', 0); - purchaseEvent.data.product_action.should.have.property('products').with.lengthOf(1); - - purchaseEvent.data.product_action.products[0].should.have.property('id', '12345'); - purchaseEvent.data.product_action.products[0].should.have.property('name', 'iPhone'); - purchaseEvent.data.product_action.products[0].should.have.property('price', 0); - purchaseEvent.data.product_action.products[0].should.have.property('quantity', 0); - purchaseEvent.data.product_action.products[0].should.have.property('brand', 'Apple'); - purchaseEvent.data.product_action.products[0].should.have.property('variant', 'Plus'); - purchaseEvent.data.product_action.products[0].should.have.property('category', 'Phones'); - purchaseEvent.data.product_action.products[0].should.have.property('position', null); - purchaseEvent.data.product_action.products[0].should.have.property('coupon_code', 'my-coupon-code'); - purchaseEvent.data.product_action.products[0].should.have.property('total_product_amount', 0); - purchaseEvent.data.product_action.products[0].should.have.property('custom_attributes'); - - purchaseEvent.data.product_action.products[0].custom_attributes.should.have.property('customkey', 'customvalue'); + ); + purchaseEvent.data.product_action.should.have.property( + 'total_amount', + 0, + ); + purchaseEvent.data.product_action.should.have.property( + 'shipping_amount', + 0, + ); + purchaseEvent.data.product_action.should.have.property( + 'tax_amount', + 0, + ); + purchaseEvent.data.product_action.should.have + .property('products') + .with.lengthOf(1); - done(); - }) + purchaseEvent.data.product_action.products[0].should.have.property( + 'id', + '12345', + ); + purchaseEvent.data.product_action.products[0].should.have.property( + 'name', + 'iPhone', + ); + purchaseEvent.data.product_action.products[0].should.have.property( + 'price', + 0, + ); + purchaseEvent.data.product_action.products[0].should.have.property( + 'quantity', + 0, + ); + purchaseEvent.data.product_action.products[0].should.have.property( + 'brand', + 'Apple', + ); + purchaseEvent.data.product_action.products[0].should.have.property( + 'variant', + 'Plus', + ); + purchaseEvent.data.product_action.products[0].should.have.property( + 'category', + 'Phones', + ); + purchaseEvent.data.product_action.products[0].should.have.property( + 'position', + null, + ); + purchaseEvent.data.product_action.products[0].should.have.property( + 'coupon_code', + 'my-coupon-code', + ); + purchaseEvent.data.product_action.products[0].should.have.property( + 'total_product_amount', + 0, + ); + purchaseEvent.data.product_action.products[0].should.have.property( + 'custom_attributes', + ); + + purchaseEvent.data.product_action.products[0].custom_attributes.should.have.property( + 'customkey', + 'customvalue', + ); + + done(); + }); }); - it('should log identical events for logPurchase and logProductAction with product action type of `purchase`', function(done) { + it('should log identical events for logPurchase and logProductAction with product action type of `purchase`', function (done) { const product = mParticle.eCommerce.createProduct( 'iPhone', '12345', @@ -207,112 +339,172 @@ describe('eCommerce', function() { 'Apple', 1, 'my-coupon-code', - { customkey: 'customvalue' } + { customkey: 'customvalue' }, ), - transactionAttributes = mParticle.eCommerce.createTransactionAttributes( - '12345', - 'test-affiliation', - 'coupon-code', - 44334, - 600, - 200 + transactionAttributes = + mParticle.eCommerce.createTransactionAttributes( + '12345', + 'test-affiliation', + 'coupon-code', + 44334, + 600, + 200, + ); + + waitForCondition(hasIdentifyReturned).then(() => { + mParticle.eCommerce.logPurchase(transactionAttributes, product); + const purchaseEvent1 = findEventFromRequest( + fetchMock.calls(), + 'purchase', ); - waitForCondition(hasIdentifyReturned) - .then(() => { - mParticle.eCommerce.logPurchase(transactionAttributes, product); - const purchaseEvent1 = findEventFromRequest(fetchMock.calls(), 'purchase'); - - fetchMock.resetHistory(); - - mParticle.eCommerce.logProductAction(mParticle.ProductActionType.Purchase, product, null, null, transactionAttributes) - const purchaseEvent2 = findEventFromRequest(fetchMock.calls(), 'purchase'); - - const { product_action: productAction1 } = purchaseEvent1.data; - const { product_action: productAction2 } = purchaseEvent2.data - - productAction1.action.should.equal(productAction2.action); - productAction1.transaction_id.should.equal(productAction2.transaction_id); - productAction1.affiliation.should.equal(productAction2.affiliation); - productAction1.coupon_code.should.equal(productAction2.coupon_code); - productAction1.total_amount.should.equal(productAction2.total_amount); - productAction1.shipping_amount.should.equal(productAction2.shipping_amount); - productAction1.tax_amount.should.equal(productAction2.tax_amount); - productAction1.products.length.should.equal(productAction2.products.length); - - productAction1.products[0].name.should.equal(productAction2.products[0].name); - productAction1.products[0].id.should.equal(productAction2.products[0].id); - productAction1.products[0].price.should.equal(productAction2.products[0].price); - productAction1.products[0].quantity.should.equal(productAction2.products[0].quantity); - productAction1.products[0].brand.should.equal(productAction2.products[0].brand); - productAction1.products[0].variant.should.equal(productAction2.products[0].variant); - productAction1.products[0].category.should.equal(productAction2.products[0].category); - productAction1.products[0].position.should.equal(productAction2.products[0].position); - - productAction1.products[0].coupon_code.should.equal(productAction2.products[0].coupon_code); - productAction1.products[0].total_product_amount.should.equal(productAction2.products[0].total_product_amount); - productAction1.products[0].custom_attributes.customkey.should.equal(productAction2.products[0].custom_attributes.customkey); - - done(); - }) - }); + fetchMock.resetHistory(); - it('logPurchase should support array of products', function(done) { - const product1 = mParticle.eCommerce.createProduct('iPhone', 'SKU1', 1), - product2 = mParticle.eCommerce.createProduct('Android', 'SKU2', 1), - transactionAttributes = mParticle.eCommerce.createTransactionAttributes( - '12345' + mParticle.eCommerce.logProductAction( + mParticle.ProductActionType.Purchase, + product, + null, + null, + transactionAttributes, ); + const purchaseEvent2 = findEventFromRequest( + fetchMock.calls(), + 'purchase', + ); + + const { product_action: productAction1 } = purchaseEvent1.data; + const { product_action: productAction2 } = purchaseEvent2.data; - waitForCondition(hasIdentifyReturned) - .then(() => { - mParticle.eCommerce.logPurchase(transactionAttributes, [ - product1, - product2, - ]); + productAction1.action.should.equal(productAction2.action); + productAction1.transaction_id.should.equal( + productAction2.transaction_id, + ); + productAction1.affiliation.should.equal(productAction2.affiliation); + productAction1.coupon_code.should.equal(productAction2.coupon_code); + productAction1.total_amount.should.equal( + productAction2.total_amount, + ); + productAction1.shipping_amount.should.equal( + productAction2.shipping_amount, + ); + productAction1.tax_amount.should.equal(productAction2.tax_amount); + productAction1.products.length.should.equal( + productAction2.products.length, + ); - const purchaseEvent = findEventFromRequest(fetchMock.calls(), 'purchase'); + productAction1.products[0].name.should.equal( + productAction2.products[0].name, + ); + productAction1.products[0].id.should.equal( + productAction2.products[0].id, + ); + productAction1.products[0].price.should.equal( + productAction2.products[0].price, + ); + productAction1.products[0].quantity.should.equal( + productAction2.products[0].quantity, + ); + productAction1.products[0].brand.should.equal( + productAction2.products[0].brand, + ); + productAction1.products[0].variant.should.equal( + productAction2.products[0].variant, + ); + productAction1.products[0].category.should.equal( + productAction2.products[0].category, + ); + productAction1.products[0].position.should.equal( + productAction2.products[0].position, + ); - purchaseEvent.data.should.have.property('product_action'); - purchaseEvent.data.product_action.should.have.property('products').with.lengthOf(2); - purchaseEvent.data.product_action.products[0].should.have.property('name', 'iPhone'); - purchaseEvent.data.product_action.products[1].should.have.property('name', 'Android'); + productAction1.products[0].coupon_code.should.equal( + productAction2.products[0].coupon_code, + ); + productAction1.products[0].total_product_amount.should.equal( + productAction2.products[0].total_product_amount, + ); + productAction1.products[0].custom_attributes.customkey.should.equal( + productAction2.products[0].custom_attributes.customkey, + ); - done(); - }) + done(); + }); }); - it('logRefund should support array of products', function(done) { + it('logPurchase should support array of products', function (done) { const product1 = mParticle.eCommerce.createProduct('iPhone', 'SKU1', 1), product2 = mParticle.eCommerce.createProduct('Android', 'SKU2', 1), - transactionAttributes = mParticle.eCommerce.createTransactionAttributes( - '12345' + transactionAttributes = + mParticle.eCommerce.createTransactionAttributes('12345'); + + waitForCondition(hasIdentifyReturned).then(() => { + mParticle.eCommerce.logPurchase(transactionAttributes, [ + product1, + product2, + ]); + + const purchaseEvent = findEventFromRequest( + fetchMock.calls(), + 'purchase', + ); + + purchaseEvent.data.should.have.property('product_action'); + purchaseEvent.data.product_action.should.have + .property('products') + .with.lengthOf(2); + purchaseEvent.data.product_action.products[0].should.have.property( + 'name', + 'iPhone', + ); + purchaseEvent.data.product_action.products[1].should.have.property( + 'name', + 'Android', ); - waitForCondition(hasIdentifyReturned) - .then(() => { - mParticle.eCommerce.logRefund(transactionAttributes, [ - product1, - product2, - ]); + done(); + }); + }); - const refundEvent = findEventFromRequest(fetchMock.calls(), 'refund'); + it('logRefund should support array of products', function (done) { + const product1 = mParticle.eCommerce.createProduct('iPhone', 'SKU1', 1), + product2 = mParticle.eCommerce.createProduct('Android', 'SKU2', 1), + transactionAttributes = + mParticle.eCommerce.createTransactionAttributes('12345'); + + waitForCondition(hasIdentifyReturned).then(() => { + mParticle.eCommerce.logRefund(transactionAttributes, [ + product1, + product2, + ]); + + const refundEvent = findEventFromRequest( + fetchMock.calls(), + 'refund', + ); - refundEvent.data.should.have.property('product_action'); - refundEvent.data.product_action.should.have.property('products').with.lengthOf(2); - refundEvent.data.product_action.products[0].should.have.property('name', 'iPhone'); - refundEvent.data.product_action.products[1].should.have.property('name', 'Android'); + refundEvent.data.should.have.property('product_action'); + refundEvent.data.product_action.should.have + .property('products') + .with.lengthOf(2); + refundEvent.data.product_action.products[0].should.have.property( + 'name', + 'iPhone', + ); + refundEvent.data.product_action.products[1].should.have.property( + 'name', + 'Android', + ); - done(); - }) + done(); + }); }); - it('should create promotion', function(done) { + it('should create promotion', function (done) { const promotion = mParticle.eCommerce.createPromotion( '12345', 'my-creative', 'creative-name', - 1 + 1, ); Should(promotion).be.ok(); @@ -325,76 +517,128 @@ describe('eCommerce', function() { done(); }); - it('should log promotion click', function(done) { + it('should log promotion click', function (done) { const promotion = mParticle.eCommerce.createPromotion( '12345', 'my-creative', 'creative-name', - 1 + 1, ); - waitForCondition(hasIdentifyReturned) - .then(() => { - mParticle.eCommerce.logPromotion( - mParticle.PromotionType.PromotionClick, - promotion - ); + waitForCondition(hasIdentifyReturned).then(() => { + mParticle.eCommerce.logPromotion( + mParticle.PromotionType.PromotionClick, + promotion, + ); - const promotionEvent = findEventFromRequest(fetchMock.calls(), 'click'); + const promotionEvent = findEventFromRequest( + fetchMock.calls(), + 'click', + ); - Should(promotionEvent).be.ok(); + Should(promotionEvent).be.ok(); - promotionEvent.data.promotion_action.should.have.property('action', PromotionActionType.PromotionClick); - promotionEvent.data.promotion_action.should.have.property('promotions'); - promotionEvent.data.promotion_action.promotions[0].should.have.property('id', '12345'); - promotionEvent.data.promotion_action.promotions[0].should.have.property('name', 'creative-name'); - promotionEvent.data.promotion_action.promotions[0].should.have.property('creative', 'my-creative'); - promotionEvent.data.promotion_action.promotions[0].should.have.property('position', 1); + promotionEvent.data.promotion_action.should.have.property( + 'action', + PromotionActionType.PromotionClick, + ); + promotionEvent.data.promotion_action.should.have.property( + 'promotions', + ); + promotionEvent.data.promotion_action.promotions[0].should.have.property( + 'id', + '12345', + ); + promotionEvent.data.promotion_action.promotions[0].should.have.property( + 'name', + 'creative-name', + ); + promotionEvent.data.promotion_action.promotions[0].should.have.property( + 'creative', + 'my-creative', + ); + promotionEvent.data.promotion_action.promotions[0].should.have.property( + 'position', + 1, + ); - done(); - }) + done(); + }); }); - it('should allow multiple promotions to be logged at once', function(done) { + it('should allow multiple promotions to be logged at once', function (done) { const promotion1 = mParticle.eCommerce.createPromotion( '12345', 'my-creative1', 'creative-name1', - 1 + 1, ); const promotion2 = mParticle.eCommerce.createPromotion( '67890', 'my-creative2', 'creative-name2', - 2 + 2, ); - waitForCondition(hasIdentifyReturned) - .then(() => { - mParticle.eCommerce.logPromotion( - mParticle.PromotionType.PromotionClick, - [promotion1, promotion2] - ); + waitForCondition(hasIdentifyReturned).then(() => { + mParticle.eCommerce.logPromotion( + mParticle.PromotionType.PromotionClick, + [promotion1, promotion2], + ); - const promotionEvent = findEventFromRequest(fetchMock.calls(), 'click'); + const promotionEvent = findEventFromRequest( + fetchMock.calls(), + 'click', + ); - Should(promotionEvent).be.ok(); + Should(promotionEvent).be.ok(); - promotionEvent.data.promotion_action.should.have.property('action', PromotionActionType.PromotionClick); - promotionEvent.data.promotion_action.should.have.property('promotions'); - promotionEvent.data.promotion_action.promotions.length.should.equal(2); - promotionEvent.data.promotion_action.promotions[0].should.have.property('id', '12345'); - promotionEvent.data.promotion_action.promotions[0].should.have.property('name', 'creative-name1'); - promotionEvent.data.promotion_action.promotions[0].should.have.property('creative', 'my-creative1'); - promotionEvent.data.promotion_action.promotions[0].should.have.property('position', 1); - promotionEvent.data.promotion_action.promotions[1].should.have.property('id', '67890'); - promotionEvent.data.promotion_action.promotions[1].should.have.property('name', 'creative-name2'); - promotionEvent.data.promotion_action.promotions[1].should.have.property('creative', 'my-creative2'); - promotionEvent.data.promotion_action.promotions[1].should.have.property('position', 2); + promotionEvent.data.promotion_action.should.have.property( + 'action', + PromotionActionType.PromotionClick, + ); + promotionEvent.data.promotion_action.should.have.property( + 'promotions', + ); + promotionEvent.data.promotion_action.promotions.length.should.equal( + 2, + ); + promotionEvent.data.promotion_action.promotions[0].should.have.property( + 'id', + '12345', + ); + promotionEvent.data.promotion_action.promotions[0].should.have.property( + 'name', + 'creative-name1', + ); + promotionEvent.data.promotion_action.promotions[0].should.have.property( + 'creative', + 'my-creative1', + ); + promotionEvent.data.promotion_action.promotions[0].should.have.property( + 'position', + 1, + ); + promotionEvent.data.promotion_action.promotions[1].should.have.property( + 'id', + '67890', + ); + promotionEvent.data.promotion_action.promotions[1].should.have.property( + 'name', + 'creative-name2', + ); + promotionEvent.data.promotion_action.promotions[1].should.have.property( + 'creative', + 'my-creative2', + ); + promotionEvent.data.promotion_action.promotions[1].should.have.property( + 'position', + 2, + ); - done(); - }) + done(); + }); }); it('should allow an promotions to bypass server upload', function (done) { @@ -402,30 +646,37 @@ describe('eCommerce', function() { '12345', 'my-creative', 'creative-name', - 1 + 1, ); - waitForCondition(hasIdentifyReturned) - .then(() => { - mParticle.eCommerce.logPromotion( - mParticle.PromotionType.PromotionClick, - promotion, - {}, {}, - { shouldUploadEvent: false } - ); + waitForCondition(hasIdentifyReturned).then(() => { + mParticle.eCommerce.logPromotion( + mParticle.PromotionType.PromotionClick, + promotion, + {}, + {}, + { shouldUploadEvent: false }, + ); - const promotionEvent = findEventFromRequest(fetchMock.calls(), 'click'); - Should(promotionEvent).not.be.ok(); + const promotionEvent = findEventFromRequest( + fetchMock.calls(), + 'click', + ); + Should(promotionEvent).not.be.ok(); - done(); - }) + done(); + }); }); - it('should create impression', function(done) { - const product = mParticle.eCommerce.createProduct('iPhone', '12345', 400), + it('should create impression', function (done) { + const product = mParticle.eCommerce.createProduct( + 'iPhone', + '12345', + 400, + ), impression = mParticle.eCommerce.createImpression( 'impression-name', - product + product, ); impression.should.have.property('Name', 'impression-name'); @@ -435,444 +686,681 @@ describe('eCommerce', function() { done(); }); - it('should log impression event', function(done) { - const product = mParticle.eCommerce.createProduct('iPhone', '12345', 400), + it('should log impression event', function (done) { + const product = mParticle.eCommerce.createProduct( + 'iPhone', + '12345', + 400, + ), impression = mParticle.eCommerce.createImpression( 'impression-name', - product + product, ); - waitForCondition(hasIdentifyReturned) - .then(() => { - mParticle.eCommerce.logImpression(impression); - const impressionEvent = findEventFromRequest(fetchMock.calls(), 'impression'); + waitForCondition(hasIdentifyReturned).then(() => { + mParticle.eCommerce.logImpression(impression); + const impressionEvent = findEventFromRequest( + fetchMock.calls(), + 'impression', + ); - Should(impressionEvent).be.ok(); + Should(impressionEvent).be.ok(); - impressionEvent.data.should.have.property('product_impressions').with.lengthOf(1); - impressionEvent.data.product_impressions[0].should.have.property('product_impression_list', 'impression-name'); - impressionEvent.data.product_impressions[0].should.have.property('products').with.lengthOf(1); - impressionEvent.data.product_impressions[0].products[0].should.have.property('id', '12345'); + impressionEvent.data.should.have + .property('product_impressions') + .with.lengthOf(1); + impressionEvent.data.product_impressions[0].should.have.property( + 'product_impression_list', + 'impression-name', + ); + impressionEvent.data.product_impressions[0].should.have + .property('products') + .with.lengthOf(1); + impressionEvent.data.product_impressions[0].products[0].should.have.property( + 'id', + '12345', + ); - done(); - }) + done(); + }); }); it('should allow an impression to bypass server upload', function (done) { - waitForCondition(hasIdentifyReturned) - .then(() => { - const product = mParticle.eCommerce.createProduct('iPhone', '12345', 400), - impression = mParticle.eCommerce.createImpression( - 'impression-name', - product + waitForCondition(hasIdentifyReturned).then(() => { + const product = mParticle.eCommerce.createProduct( + 'iPhone', + '12345', + 400, + ), + impression = mParticle.eCommerce.createImpression( + 'impression-name', + product, + ); + + mParticle.eCommerce.logImpression(impression, null, null, { + shouldUploadEvent: false, + }); + + const impressionEvent = findEventFromRequest( + fetchMock.calls(), + 'impression', ); - mParticle.eCommerce.logImpression(impression, null, null, { shouldUploadEvent: false }); - - const impressionEvent = findEventFromRequest(fetchMock.calls(), 'impression'); + Should(impressionEvent).not.be.ok(); - Should(impressionEvent).not.be.ok(); - - done(); - }) + done(); + }); }); - it('should log multiple impression when an array of impressions is passed', function(done) { - waitForCondition(hasIdentifyReturned) - .then(() => { - const product = mParticle.eCommerce.createProduct('iPhone', '12345', 400), - impression = mParticle.eCommerce.createImpression( - 'impression-name1', - product - ), - product2 = mParticle.eCommerce.createProduct( - 'Android', - '23456', - 200 - ), - impression2 = mParticle.eCommerce.createImpression( - 'impression-name2', - product2 + it('should log multiple impression when an array of impressions is passed', function (done) { + waitForCondition(hasIdentifyReturned).then(() => { + const product = mParticle.eCommerce.createProduct( + 'iPhone', + '12345', + 400, + ), + impression = mParticle.eCommerce.createImpression( + 'impression-name1', + product, + ), + product2 = mParticle.eCommerce.createProduct( + 'Android', + '23456', + 200, + ), + impression2 = mParticle.eCommerce.createImpression( + 'impression-name2', + product2, + ); + + mParticle.eCommerce.logImpression([impression, impression2]); + + const impressionEvent = findEventFromRequest( + fetchMock.calls(), + 'impression', ); - mParticle.eCommerce.logImpression([impression, impression2]); - - const impressionEvent = findEventFromRequest(fetchMock.calls(), 'impression'); + Should(impressionEvent).be.ok(); - Should(impressionEvent).be.ok(); + impressionEvent.data.should.have + .property('product_impressions') + .with.lengthOf(2); - impressionEvent.data.should.have.property('product_impressions').with.lengthOf(2); - - impressionEvent.data.product_impressions[0].should.have.property('product_impression_list', 'impression-name1'); - impressionEvent.data.product_impressions[0].should.have.property('products').with.lengthOf(1); - impressionEvent.data.product_impressions[0].products[0].should.have.property('id', '12345'); + impressionEvent.data.product_impressions[0].should.have.property( + 'product_impression_list', + 'impression-name1', + ); + impressionEvent.data.product_impressions[0].should.have + .property('products') + .with.lengthOf(1); + impressionEvent.data.product_impressions[0].products[0].should.have.property( + 'id', + '12345', + ); - impressionEvent.data.product_impressions[1].should.have.property('product_impression_list', 'impression-name2'); - impressionEvent.data.product_impressions[1].should.have.property('products').with.lengthOf(1); - impressionEvent.data.product_impressions[1].products[0].should.have.property('id', '23456'); + impressionEvent.data.product_impressions[1].should.have.property( + 'product_impression_list', + 'impression-name2', + ); + impressionEvent.data.product_impressions[1].should.have + .property('products') + .with.lengthOf(1); + impressionEvent.data.product_impressions[1].products[0].should.have.property( + 'id', + '23456', + ); - done(); - }) + done(); + }); }); - it('should log ecommerce refund', function(done) { - waitForCondition(hasIdentifyReturned) - .then(() => { - const product = mParticle.eCommerce.createProduct( - 'iPhone', - '12345', - 400, - 2, - 'Apple', - 'Plus', - 'Phones' - ), - transactionAttributes = mParticle.eCommerce.createTransactionAttributes( - '12345', - 'test-affiliation', - 'coupon-code', - 44334, - 600, - 200 - ); - - mParticle.eCommerce.logRefund(transactionAttributes, product); - - - const refundEvent = findEventFromRequest(fetchMock.calls(), 'refund'); - - Should(refundEvent).be.ok(); - - refundEvent.data.should.have.property('product_action'); + it('should log ecommerce refund', function (done) { + waitForCondition(hasIdentifyReturned).then(() => { + const product = mParticle.eCommerce.createProduct( + 'iPhone', + '12345', + 400, + 2, + 'Apple', + 'Plus', + 'Phones', + ), + transactionAttributes = + mParticle.eCommerce.createTransactionAttributes( + '12345', + 'test-affiliation', + 'coupon-code', + 44334, + 600, + 200, + ); + + mParticle.eCommerce.logRefund(transactionAttributes, product); + + const refundEvent = findEventFromRequest( + fetchMock.calls(), + 'refund', + ); - refundEvent.data.product_action.should.have.property('action', 'refund'); - refundEvent.data.product_action.should.have.property('transaction_id', '12345'); - refundEvent.data.product_action.should.have.property('affiliation', 'test-affiliation'); - refundEvent.data.product_action.should.have.property('coupon_code', 'coupon-code'); - refundEvent.data.product_action.should.have.property('total_amount', 44334); - refundEvent.data.product_action.should.have.property('shipping_amount', 600); - refundEvent.data.product_action.should.have.property('tax_amount', 200); - refundEvent.data.product_action.products.should.have.length(1); - refundEvent.data.product_action.products[0].should.have.property('id', '12345') - refundEvent.data.product_action.products[0].should.have.property('name', 'iPhone') - refundEvent.data.product_action.products[0].should.have.property('price', 400) - refundEvent.data.product_action.products[0].should.have.property('quantity', 2) - refundEvent.data.product_action.products[0].should.have.property('brand', 'Phones') - refundEvent.data.product_action.products[0].should.have.property('variant', 'Apple') - refundEvent.data.product_action.products[0].should.have.property('category', 'Plus') - refundEvent.data.product_action.products[0].should.have.property('total_product_amount', 800) + Should(refundEvent).be.ok(); - done(); - }) - }); + refundEvent.data.should.have.property('product_action'); - it('should log identical events for logRefund and logProductAction with a product action of `refund`', function(done) { - waitForCondition(hasIdentifyReturned) - .then(() => { - const product = mParticle.eCommerce.createProduct( - 'iPhone', - '12345', - '400', - 2, - 'Plus', - 'Phones', - 'Apple', - 1, - 'my-coupon-code', - { customkey: 'customvalue' } - ), - transactionAttributes = mParticle.eCommerce.createTransactionAttributes( - '12345', - 'test-affiliation', - 'coupon-code', - 44334, - 600, - 200 - ); + refundEvent.data.product_action.should.have.property( + 'action', + 'refund', + ); + refundEvent.data.product_action.should.have.property( + 'transaction_id', + '12345', + ); + refundEvent.data.product_action.should.have.property( + 'affiliation', + 'test-affiliation', + ); + refundEvent.data.product_action.should.have.property( + 'coupon_code', + 'coupon-code', + ); + refundEvent.data.product_action.should.have.property( + 'total_amount', + 44334, + ); + refundEvent.data.product_action.should.have.property( + 'shipping_amount', + 600, + ); + refundEvent.data.product_action.should.have.property( + 'tax_amount', + 200, + ); + refundEvent.data.product_action.products.should.have.length(1); + refundEvent.data.product_action.products[0].should.have.property( + 'id', + '12345', + ); + refundEvent.data.product_action.products[0].should.have.property( + 'name', + 'iPhone', + ); + refundEvent.data.product_action.products[0].should.have.property( + 'price', + 400, + ); + refundEvent.data.product_action.products[0].should.have.property( + 'quantity', + 2, + ); + refundEvent.data.product_action.products[0].should.have.property( + 'brand', + 'Phones', + ); + refundEvent.data.product_action.products[0].should.have.property( + 'variant', + 'Apple', + ); + refundEvent.data.product_action.products[0].should.have.property( + 'category', + 'Plus', + ); + refundEvent.data.product_action.products[0].should.have.property( + 'total_product_amount', + 800, + ); - mParticle.eCommerce.logRefund(transactionAttributes, product); - - const refundEvent1 = findEventFromRequest(fetchMock.calls(), 'refund'); + done(); + }); + }); - fetchMock.resetHistory(); - - mParticle.eCommerce.logProductAction(mParticle.ProductActionType.Refund, product, null, null, transactionAttributes) - - const refundEvent2 = findEventFromRequest(fetchMock.calls(), 'refund'); - - Should(refundEvent1).be.ok(); - Should(refundEvent2).be.ok(); - - refundEvent1.data.product_action.action.should.equal(refundEvent2.data.product_action.action); - refundEvent1.data.product_action.transaction_id.should.equal(refundEvent2.data.product_action.transaction_id); - refundEvent1.data.product_action.affiliation.should.equal(refundEvent2.data.product_action.affiliation); - refundEvent1.data.product_action.coupon_code.should.equal(refundEvent2.data.product_action.coupon_code); - refundEvent1.data.product_action.total_amount.should.equal(refundEvent2.data.product_action.total_amount); - refundEvent1.data.product_action.shipping_amount.should.equal(refundEvent2.data.product_action.shipping_amount); - refundEvent1.data.product_action.tax_amount.should.equal(refundEvent2.data.product_action.tax_amount); - refundEvent1.data.product_action.products.length.should.equal(refundEvent2.data.product_action.products.length) - - refundEvent1.data.product_action.products[0].id.should.equal(refundEvent2.data.product_action.products[0].id) - refundEvent1.data.product_action.products[0].price.should.equal(refundEvent2.data.product_action.products[0].price) - refundEvent1.data.product_action.products[0].quantity.should.equal(refundEvent2.data.product_action.products[0].quantity) - refundEvent1.data.product_action.products[0].brand.should.equal(refundEvent2.data.product_action.products[0].brand) - refundEvent1.data.product_action.products[0].variant.should.equal(refundEvent2.data.product_action.products[0].variant) - refundEvent1.data.product_action.products[0].category.should.equal(refundEvent2.data.product_action.products[0].category) - refundEvent1.data.product_action.products[0].position.should.equal(refundEvent2.data.product_action.products[0].position) + it('should log identical events for logRefund and logProductAction with a product action of `refund`', function (done) { + waitForCondition(hasIdentifyReturned).then(() => { + const product = mParticle.eCommerce.createProduct( + 'iPhone', + '12345', + '400', + 2, + 'Plus', + 'Phones', + 'Apple', + 1, + 'my-coupon-code', + { customkey: 'customvalue' }, + ), + transactionAttributes = + mParticle.eCommerce.createTransactionAttributes( + '12345', + 'test-affiliation', + 'coupon-code', + 44334, + 600, + 200, + ); + + mParticle.eCommerce.logRefund(transactionAttributes, product); + + const refundEvent1 = findEventFromRequest( + fetchMock.calls(), + 'refund', + ); - done(); - }) + fetchMock.resetHistory(); + + mParticle.eCommerce.logProductAction( + mParticle.ProductActionType.Refund, + product, + null, + null, + transactionAttributes, + ); + + const refundEvent2 = findEventFromRequest( + fetchMock.calls(), + 'refund', + ); + + Should(refundEvent1).be.ok(); + Should(refundEvent2).be.ok(); + + refundEvent1.data.product_action.action.should.equal( + refundEvent2.data.product_action.action, + ); + refundEvent1.data.product_action.transaction_id.should.equal( + refundEvent2.data.product_action.transaction_id, + ); + refundEvent1.data.product_action.affiliation.should.equal( + refundEvent2.data.product_action.affiliation, + ); + refundEvent1.data.product_action.coupon_code.should.equal( + refundEvent2.data.product_action.coupon_code, + ); + refundEvent1.data.product_action.total_amount.should.equal( + refundEvent2.data.product_action.total_amount, + ); + refundEvent1.data.product_action.shipping_amount.should.equal( + refundEvent2.data.product_action.shipping_amount, + ); + refundEvent1.data.product_action.tax_amount.should.equal( + refundEvent2.data.product_action.tax_amount, + ); + refundEvent1.data.product_action.products.length.should.equal( + refundEvent2.data.product_action.products.length, + ); + + refundEvent1.data.product_action.products[0].id.should.equal( + refundEvent2.data.product_action.products[0].id, + ); + refundEvent1.data.product_action.products[0].price.should.equal( + refundEvent2.data.product_action.products[0].price, + ); + refundEvent1.data.product_action.products[0].quantity.should.equal( + refundEvent2.data.product_action.products[0].quantity, + ); + refundEvent1.data.product_action.products[0].brand.should.equal( + refundEvent2.data.product_action.products[0].brand, + ); + refundEvent1.data.product_action.products[0].variant.should.equal( + refundEvent2.data.product_action.products[0].variant, + ); + refundEvent1.data.product_action.products[0].category.should.equal( + refundEvent2.data.product_action.products[0].category, + ); + refundEvent1.data.product_action.products[0].position.should.equal( + refundEvent2.data.product_action.products[0].position, + ); + + done(); + }); }); it('should allow a product action to bypass server upload', function (done) { - waitForCondition(hasIdentifyReturned) - .then(() => { - const product = mParticle.eCommerce.createProduct( - 'iPhone', - '12345', - '400', - 2, - 'Plus', - 'Phones', - 'Apple', - 1, - 'my-coupon-code', - { customkey: 'customvalue' } - ), - transactionAttributes = mParticle.eCommerce.createTransactionAttributes( - '12345', - 'test-affiliation', - 'coupon-code', - 44334, - 600, - 200 - ); + waitForCondition(hasIdentifyReturned).then(() => { + const product = mParticle.eCommerce.createProduct( + 'iPhone', + '12345', + '400', + 2, + 'Plus', + 'Phones', + 'Apple', + 1, + 'my-coupon-code', + { customkey: 'customvalue' }, + ), + transactionAttributes = + mParticle.eCommerce.createTransactionAttributes( + '12345', + 'test-affiliation', + 'coupon-code', + 44334, + 600, + 200, + ); - mParticle.eCommerce.logProductAction( - mParticle.ProductActionType.Purchase, - product, - null, - null, - transactionAttributes, - { shouldUploadEvent: false} - ); + mParticle.eCommerce.logProductAction( + mParticle.ProductActionType.Purchase, + product, + null, + null, + transactionAttributes, + { shouldUploadEvent: false }, + ); - const event = findEventFromRequest(fetchMock.calls(), 'purchase'); + const event = findEventFromRequest(fetchMock.calls(), 'purchase'); - Should(event).not.be.ok(); - done(); - }) + Should(event).not.be.ok(); + done(); + }); }); - it('should add products to cart', function(done) { - waitForCondition(hasIdentifyReturned) - .then(() => { - const product = mParticle.eCommerce.createProduct('iPhone', '12345', 400); + it('should add products to cart', function (done) { + waitForCondition(hasIdentifyReturned).then(() => { + const product = mParticle.eCommerce.createProduct( + 'iPhone', + '12345', + 400, + ); + + mParticle.eCommerce.Cart.add(product, true); - mParticle.eCommerce.Cart.add(product, true); + const addToCartEvent = findEventFromRequest( + fetchMock.calls(), + 'add_to_cart', + ); - const addToCartEvent = findEventFromRequest(fetchMock.calls(), 'add_to_cart'); - - addToCartEvent.data.should.have.property('product_action'); - addToCartEvent.data.product_action.should.have.property('action', 'add_to_cart'); - addToCartEvent.data.product_action.should.have.property('products').with.lengthOf(1); - addToCartEvent.data.product_action.products[0].should.have.property('id', '12345'); + addToCartEvent.data.should.have.property('product_action'); + addToCartEvent.data.product_action.should.have.property( + 'action', + 'add_to_cart', + ); + addToCartEvent.data.product_action.should.have + .property('products') + .with.lengthOf(1); + addToCartEvent.data.product_action.products[0].should.have.property( + 'id', + '12345', + ); - done(); - }) + done(); + }); }); - it('should remove products to cart', function(done) { - waitForCondition(hasIdentifyReturned) - .then(() => { - const product = mParticle.eCommerce.createProduct('iPhone', '12345', 400); + it('should remove products to cart', function (done) { + waitForCondition(hasIdentifyReturned).then(() => { + const product = mParticle.eCommerce.createProduct( + 'iPhone', + '12345', + 400, + ); - mParticle.eCommerce.Cart.add(product); - mParticle.eCommerce.Cart.remove({ Sku: '12345' }, true); + mParticle.eCommerce.Cart.add(product); + mParticle.eCommerce.Cart.remove({ Sku: '12345' }, true); - const removeFromCartEvent = findEventFromRequest(fetchMock.calls(), 'remove_from_cart'); - - removeFromCartEvent.data.should.have.property('product_action'); - removeFromCartEvent.data.product_action.should.have.property('action', 'remove_from_cart'); - removeFromCartEvent.data.product_action.should.have.property('products').with.lengthOf(1); - removeFromCartEvent.data.product_action.products[0].should.have.property('id', '12345'); + const removeFromCartEvent = findEventFromRequest( + fetchMock.calls(), + 'remove_from_cart', + ); - done(); - }) + removeFromCartEvent.data.should.have.property('product_action'); + removeFromCartEvent.data.product_action.should.have.property( + 'action', + 'remove_from_cart', + ); + removeFromCartEvent.data.product_action.should.have + .property('products') + .with.lengthOf(1); + removeFromCartEvent.data.product_action.products[0].should.have.property( + 'id', + '12345', + ); + + done(); + }); }); - it('should update cart products in cookies after adding/removing product to/from a cart and clearing cart', function(done) { - waitForCondition(hasIdentifyReturned) - .then(() => { - const product = mParticle.eCommerce.createProduct('iPhone', '12345', 400); + it('should update cart products in cookies after adding/removing product to/from a cart and clearing cart', function (done) { + waitForCondition(hasIdentifyReturned).then(() => { + const product = mParticle.eCommerce.createProduct( + 'iPhone', + '12345', + 400, + ); - mParticle.eCommerce.Cart.add(product); - const products1 = getLocalStorageProducts(); + mParticle.eCommerce.Cart.add(product); + const products1 = getLocalStorageProducts(); - products1[testMPID].cp[0].should.have.properties([ - 'Name', - 'Sku', - 'Price', - ]); + products1[testMPID].cp[0].should.have.properties([ + 'Name', + 'Sku', + 'Price', + ]); - mParticle.eCommerce.Cart.remove(product); - const products2 = getLocalStorageProducts(); - products2[testMPID].cp.length.should.equal(0); + mParticle.eCommerce.Cart.remove(product); + const products2 = getLocalStorageProducts(); + products2[testMPID].cp.length.should.equal(0); - mParticle.eCommerce.Cart.add(product); - const products3 = getLocalStorageProducts(); - products3[testMPID].cp[0].should.have.properties([ - 'Name', - 'Sku', - 'Price', - ]); + mParticle.eCommerce.Cart.add(product); + const products3 = getLocalStorageProducts(); + products3[testMPID].cp[0].should.have.properties([ + 'Name', + 'Sku', + 'Price', + ]); - mParticle.eCommerce.Cart.clear(); - const products4 = getLocalStorageProducts(); - products4[testMPID].cp.length.should.equal(0); + mParticle.eCommerce.Cart.clear(); + const products4 = getLocalStorageProducts(); + products4[testMPID].cp.length.should.equal(0); - done(); - }) + done(); + }); }); - it('should not add the (config.maxProducts + 1st) item to cookie cartItems and only send cookie cartProducts when logging', function(done) { - waitForCondition(hasIdentifyReturned) - .then(() => { - mParticle.config.maxProducts = 10; - mParticle.config.workspaceToken = workspaceToken; - mParticle.init(apiKey, window.mParticle.config); + it('should not add the (config.maxProducts + 1st) item to cookie cartItems and only send cookie cartProducts when logging', function (done) { + waitForCondition(hasIdentifyReturned).then(() => { + mParticle.config.maxProducts = 10; + mParticle.config.workspaceToken = workspaceToken; + mParticle.init(apiKey, window.mParticle.config); - const product = mParticle.eCommerce.createProduct( - 'Product', - '12345', - 400 - ); - for (let i = 0; i < mParticle.config.maxProducts; i++) { - mParticle.eCommerce.Cart.add(product); - } + const product = mParticle.eCommerce.createProduct( + 'Product', + '12345', + 400, + ); + for (let i = 0; i < mParticle.config.maxProducts; i++) { + mParticle.eCommerce.Cart.add(product); + } - mParticle.eCommerce.Cart.add( - mParticle.eCommerce.createProduct('Product11', '12345', 400) - ); - const products1 = getLocalStorageProducts(); + mParticle.eCommerce.Cart.add( + mParticle.eCommerce.createProduct('Product11', '12345', 400), + ); + const products1 = getLocalStorageProducts(); - const foundProductInCookies = products1[testMPID].cp.filter(function( - product - ) { - return product.Name === 'Product11'; - })[0]; + const foundProductInCookies = products1[testMPID].cp.filter( + function (product) { + return product.Name === 'Product11'; + }, + )[0]; - products1[testMPID].cp.length.should.equal(10); - Should(foundProductInCookies).be.ok(); + products1[testMPID].cp.length.should.equal(10); + Should(foundProductInCookies).be.ok(); - done(); - }) + done(); + }); }); - it('should log checkout via deprecated logCheckout method', function(done) { - waitForCondition(hasIdentifyReturned) - .then(() => { - const bond = sinon.spy(mParticle.getInstance().Logger, 'warning'); + it('should log checkout via deprecated logCheckout method', function (done) { + waitForCondition(hasIdentifyReturned).then(() => { + const bond = sinon.spy(mParticle.getInstance().Logger, 'warning'); - mParticle.eCommerce.logCheckout(1, 'Visa'); + mParticle.eCommerce.logCheckout(1, 'Visa'); - const checkoutEvent = findEventFromRequest(fetchMock.calls(), 'checkout'); + const checkoutEvent = findEventFromRequest( + fetchMock.calls(), + 'checkout', + ); - Should(checkoutEvent).be.ok(); + Should(checkoutEvent).be.ok(); - bond.called.should.eql(true); - bond.getCalls()[0].args[0].should.eql( - 'mParticle.logCheckout is deprecated, please use mParticle.logProductAction instead' - ); + bond.called.should.eql(true); + bond.getCalls()[0].args[0].should.eql( + 'mParticle.logCheckout is deprecated, please use mParticle.logProductAction instead', + ); - checkoutEvent.should.have.property('event_type', 'commerce_event'); - checkoutEvent.data.should.have.property('product_action'); + checkoutEvent.should.have.property('event_type', 'commerce_event'); + checkoutEvent.data.should.have.property('product_action'); - checkoutEvent.data.product_action.should.have.property('action', 'checkout'); - checkoutEvent.data.product_action.should.have.property('checkout_step', 1); - checkoutEvent.data.product_action.should.have.property('checkout_options', 'Visa'); + checkoutEvent.data.product_action.should.have.property( + 'action', + 'checkout', + ); + checkoutEvent.data.product_action.should.have.property( + 'checkout_step', + 1, + ); + checkoutEvent.data.product_action.should.have.property( + 'checkout_options', + 'Visa', + ); - done(); - }) + done(); + }); }); - it('should log checkout via mParticle.logProductAction method', function(done) { - waitForCondition(hasIdentifyReturned) - .then(() => { - const product1 = mParticle.eCommerce.createProduct('iphone', 'iphoneSKU', 999); - const product2 = mParticle.eCommerce.createProduct('galaxy', 'galaxySKU', 799); + it('should log checkout via mParticle.logProductAction method', function (done) { + waitForCondition(hasIdentifyReturned).then(() => { + const product1 = mParticle.eCommerce.createProduct( + 'iphone', + 'iphoneSKU', + 999, + ); + const product2 = mParticle.eCommerce.createProduct( + 'galaxy', + 'galaxySKU', + 799, + ); - mParticle.eCommerce.logProductAction(mParticle.ProductActionType.Checkout, [product1, product2], null, null, {Step: 4, Option: 'Visa'}); + mParticle.eCommerce.logProductAction( + mParticle.ProductActionType.Checkout, + [product1, product2], + null, + null, + { Step: 4, Option: 'Visa' }, + ); - const checkoutEvent = findEventFromRequest(fetchMock.calls(), 'checkout'); + const checkoutEvent = findEventFromRequest( + fetchMock.calls(), + 'checkout', + ); - Should(checkoutEvent).be.ok(); + Should(checkoutEvent).be.ok(); - checkoutEvent.should.have.property('event_type', 'commerce_event'); - checkoutEvent.data.should.have.property('product_action'); + checkoutEvent.should.have.property('event_type', 'commerce_event'); + checkoutEvent.data.should.have.property('product_action'); - checkoutEvent.data.product_action.should.have.property('action', 'checkout'); - checkoutEvent.data.product_action.should.have.property('checkout_step', 4); - checkoutEvent.data.product_action.should.have.property('checkout_options', 'Visa'); - checkoutEvent.data.product_action.products[0].should.have.property('id', 'iphoneSKU'); - checkoutEvent.data.product_action.products[1].should.have.property('id', 'galaxySKU'); + checkoutEvent.data.product_action.should.have.property( + 'action', + 'checkout', + ); + checkoutEvent.data.product_action.should.have.property( + 'checkout_step', + 4, + ); + checkoutEvent.data.product_action.should.have.property( + 'checkout_options', + 'Visa', + ); + checkoutEvent.data.product_action.products[0].should.have.property( + 'id', + 'iphoneSKU', + ); + checkoutEvent.data.product_action.products[1].should.have.property( + 'id', + 'galaxySKU', + ); - done(); - }) + done(); + }); }); - it('should log checkout option', function(done) { - waitForCondition(hasIdentifyReturned) - .then(() => { - const product = mParticle.eCommerce.createProduct('iPhone', '12345', 400); - - mParticle.eCommerce.logProductAction( - ProductActionType.CheckoutOption, - product, - { color: 'blue' } - ); + it('should log checkout option', function (done) { + waitForCondition(hasIdentifyReturned).then(() => { + const product = mParticle.eCommerce.createProduct( + 'iPhone', + '12345', + 400, + ); - const checkoutOptionEvent = findEventFromRequest(fetchMock.calls(), 'checkout_option'); + mParticle.eCommerce.logProductAction( + ProductActionType.CheckoutOption, + product, + { color: 'blue' }, + ); + const checkoutOptionEvent = findEventFromRequest( + fetchMock.calls(), + 'checkout_option', + ); - Should(checkoutOptionEvent).be.ok(); + Should(checkoutOptionEvent).be.ok(); - checkoutOptionEvent.should.have.property( - 'event_type', - 'commerce_event' - ); - checkoutOptionEvent.data.should.have.property('product_action'); + checkoutOptionEvent.should.have.property( + 'event_type', + 'commerce_event', + ); + checkoutOptionEvent.data.should.have.property('product_action'); - checkoutOptionEvent.data.product_action.should.have.property('action', 'checkout_option'); - checkoutOptionEvent.data.custom_attributes.should.have.property('color', 'blue'); - done(); - }) + checkoutOptionEvent.data.product_action.should.have.property( + 'action', + 'checkout_option', + ); + checkoutOptionEvent.data.custom_attributes.should.have.property( + 'color', + 'blue', + ); + done(); + }); }); - it('should log product action', function(done) { - waitForCondition(hasIdentifyReturned) - .then(() => { - const product = mParticle.eCommerce.createProduct('iPhone', '12345', 400); + it('should log product action', function (done) { + waitForCondition(hasIdentifyReturned).then(() => { + const product = mParticle.eCommerce.createProduct( + 'iPhone', + '12345', + 400, + ); - mParticle.eCommerce.logProductAction( - ProductActionType.ViewDetail, - product - ); + mParticle.eCommerce.logProductAction( + ProductActionType.ViewDetail, + product, + ); - const viewDetailEvent = findEventFromRequest(fetchMock.calls(), 'view_detail'); - Should(viewDetailEvent).be.ok(); - - viewDetailEvent.should.have.property('event_type', 'commerce_event'); - viewDetailEvent.data.should.have.property('product_action'); - viewDetailEvent.data.product_action.should.have.property('action', 'view_detail'); - viewDetailEvent.data.product_action.should.have.property('products').with.lengthOf(1); - viewDetailEvent.data.product_action.products[0].should.have.property('id', '12345'); + const viewDetailEvent = findEventFromRequest( + fetchMock.calls(), + 'view_detail', + ); + Should(viewDetailEvent).be.ok(); - done(); - }) + viewDetailEvent.should.have.property( + 'event_type', + 'commerce_event', + ); + viewDetailEvent.data.should.have.property('product_action'); + viewDetailEvent.data.product_action.should.have.property( + 'action', + 'view_detail', + ); + viewDetailEvent.data.product_action.should.have + .property('products') + .with.lengthOf(1); + viewDetailEvent.data.product_action.products[0].should.have.property( + 'id', + '12345', + ); + + done(); + }); }); - it('should fail to create product if name not a string', function(done) { + it('should fail to create product if name not a string', function (done) { const product = mParticle.eCommerce.createProduct(null); const product2 = mParticle.eCommerce.createProduct(undefined); const product3 = mParticle.eCommerce.createProduct(['product']); @@ -888,7 +1376,7 @@ describe('eCommerce', function() { done(); }); - it('should fail to create product if sku not a string or a number', function(done) { + it('should fail to create product if sku not a string or a number', function (done) { const product = mParticle.eCommerce.createProduct('test', null); const product2 = mParticle.eCommerce.createProduct('test', { key: 'value', @@ -904,7 +1392,7 @@ describe('eCommerce', function() { done(); }); - it('should fail to create product if price not a string or number', function(done) { + it('should fail to create product if price not a string or number', function (done) { const product = mParticle.eCommerce.createProduct('test', 'sku', null); const product2 = mParticle.eCommerce.createProduct('test', 'sku', null); const product3 = mParticle.eCommerce.createProduct('test', 'sku', null); @@ -918,7 +1406,7 @@ describe('eCommerce', function() { done(); }); - it('should fail to create impression if name is not specified', function(done) { + it('should fail to create impression if name is not specified', function (done) { const impression = mParticle.eCommerce.createImpression(null); Should(impression).not.be.ok(); @@ -926,7 +1414,7 @@ describe('eCommerce', function() { done(); }); - it('should fail to create impression if product is not specified', function(done) { + it('should fail to create impression if product is not specified', function (done) { const impression = mParticle.eCommerce.createImpression('name', null); Should(impression).not.be.ok(); @@ -934,878 +1422,1012 @@ describe('eCommerce', function() { done(); }); - it('should set product position to 0 if null', function(done) { - waitForCondition(hasIdentifyReturned) - .then(() => { - const product = mParticle.eCommerce.createProduct( - 'iPhone', - '12345', - 400, - 2, - 'Apple', - 'Plus', - 'Phones' - ), - transactionAttributes = mParticle.eCommerce.createTransactionAttributes( - '12345', - 'test-affiliation', - 'coupon-code', - 44334, - 600, - 200 + it('should set product position to 0 if null', function (done) { + waitForCondition(hasIdentifyReturned).then(() => { + const product = mParticle.eCommerce.createProduct( + 'iPhone', + '12345', + 400, + 2, + 'Apple', + 'Plus', + 'Phones', + ), + transactionAttributes = + mParticle.eCommerce.createTransactionAttributes( + '12345', + 'test-affiliation', + 'coupon-code', + 44334, + 600, + 200, + ); + + mParticle.eCommerce.logPurchase(transactionAttributes, product); + const purchaseEvent = findEventFromRequest( + fetchMock.calls(), + 'purchase', ); - mParticle.eCommerce.logPurchase(transactionAttributes, product); - const purchaseEvent = findEventFromRequest(fetchMock.calls(), 'purchase'); - - purchaseEvent.data.product_action.products[0].should.not.have.property('position'); - - - done(); - }) - }); - - it('should support array of products when adding to cart', function(done) { - waitForCondition(hasIdentifyReturned) - .then(() => { - const product1 = mParticle.eCommerce.createProduct( - 'iPhone', - '12345', - 400, - 2 - ), - product2 = mParticle.eCommerce.createProduct( - 'Nexus', - '67890', - 300, - 1 + purchaseEvent.data.product_action.products[0].should.not.have.property( + 'position', ); - mParticle.eCommerce.Cart.add([product1, product2], true); - - const addToCartEvent = findEventFromRequest(fetchMock.calls(), 'add_to_cart'); - - Should(addToCartEvent).be.ok(); - - addToCartEvent.data.should.have.property('product_action'); - addToCartEvent.data.product_action.should.have.property('action', 'add_to_cart'); - addToCartEvent.data.product_action.should.have.property('products').with.lengthOf(2); - - addToCartEvent.data.product_action.products[0].should.have.property('id', '12345'); - addToCartEvent.data.product_action.products[0].should.have.property('name', 'iPhone'); - - addToCartEvent.data.product_action.products[1].should.have.property('id', '67890'); - addToCartEvent.data.product_action.products[1].should.have.property('name', 'Nexus'); - - done(); - }) - }); - - it('should support a single product when adding to cart', function(done) { - waitForCondition(hasIdentifyReturned) - .then(() => { - const product1 = mParticle.eCommerce.createProduct( - 'iPhone', - '12345', - 400, - 2 - ); - - mParticle.eCommerce.Cart.add(product1, true); - - const addToCartEvent = findEventFromRequest(fetchMock.calls(), 'add_to_cart'); - - Should(addToCartEvent).be.ok(); - - addToCartEvent.data.should.have.property('product_action'); - addToCartEvent.data.product_action.should.have.property('action', 'add_to_cart'); - addToCartEvent.data.product_action.should.have.property('products').with.lengthOf(1); - - addToCartEvent.data.product_action.products[0].should.have.property('id', '12345'); - addToCartEvent.data.product_action.products[0].should.have.property('name', 'iPhone'); - - done(); - }) + done(); + }); }); - it('expand product purchase commerce event', function(done) { - waitForCondition(hasIdentifyReturned) - .then(() => { - mParticle._resetForTests(MPConfig); - const mockForwarder = new MockForwarder(); - mockForwarder.register(window.mParticle.config); - const config1 = forwarderDefaultConfiguration('MockForwarder', 1); - window.mParticle.config.kitConfigs.push(config1); - - - mParticle.init(apiKey, window.mParticle.config); - waitForCondition(() => { - return ( - mParticle.getInstance()._Store.identityCallInFlight === false + it('should support array of products when adding to cart', function (done) { + waitForCondition(hasIdentifyReturned).then(() => { + const product1 = mParticle.eCommerce.createProduct( + 'iPhone', + '12345', + 400, + 2, + ), + product2 = mParticle.eCommerce.createProduct( + 'Nexus', + '67890', + 300, + 1, + ); + + mParticle.eCommerce.Cart.add([product1, product2], true); + + const addToCartEvent = findEventFromRequest( + fetchMock.calls(), + 'add_to_cart', ); - }) - .then(() => { - mParticle.eCommerce.setCurrencyCode('foo-currency'); - const productAttributes = {}; - productAttributes['foo-attribute-key'] = 'foo-product-attribute-value'; - const eventAttributes = {}; - eventAttributes['foo-event-attribute-key'] = - 'foo-event-attribute-value'; + Should(addToCartEvent).be.ok(); - const product = mParticle.eCommerce.createProduct( - 'Foo name', - 'Foo sku', - 100.0, - 4, - 'foo-variant', - 'foo-category', - 'foo-brand', - 5, - 'foo-productcouponcode', - productAttributes - ); - - const transactionAttributes = mParticle.eCommerce.createTransactionAttributes( - 'foo-transaction-id', - 'foo-affiliation', - 'foo-couponcode', - 400, - 10, - 8 - ); - mParticle.eCommerce.logPurchase( - transactionAttributes, - product, - false, - eventAttributes - ); - window.MockForwarder1.instance.receivedEvent.should.have.property( - 'ProductAction' - ); - const expandedEvents = mParticle.eCommerce.expandCommerceEvent( - window.MockForwarder1.instance.receivedEvent - ); - expandedEvents.should.be.instanceof(Array).and.have.lengthOf(2); - - const plusOneEvent = expandedEvents[0]; - plusOneEvent.should.have.property( - 'EventName', - 'eCommerce - purchase - Total' - ); - plusOneEvent.should.have.property( - 'EventCategory', - mParticle.EventType.Transaction - ); - let attributes = plusOneEvent.EventAttributes; - attributes.should.have.property('Transaction Id', 'foo-transaction-id'); - attributes.should.have.property('Affiliation', 'foo-affiliation'); - attributes.should.have.property('Coupon Code', 'foo-couponcode'); - attributes.should.have.property('Total Amount', 400); - attributes.should.have.property('Shipping Amount', 10); - attributes.should.have.property('Product Count', 1); - attributes.should.have.property('Tax Amount', 8); - attributes.should.have.property('Currency Code', 'foo-currency'); - attributes.should.have.property( - 'foo-event-attribute-key', - 'foo-event-attribute-value' - ); - - const productEvent = expandedEvents[1]; - productEvent.should.have.property( - 'EventName', - 'eCommerce - purchase - Item' - ); - productEvent.should.have.property( - 'EventCategory', - mParticle.EventType.Transaction - ); - attributes = productEvent.EventAttributes; - attributes.should.not.have.property('Affiliation'); - attributes.should.not.have.property('Total Amount'); - attributes.should.not.have.property('Shipping Amount'); - attributes.should.not.have.property('Tax Amount'); - attributes.should.have.property('foo-event-attribute-key'); - attributes.should.have.property('Coupon Code', 'foo-productcouponcode'); - attributes.should.have.property('Brand', 'foo-brand'); - attributes.should.have.property('Category', 'foo-category'); - attributes.should.have.property('Name', 'Foo name'); - attributes.should.have.property('Id', 'Foo sku'); - attributes.should.have.property('Item Price', 100.0); - attributes.should.have.property('Quantity', 4); - attributes.should.have.property('Position', 5); - attributes.should.have.property( - 'foo-attribute-key', - 'foo-product-attribute-value' - ); - - done(); - }) - }) - }); - - it('expand product refund commerce event', function(done) { - waitForCondition(hasIdentifyReturned) - .then(() => { - mParticle._resetForTests(MPConfig); - const mockForwarder = new MockForwarder(); - mockForwarder.register(window.mParticle.config); - const config1 = forwarderDefaultConfiguration('MockForwarder', 1); - window.mParticle.config.kitConfigs.push(config1); - - mParticle.init(apiKey, window.mParticle.config); - - waitForCondition(() => { - return ( - mParticle.getInstance()._Store.identityCallInFlight === false + addToCartEvent.data.should.have.property('product_action'); + addToCartEvent.data.product_action.should.have.property( + 'action', + 'add_to_cart', ); - }) - .then(() => { - const productAttributes = {}; - productAttributes['foo-attribute-key'] = 'foo-product-attribute-value'; - - const eventAttributes = {}; - eventAttributes['foo-event-attribute-key'] = - 'foo-event-attribute-value'; - - const product = mParticle.eCommerce.createProduct( - 'Foo name', - 'Foo sku', - 100.0, - 4, - 'foo-variant', - 'foo-category', - 'foo-brand', - 5, - 'foo-productcouponcode', - productAttributes - ); - - const transactionAttributes = mParticle.eCommerce.createTransactionAttributes( - 'foo-transaction-id', - 'foo-affiliation', - 'foo-couponcode', - 400, - 10, - 8 - ); - mParticle.eCommerce.logRefund( - transactionAttributes, - product, - false, - eventAttributes - ); - window.MockForwarder1.instance.receivedEvent.should.have.property( - 'ProductAction' - ); - const expandedEvents = mParticle.eCommerce.expandCommerceEvent( - window.MockForwarder1.instance.receivedEvent - ); - expandedEvents.should.be.instanceof(Array).and.have.lengthOf(2); + addToCartEvent.data.product_action.should.have + .property('products') + .with.lengthOf(2); - const plusOneEvent = expandedEvents[0]; - plusOneEvent.should.have.property( - 'EventName', - 'eCommerce - refund - Total' - ); - const attributes = plusOneEvent.EventAttributes; - attributes.should.have.property('Product Count', 1); - - const productEvent = expandedEvents[1]; - productEvent.should.have.property( - 'EventName', - 'eCommerce - refund - Item' - ); - - done(); - }); - }) - }); - - it('expand non-plus-one-product commerce event', function(done) { - waitForCondition(hasIdentifyReturned) - .then(() => { - mParticle._resetForTests(MPConfig); - const mockForwarder = new MockForwarder(); - mockForwarder.register(window.mParticle.config); - const config1 = forwarderDefaultConfiguration('MockForwarder', 1); - window.mParticle.config.kitConfigs.push(config1); - - mParticle.init(apiKey, window.mParticle.config); - waitForCondition(() => { - return ( - mParticle.getInstance()._Store.identityCallInFlight === false + addToCartEvent.data.product_action.products[0].should.have.property( + 'id', + '12345', + ); + addToCartEvent.data.product_action.products[0].should.have.property( + 'name', + 'iPhone', ); - }) - .then(() => { - const productAttributes = {}; - productAttributes['foo-attribute-key'] = 'foo-product-attribute-value'; - - const eventAttributes = {}; - eventAttributes['foo-event-attribute-key'] = - 'foo-event-attribute-value'; - - const product = mParticle.eCommerce.createProduct( - 'Foo name', - 'Foo sku', - 100.0, - 4, - 'foo-variant', - 'foo-category', - 'foo-brand', - 5, - 'foo-productcouponcode', - productAttributes - ); - - mParticle.eCommerce.logProductAction( - mParticle.ProductActionType.RemoveFromWishlist, - product, - eventAttributes - ); - window.MockForwarder1.instance.receivedEvent.should.have.property( - 'ProductAction' - ); - const expandedEvents = mParticle.eCommerce.expandCommerceEvent( - window.MockForwarder1.instance.receivedEvent - ); - expandedEvents.should.be.instanceof(Array).and.have.lengthOf(1); - const productEvent = expandedEvents[0]; - productEvent.should.have.property( - 'EventName', - 'eCommerce - remove_from_wishlist - Item' - ); - productEvent.should.have.property( - 'EventCategory', - mParticle.EventType.Transaction - ); - const attributes = productEvent.EventAttributes; - - attributes.should.have.property('Coupon Code', 'foo-productcouponcode'); - attributes.should.have.property('Brand', 'foo-brand'); - attributes.should.have.property('Category', 'foo-category'); - attributes.should.have.property('Name', 'Foo name'); - attributes.should.have.property('Id', 'Foo sku'); - attributes.should.have.property('Item Price', 100.0); - attributes.should.have.property('Quantity', 4); - attributes.should.have.property('Position', 5); - attributes.should.have.property( - 'foo-attribute-key', - 'foo-product-attribute-value' - ); + addToCartEvent.data.product_action.products[1].should.have.property( + 'id', + '67890', + ); + addToCartEvent.data.product_action.products[1].should.have.property( + 'name', + 'Nexus', + ); - done(); - }); - }); + done(); + }); }); - it('expand checkout commerce event', function(done) { - waitForCondition(hasIdentifyReturned) - .then(() => { - mParticle._resetForTests(MPConfig); - const mockForwarder = new MockForwarder(); - mockForwarder.register(window.mParticle.config); - const config1 = forwarderDefaultConfiguration('MockForwarder', 1); - window.mParticle.config.kitConfigs.push(config1); - - mParticle.init(apiKey, window.mParticle.config); - waitForCondition(() => { - return ( - mParticle.getInstance()._Store.identityCallInFlight === false + it('should support a single product when adding to cart', function (done) { + waitForCondition(hasIdentifyReturned).then(() => { + const product1 = mParticle.eCommerce.createProduct( + 'iPhone', + '12345', + 400, + 2, ); - }) - .then(() => { - const eventAttributes = {}; - eventAttributes['foo-event-attribute-key'] = - 'foo-event-attribute-value'; - eventAttributes['Checkout Step'] = 'foo-step'; - eventAttributes['Checkout Options'] = 'foo-options'; - - const productAttributes = {}; - productAttributes['foo-attribute-key'] = 'foo-product-attribute-value'; - - const product = mParticle.eCommerce.createProduct( - 'Foo name', - 'Foo sku', - 100.0, - 4, - 'foo-variant', - 'foo-category', - 'foo-brand', - 5, - 'foo-productcouponcode', - productAttributes - ); - - mParticle.eCommerce.Cart.add(product, true); - - mParticle.eCommerce.logProductAction(mParticle.ProductActionType.Checkout, [product], eventAttributes); - - window.MockForwarder1.instance.receivedEvent.should.have.property( - 'ProductAction' - ); + mParticle.eCommerce.Cart.add(product1, true); - const expandedEvents = mParticle.eCommerce.expandCommerceEvent( - window.MockForwarder1.instance.receivedEvent - ); - expandedEvents.should.be.instanceof(Array).and.have.lengthOf(1); + const addToCartEvent = findEventFromRequest( + fetchMock.calls(), + 'add_to_cart', + ); - const productEvent = expandedEvents[0]; - productEvent.should.have.property( - 'EventName', - 'eCommerce - checkout - Item' - ); - productEvent.should.have.property( - 'EventCategory', - mParticle.EventType.Transaction - ); - const attributes = productEvent.EventAttributes; - - attributes.should.have.property('Checkout Step', 'foo-step'); - attributes.should.have.property('Checkout Options', 'foo-options'); - attributes.should.have.property('Coupon Code', 'foo-productcouponcode'); - attributes.should.have.property('Brand', 'foo-brand'); - attributes.should.have.property('Category', 'foo-category'); - attributes.should.have.property('Name', 'Foo name'); - attributes.should.have.property('Id', 'Foo sku'); - attributes.should.have.property('Item Price', 100.0); - attributes.should.have.property('Quantity', 4); - attributes.should.have.property('Position', 5); - attributes.should.have.property( - 'foo-attribute-key', - 'foo-product-attribute-value' - ); + Should(addToCartEvent).be.ok(); - done(); - }) - }) - }); + addToCartEvent.data.should.have.property('product_action'); + addToCartEvent.data.product_action.should.have.property( + 'action', + 'add_to_cart', + ); + addToCartEvent.data.product_action.should.have + .property('products') + .with.lengthOf(1); - it('expand promotion commerce event', function(done) { - waitForCondition(hasIdentifyReturned) - .then(() => { - mParticle._resetForTests(MPConfig); - const mockForwarder = new MockForwarder(); - mockForwarder.register(window.mParticle.config); - const config1 = forwarderDefaultConfiguration('MockForwarder', 1); - window.mParticle.config.kitConfigs.push(config1); - - mParticle.init(apiKey, window.mParticle.config); - waitForCondition(() => { - return ( - mParticle.getInstance()._Store.identityCallInFlight === false + addToCartEvent.data.product_action.products[0].should.have.property( + 'id', + '12345', + ); + addToCartEvent.data.product_action.products[0].should.have.property( + 'name', + 'iPhone', ); - }) - .then(() => { - const eventAttributes = {}; - eventAttributes['foo-event-attribute-key'] = - 'foo-event-attribute-value'; + done(); + }); + }); - const promotion = mParticle.eCommerce.createPromotion( - 'foo-id', - 'foo-creative', - 'foo-name', - 5 - ); + it('expand product purchase commerce event', function (done) { + waitForCondition(hasIdentifyReturned).then(() => { + mParticle._resetForTests(MPConfig); + const mockForwarder = new MockForwarder(); + mockForwarder.register(window.mParticle.config); + const config1 = forwarderDefaultConfiguration('MockForwarder', 1); + window.mParticle.config.kitConfigs.push(config1); + + mParticle.init(apiKey, window.mParticle.config); + waitForCondition(() => { + return ( + mParticle.getInstance()._Store.identityCallInFlight === + false + ); + }).then(() => { + mParticle.eCommerce.setCurrencyCode('foo-currency'); + const productAttributes = {}; + productAttributes['foo-attribute-key'] = + 'foo-product-attribute-value'; + + const eventAttributes = {}; + eventAttributes['foo-event-attribute-key'] = + 'foo-event-attribute-value'; + + const product = mParticle.eCommerce.createProduct( + 'Foo name', + 'Foo sku', + 100.0, + 4, + 'foo-variant', + 'foo-category', + 'foo-brand', + 5, + 'foo-productcouponcode', + productAttributes, + ); + + const transactionAttributes = + mParticle.eCommerce.createTransactionAttributes( + 'foo-transaction-id', + 'foo-affiliation', + 'foo-couponcode', + 400, + 10, + 8, + ); + mParticle.eCommerce.logPurchase( + transactionAttributes, + product, + false, + eventAttributes, + ); + window.MockForwarder1.instance.receivedEvent.should.have.property( + 'ProductAction', + ); + const expandedEvents = mParticle.eCommerce.expandCommerceEvent( + window.MockForwarder1.instance.receivedEvent, + ); + expandedEvents.should.be.instanceof(Array).and.have.lengthOf(2); + + const plusOneEvent = expandedEvents[0]; + plusOneEvent.should.have.property( + 'EventName', + 'eCommerce - purchase - Total', + ); + plusOneEvent.should.have.property( + 'EventCategory', + mParticle.EventType.Transaction, + ); + let attributes = plusOneEvent.EventAttributes; + attributes.should.have.property( + 'Transaction Id', + 'foo-transaction-id', + ); + attributes.should.have.property( + 'Affiliation', + 'foo-affiliation', + ); + attributes.should.have.property( + 'Coupon Code', + 'foo-couponcode', + ); + attributes.should.have.property('Total Amount', 400); + attributes.should.have.property('Shipping Amount', 10); + attributes.should.have.property('Product Count', 1); + attributes.should.have.property('Tax Amount', 8); + attributes.should.have.property( + 'Currency Code', + 'foo-currency', + ); + attributes.should.have.property( + 'foo-event-attribute-key', + 'foo-event-attribute-value', + ); + + const productEvent = expandedEvents[1]; + productEvent.should.have.property( + 'EventName', + 'eCommerce - purchase - Item', + ); + productEvent.should.have.property( + 'EventCategory', + mParticle.EventType.Transaction, + ); + attributes = productEvent.EventAttributes; + attributes.should.not.have.property('Affiliation'); + attributes.should.not.have.property('Total Amount'); + attributes.should.not.have.property('Shipping Amount'); + attributes.should.not.have.property('Tax Amount'); + attributes.should.have.property('foo-event-attribute-key'); + attributes.should.have.property( + 'Coupon Code', + 'foo-productcouponcode', + ); + attributes.should.have.property('Brand', 'foo-brand'); + attributes.should.have.property('Category', 'foo-category'); + attributes.should.have.property('Name', 'Foo name'); + attributes.should.have.property('Id', 'Foo sku'); + attributes.should.have.property('Item Price', 100.0); + attributes.should.have.property('Quantity', 4); + attributes.should.have.property('Position', 5); + attributes.should.have.property( + 'foo-attribute-key', + 'foo-product-attribute-value', + ); + + done(); + }); + }); + }); - mParticle.eCommerce.logPromotion( - mParticle.PromotionType.PromotionClick, - promotion, - eventAttributes - ); - window.MockForwarder1.instance.receivedEvent.should.have.property( - 'PromotionAction' - ); - const expandedEvents = mParticle.eCommerce.expandCommerceEvent( - window.MockForwarder1.instance.receivedEvent - ); + it('expand product refund commerce event', function (done) { + waitForCondition(hasIdentifyReturned).then(() => { + mParticle._resetForTests(MPConfig); + const mockForwarder = new MockForwarder(); + mockForwarder.register(window.mParticle.config); + const config1 = forwarderDefaultConfiguration('MockForwarder', 1); + window.mParticle.config.kitConfigs.push(config1); + + mParticle.init(apiKey, window.mParticle.config); + + waitForCondition(() => { + return ( + mParticle.getInstance()._Store.identityCallInFlight === + false + ); + }).then(() => { + const productAttributes = {}; + productAttributes['foo-attribute-key'] = + 'foo-product-attribute-value'; + + const eventAttributes = {}; + eventAttributes['foo-event-attribute-key'] = + 'foo-event-attribute-value'; + + const product = mParticle.eCommerce.createProduct( + 'Foo name', + 'Foo sku', + 100.0, + 4, + 'foo-variant', + 'foo-category', + 'foo-brand', + 5, + 'foo-productcouponcode', + productAttributes, + ); + + const transactionAttributes = + mParticle.eCommerce.createTransactionAttributes( + 'foo-transaction-id', + 'foo-affiliation', + 'foo-couponcode', + 400, + 10, + 8, + ); + mParticle.eCommerce.logRefund( + transactionAttributes, + product, + false, + eventAttributes, + ); + window.MockForwarder1.instance.receivedEvent.should.have.property( + 'ProductAction', + ); + const expandedEvents = mParticle.eCommerce.expandCommerceEvent( + window.MockForwarder1.instance.receivedEvent, + ); + expandedEvents.should.be.instanceof(Array).and.have.lengthOf(2); + + const plusOneEvent = expandedEvents[0]; + plusOneEvent.should.have.property( + 'EventName', + 'eCommerce - refund - Total', + ); + const attributes = plusOneEvent.EventAttributes; + attributes.should.have.property('Product Count', 1); + + const productEvent = expandedEvents[1]; + productEvent.should.have.property( + 'EventName', + 'eCommerce - refund - Item', + ); + + done(); + }); + }); + }); - expandedEvents.should.be.instanceof(Array).and.have.lengthOf(1); + it('expand non-plus-one-product commerce event', function (done) { + waitForCondition(hasIdentifyReturned).then(() => { + mParticle._resetForTests(MPConfig); + const mockForwarder = new MockForwarder(); + mockForwarder.register(window.mParticle.config); + const config1 = forwarderDefaultConfiguration('MockForwarder', 1); + window.mParticle.config.kitConfigs.push(config1); + + mParticle.init(apiKey, window.mParticle.config); + waitForCondition(() => { + return ( + mParticle.getInstance()._Store.identityCallInFlight === + false + ); + }).then(() => { + const productAttributes = {}; + productAttributes['foo-attribute-key'] = + 'foo-product-attribute-value'; + + const eventAttributes = {}; + eventAttributes['foo-event-attribute-key'] = + 'foo-event-attribute-value'; + + const product = mParticle.eCommerce.createProduct( + 'Foo name', + 'Foo sku', + 100.0, + 4, + 'foo-variant', + 'foo-category', + 'foo-brand', + 5, + 'foo-productcouponcode', + productAttributes, + ); + + mParticle.eCommerce.logProductAction( + mParticle.ProductActionType.RemoveFromWishlist, + product, + eventAttributes, + ); + window.MockForwarder1.instance.receivedEvent.should.have.property( + 'ProductAction', + ); + const expandedEvents = mParticle.eCommerce.expandCommerceEvent( + window.MockForwarder1.instance.receivedEvent, + ); + expandedEvents.should.be.instanceof(Array).and.have.lengthOf(1); + + const productEvent = expandedEvents[0]; + productEvent.should.have.property( + 'EventName', + 'eCommerce - remove_from_wishlist - Item', + ); + productEvent.should.have.property( + 'EventCategory', + mParticle.EventType.Transaction, + ); + const attributes = productEvent.EventAttributes; + + attributes.should.have.property( + 'Coupon Code', + 'foo-productcouponcode', + ); + attributes.should.have.property('Brand', 'foo-brand'); + attributes.should.have.property('Category', 'foo-category'); + attributes.should.have.property('Name', 'Foo name'); + attributes.should.have.property('Id', 'Foo sku'); + attributes.should.have.property('Item Price', 100.0); + attributes.should.have.property('Quantity', 4); + attributes.should.have.property('Position', 5); + attributes.should.have.property( + 'foo-attribute-key', + 'foo-product-attribute-value', + ); + + done(); + }); + }); + }); - const promotionEvent = expandedEvents[0]; - promotionEvent.should.have.property( - 'EventName', - 'eCommerce - click - Item' - ); - promotionEvent.should.have.property( - 'EventCategory', - mParticle.EventType.Transaction - ); - const attributes = promotionEvent.EventAttributes; - - attributes.should.have.property('Id', 'foo-id'); - attributes.should.have.property('Creative', 'foo-creative'); - attributes.should.have.property('Name', 'foo-name'); - attributes.should.have.property('Position', 5); - attributes.should.have.property( - 'foo-event-attribute-key', - 'foo-event-attribute-value' - ); + it('expand checkout commerce event', function (done) { + waitForCondition(hasIdentifyReturned).then(() => { + mParticle._resetForTests(MPConfig); + const mockForwarder = new MockForwarder(); + mockForwarder.register(window.mParticle.config); + const config1 = forwarderDefaultConfiguration('MockForwarder', 1); + window.mParticle.config.kitConfigs.push(config1); + + mParticle.init(apiKey, window.mParticle.config); + waitForCondition(() => { + return ( + mParticle.getInstance()._Store.identityCallInFlight === + false + ); + }).then(() => { + const eventAttributes = {}; + eventAttributes['foo-event-attribute-key'] = + 'foo-event-attribute-value'; + eventAttributes['Checkout Step'] = 'foo-step'; + eventAttributes['Checkout Options'] = 'foo-options'; + + const productAttributes = {}; + productAttributes['foo-attribute-key'] = + 'foo-product-attribute-value'; + + const product = mParticle.eCommerce.createProduct( + 'Foo name', + 'Foo sku', + 100.0, + 4, + 'foo-variant', + 'foo-category', + 'foo-brand', + 5, + 'foo-productcouponcode', + productAttributes, + ); + + mParticle.eCommerce.Cart.add(product, true); + + mParticle.eCommerce.logProductAction( + mParticle.ProductActionType.Checkout, + [product], + eventAttributes, + ); + + window.MockForwarder1.instance.receivedEvent.should.have.property( + 'ProductAction', + ); + + const expandedEvents = mParticle.eCommerce.expandCommerceEvent( + window.MockForwarder1.instance.receivedEvent, + ); + expandedEvents.should.be.instanceof(Array).and.have.lengthOf(1); + + const productEvent = expandedEvents[0]; + productEvent.should.have.property( + 'EventName', + 'eCommerce - checkout - Item', + ); + productEvent.should.have.property( + 'EventCategory', + mParticle.EventType.Transaction, + ); + const attributes = productEvent.EventAttributes; + + attributes.should.have.property('Checkout Step', 'foo-step'); + attributes.should.have.property( + 'Checkout Options', + 'foo-options', + ); + attributes.should.have.property( + 'Coupon Code', + 'foo-productcouponcode', + ); + attributes.should.have.property('Brand', 'foo-brand'); + attributes.should.have.property('Category', 'foo-category'); + attributes.should.have.property('Name', 'Foo name'); + attributes.should.have.property('Id', 'Foo sku'); + attributes.should.have.property('Item Price', 100.0); + attributes.should.have.property('Quantity', 4); + attributes.should.have.property('Position', 5); + attributes.should.have.property( + 'foo-attribute-key', + 'foo-product-attribute-value', + ); + + done(); + }); + }); + }); - done(); - }) - }) + it('expand promotion commerce event', function (done) { + waitForCondition(hasIdentifyReturned).then(() => { + mParticle._resetForTests(MPConfig); + const mockForwarder = new MockForwarder(); + mockForwarder.register(window.mParticle.config); + const config1 = forwarderDefaultConfiguration('MockForwarder', 1); + window.mParticle.config.kitConfigs.push(config1); + + mParticle.init(apiKey, window.mParticle.config); + waitForCondition(() => { + return ( + mParticle.getInstance()._Store.identityCallInFlight === + false + ); + }).then(() => { + const eventAttributes = {}; + eventAttributes['foo-event-attribute-key'] = + 'foo-event-attribute-value'; + + const promotion = mParticle.eCommerce.createPromotion( + 'foo-id', + 'foo-creative', + 'foo-name', + 5, + ); + + mParticle.eCommerce.logPromotion( + mParticle.PromotionType.PromotionClick, + promotion, + eventAttributes, + ); + window.MockForwarder1.instance.receivedEvent.should.have.property( + 'PromotionAction', + ); + const expandedEvents = mParticle.eCommerce.expandCommerceEvent( + window.MockForwarder1.instance.receivedEvent, + ); + + expandedEvents.should.be.instanceof(Array).and.have.lengthOf(1); + + const promotionEvent = expandedEvents[0]; + promotionEvent.should.have.property( + 'EventName', + 'eCommerce - click - Item', + ); + promotionEvent.should.have.property( + 'EventCategory', + mParticle.EventType.Transaction, + ); + const attributes = promotionEvent.EventAttributes; + + attributes.should.have.property('Id', 'foo-id'); + attributes.should.have.property('Creative', 'foo-creative'); + attributes.should.have.property('Name', 'foo-name'); + attributes.should.have.property('Position', 5); + attributes.should.have.property( + 'foo-event-attribute-key', + 'foo-event-attribute-value', + ); + + done(); + }); + }); }); - it('expand null commerce event', function(done) { + it('expand null commerce event', function (done) { const expandedEvents = mParticle.eCommerce.expandCommerceEvent(null); (expandedEvents == null).should.be.true; done(); }); - it('expand impression commerce event', function(done) { - waitForCondition(hasIdentifyReturned) - .then(() => { - mParticle._resetForTests(MPConfig); - const mockForwarder = new MockForwarder(); - mockForwarder.register(window.mParticle.config); - const config1 = forwarderDefaultConfiguration('MockForwarder', 1); - window.mParticle.config.kitConfigs.push(config1); - - mParticle.init(apiKey, window.mParticle.config); - waitForCondition(() => { - return ( - mParticle.getInstance()._Store.identityCallInFlight === false - ); - }) - .then(() => { - - const productAttributes = {}; - productAttributes['foo-attribute-key'] = 'foo-product-attribute-value'; - - const eventAttributes = {}; - eventAttributes['foo-event-attribute-key'] = - 'foo-event-attribute-value'; - - const product = mParticle.eCommerce.createProduct( - 'Foo name', - 'Foo sku', - 100.0, - 4, - 'foo-variant', - 'foo-category', - 'foo-brand', - 5, - 'foo-productcouponcode', - productAttributes - ); - - const impression = mParticle.eCommerce.createImpression( - 'suggested products list', - product - ); - - mParticle.eCommerce.logImpression(impression, eventAttributes); - window.MockForwarder1.instance.receivedEvent.should.have.property( - 'ProductImpressions' - ); - const expandedEvents = mParticle.eCommerce.expandCommerceEvent( - window.MockForwarder1.instance.receivedEvent - ); - - expandedEvents.should.be.instanceof(Array).and.have.lengthOf(1); - - const impressionEvent = expandedEvents[0]; - impressionEvent.should.have.property( - 'EventName', - 'eCommerce - Impression - Item' - ); - impressionEvent.should.have.property( - 'EventCategory', - mParticle.EventType.Transaction - ); - const attributes = impressionEvent.EventAttributes; - - attributes.should.have.property( - 'Product Impression List', - 'suggested products list' - ); - attributes.should.have.property('Coupon Code', 'foo-productcouponcode'); - attributes.should.have.property('Brand', 'foo-brand'); - attributes.should.have.property('Category', 'foo-category'); - attributes.should.have.property('Name', 'Foo name'); - attributes.should.have.property('Id', 'Foo sku'); - attributes.should.have.property('Item Price', 100.0); - attributes.should.have.property('Quantity', 4); - attributes.should.have.property('Position', 5); - attributes.should.have.property( - 'foo-attribute-key', - 'foo-product-attribute-value' - ); - attributes.should.have.property( - 'foo-event-attribute-key', - 'foo-event-attribute-value' - ); - - done(); - }) - }) - }); - - it('should add customFlags to logCheckout events', function(done) { - waitForCondition(hasIdentifyReturned) - .then(() => { - mParticle.eCommerce.logCheckout(1, {}, {}, { interactionEvent: true }); - - const checkoutEvent = findEventFromRequest(fetchMock.calls(), 'checkout'); - checkoutEvent.data.custom_flags.interactionEvent.should.equal(true); - - done(); - }) + it('expand impression commerce event', function (done) { + waitForCondition(hasIdentifyReturned).then(() => { + mParticle._resetForTests(MPConfig); + const mockForwarder = new MockForwarder(); + mockForwarder.register(window.mParticle.config); + const config1 = forwarderDefaultConfiguration('MockForwarder', 1); + window.mParticle.config.kitConfigs.push(config1); + + mParticle.init(apiKey, window.mParticle.config); + waitForCondition(() => { + return ( + mParticle.getInstance()._Store.identityCallInFlight === + false + ); + }).then(() => { + const productAttributes = {}; + productAttributes['foo-attribute-key'] = + 'foo-product-attribute-value'; + + const eventAttributes = {}; + eventAttributes['foo-event-attribute-key'] = + 'foo-event-attribute-value'; + + const product = mParticle.eCommerce.createProduct( + 'Foo name', + 'Foo sku', + 100.0, + 4, + 'foo-variant', + 'foo-category', + 'foo-brand', + 5, + 'foo-productcouponcode', + productAttributes, + ); + + const impression = mParticle.eCommerce.createImpression( + 'suggested products list', + product, + ); + + mParticle.eCommerce.logImpression(impression, eventAttributes); + window.MockForwarder1.instance.receivedEvent.should.have.property( + 'ProductImpressions', + ); + const expandedEvents = mParticle.eCommerce.expandCommerceEvent( + window.MockForwarder1.instance.receivedEvent, + ); + + expandedEvents.should.be.instanceof(Array).and.have.lengthOf(1); + + const impressionEvent = expandedEvents[0]; + impressionEvent.should.have.property( + 'EventName', + 'eCommerce - Impression - Item', + ); + impressionEvent.should.have.property( + 'EventCategory', + mParticle.EventType.Transaction, + ); + const attributes = impressionEvent.EventAttributes; + + attributes.should.have.property( + 'Product Impression List', + 'suggested products list', + ); + attributes.should.have.property( + 'Coupon Code', + 'foo-productcouponcode', + ); + attributes.should.have.property('Brand', 'foo-brand'); + attributes.should.have.property('Category', 'foo-category'); + attributes.should.have.property('Name', 'Foo name'); + attributes.should.have.property('Id', 'Foo sku'); + attributes.should.have.property('Item Price', 100.0); + attributes.should.have.property('Quantity', 4); + attributes.should.have.property('Position', 5); + attributes.should.have.property( + 'foo-attribute-key', + 'foo-product-attribute-value', + ); + attributes.should.have.property( + 'foo-event-attribute-key', + 'foo-event-attribute-value', + ); + + done(); + }); + }); }); - it('should add customFlags to logProductAction events', function(done) { - waitForCondition(hasIdentifyReturned) - .then(() => { - const product = mParticle.eCommerce.createProduct('iPhone', 'sku1', 499); - mParticle.eCommerce.logProductAction( - mParticle.ProductActionType.Unknown, - product, - { price: 5 }, - { interactionEvent: true } - ); - const unknownEvent = findEventFromRequest(fetchMock.calls(), 'unknown'); + it('should add customFlags to logCheckout events', function (done) { + waitForCondition(hasIdentifyReturned).then(() => { + mParticle.eCommerce.logCheckout( + 1, + {}, + {}, + { interactionEvent: true }, + ); - unknownEvent.data.custom_flags.interactionEvent.should.equal(true); + const checkoutEvent = findEventFromRequest( + fetchMock.calls(), + 'checkout', + ); + checkoutEvent.data.custom_flags.interactionEvent.should.equal(true); - done(); - }) + done(); + }); }); - it('should add customFlags to logPurchase events', function(done) { - waitForCondition(hasIdentifyReturned) - .then(() => { - const product = mParticle.eCommerce.createProduct('iPhone', 'sku1', 499); - const transactionAttributes = mParticle.eCommerce.createTransactionAttributes( - 'id1', - 'affil1', - 'couponCode1' - ); - mParticle.eCommerce.logPurchase( - transactionAttributes, - product, - true, - { shipping: 5 }, - { interactionEvent: true } - ); - - const purchaseEvent = findEventFromRequest(fetchMock.calls(), 'purchase'); + it('should add customFlags to logProductAction events', function (done) { + waitForCondition(hasIdentifyReturned).then(() => { + const product = mParticle.eCommerce.createProduct( + 'iPhone', + 'sku1', + 499, + ); + mParticle.eCommerce.logProductAction( + mParticle.ProductActionType.Unknown, + product, + { price: 5 }, + { interactionEvent: true }, + ); + const unknownEvent = findEventFromRequest( + fetchMock.calls(), + 'unknown', + ); - purchaseEvent.data.custom_flags.interactionEvent.should.equal(true); + unknownEvent.data.custom_flags.interactionEvent.should.equal(true); - done(); - }) + done(); + }); }); - it('should add customFlags to logPromotion events', function(done) { - waitForCondition(hasIdentifyReturned) - .then(() => { - const promotion = mParticle.eCommerce.createPromotion( - 'id', - 'creative', - 'name' - ); - - mParticle.eCommerce.logPromotion( - mParticle.PromotionType.Unknown, - promotion, - { shipping: 5 }, - { interactionEvent: true } - ); - + it('should add customFlags to logPurchase events', function (done) { + waitForCondition(hasIdentifyReturned).then(() => { + const product = mParticle.eCommerce.createProduct( + 'iPhone', + 'sku1', + 499, + ); + const transactionAttributes = + mParticle.eCommerce.createTransactionAttributes( + 'id1', + 'affil1', + 'couponCode1', + ); + mParticle.eCommerce.logPurchase( + transactionAttributes, + product, + true, + { shipping: 5 }, + { interactionEvent: true }, + ); - const promotionEvent = findEventFromRequest(fetchMock.calls(), 'click'); + const purchaseEvent = findEventFromRequest( + fetchMock.calls(), + 'purchase', + ); - promotionEvent.data.custom_flags.interactionEvent.should.equal(true); + purchaseEvent.data.custom_flags.interactionEvent.should.equal(true); - done(); - }) + done(); + }); }); - it('should add customFlags to logImpression events', function(done) { - waitForCondition(hasIdentifyReturned) - .then(() => { - const product = mParticle.eCommerce.createProduct('iPhone', 'sku1', 499); - const impression = mParticle.eCommerce.createImpression( - 'iphoneImpressionName', - product - ); - mParticle.eCommerce.logImpression( - impression, - { shipping: 5 }, - { interactionEvent: true } - ); - - const impressionEvent = findEventFromRequest(fetchMock.calls(), 'impression'); - impressionEvent.data.custom_flags.interactionEvent.should.equal(true); + it('should add customFlags to logPromotion events', function (done) { + waitForCondition(hasIdentifyReturned).then(() => { + const promotion = mParticle.eCommerce.createPromotion( + 'id', + 'creative', + 'name', + ); - done(); - }) - }); + mParticle.eCommerce.logPromotion( + mParticle.PromotionType.Unknown, + promotion, + { shipping: 5 }, + { interactionEvent: true }, + ); - it('should add customFlags to logRefund events', function(done) { - waitForCondition(hasIdentifyReturned) - .then(() => { - const product = mParticle.eCommerce.createProduct('iPhone', 'sku1', 499); - const transactionAttributes = mParticle.eCommerce.createTransactionAttributes( - 'id1', - 'affil1', - 'couponCode1' - ); - mParticle.eCommerce.logRefund( - transactionAttributes, - product, - true, - { shipping: 5 }, - { interactionEvent: true } - ); - const refundEvent = findEventFromRequest(fetchMock.calls(), 'refund'); + const promotionEvent = findEventFromRequest( + fetchMock.calls(), + 'click', + ); - refundEvent.data.custom_flags.interactionEvent.should.equal(true); + promotionEvent.data.custom_flags.interactionEvent.should.equal( + true, + ); - done(); - }) - }); - describe('Cart', function() { - afterEach(function() { - sinon.restore(); + done(); }); + }); - it('should deprecate add', function() { - waitForCondition(hasIdentifyReturned) - .then(() => { - const bond = sinon.spy(mParticle.getInstance().Logger, 'warning'); - + it('should add customFlags to logImpression events', function (done) { + waitForCondition(hasIdentifyReturned).then(() => { const product = mParticle.eCommerce.createProduct( 'iPhone', - '12345', - 400 + 'sku1', + 499, + ); + const impression = mParticle.eCommerce.createImpression( + 'iphoneImpressionName', + product, + ); + mParticle.eCommerce.logImpression( + impression, + { shipping: 5 }, + { interactionEvent: true }, ); - mParticle.eCommerce.Cart.add(product, true); - - bond.called.should.eql(true); - bond.getCalls()[0].args[0].should.eql( - 'Deprecated function eCommerce.Cart.add() will be removed in future releases' + const impressionEvent = findEventFromRequest( + fetchMock.calls(), + 'impression', ); - }) + impressionEvent.data.custom_flags.interactionEvent.should.equal( + true, + ); + + done(); }); - it('should deprecate remove', function() { - waitForCondition(hasIdentifyReturned) - .then(() => { - const bond = sinon.spy(mParticle.getInstance().Logger, 'warning'); + }); + it('should add customFlags to logRefund events', function (done) { + waitForCondition(hasIdentifyReturned).then(() => { const product = mParticle.eCommerce.createProduct( 'iPhone', - '12345', - 400 + 'sku1', + 499, + ); + const transactionAttributes = + mParticle.eCommerce.createTransactionAttributes( + 'id1', + 'affil1', + 'couponCode1', + ); + mParticle.eCommerce.logRefund( + transactionAttributes, + product, + true, + { shipping: 5 }, + { interactionEvent: true }, + ); + const refundEvent = findEventFromRequest( + fetchMock.calls(), + 'refund', ); - mParticle.eCommerce.Cart.remove(product, true); + refundEvent.data.custom_flags.interactionEvent.should.equal(true); - bond.called.should.eql(true); - bond.getCalls()[0].args[0].should.eql( - 'Deprecated function eCommerce.Cart.remove() will be removed in future releases' - ); - }) + done(); + }); + }); + describe('Cart', function () { + afterEach(function () { + sinon.restore(); }); - it('should deprecate clear', function() { - waitForCondition(hasIdentifyReturned) - .then(() => { - const bond = sinon.spy(mParticle.getInstance().Logger, 'warning'); + it('should deprecate add', function () { + waitForCondition(hasIdentifyReturned).then(() => { + const bond = sinon.spy( + mParticle.getInstance().Logger, + 'warning', + ); + + const product = mParticle.eCommerce.createProduct( + 'iPhone', + '12345', + 400, + ); + + mParticle.eCommerce.Cart.add(product, true); + + bond.called.should.eql(true); + bond.getCalls()[0].args[0].should.eql( + 'Deprecated function eCommerce.Cart.add() will be removed in future releases', + ); + }); + }); + it('should deprecate remove', function () { + waitForCondition(hasIdentifyReturned).then(() => { + const bond = sinon.spy( + mParticle.getInstance().Logger, + 'warning', + ); + + const product = mParticle.eCommerce.createProduct( + 'iPhone', + '12345', + 400, + ); + + mParticle.eCommerce.Cart.remove(product, true); + + bond.called.should.eql(true); + bond.getCalls()[0].args[0].should.eql( + 'Deprecated function eCommerce.Cart.remove() will be removed in future releases', + ); + }); + }); - mParticle.eCommerce.Cart.clear(); + it('should deprecate clear', function () { + waitForCondition(hasIdentifyReturned).then(() => { + const bond = sinon.spy( + mParticle.getInstance().Logger, + 'warning', + ); - bond.called.should.eql(true); - bond.getCalls()[0].args[0].should.eql( - 'Deprecated function eCommerce.Cart.clear() will be removed in future releases' - ); - }) + mParticle.eCommerce.Cart.clear(); + + bond.called.should.eql(true); + bond.getCalls()[0].args[0].should.eql( + 'Deprecated function eCommerce.Cart.clear() will be removed in future releases', + ); + }); }); - it('should be empty when transactionAttributes is empty', function() { - const mparticle = mParticle.getInstance() - const productAction = {} - mparticle._Ecommerce.convertTransactionAttributesToProductAction({}, productAction) + it('should be empty when transactionAttributes is empty', function () { + const mparticle = mParticle.getInstance(); + const productAction = {}; + mparticle._Ecommerce.convertTransactionAttributesToProductAction( + {}, + productAction, + ); Object.keys(productAction).length.should.equal(0); }); - it('should sanitize certain ecommerce amounts from strings to 0', function() { - mParticle.getInstance()._Ecommerce.sanitizeAmount('$42', 'Price').should.equal(0); - mParticle.getInstance()._Ecommerce.sanitizeAmount('$100', 'TotalAmount').should.equal(0); - mParticle.getInstance()._Ecommerce.sanitizeAmount('first', 'Position').should.equal(0); - mParticle.getInstance()._Ecommerce.sanitizeAmount('two', 'Quantity').should.equal(0); - mParticle.getInstance()._Ecommerce.sanitizeAmount('string', 'Shipping').should.equal(0); - mParticle.getInstance()._Ecommerce.sanitizeAmount('$5.80', 'Tax').should.equal(0); + it('should sanitize certain ecommerce amounts from strings to 0', function () { + mParticle + .getInstance() + ._Ecommerce.sanitizeAmount('$42', 'Price') + .should.equal(0); + mParticle + .getInstance() + ._Ecommerce.sanitizeAmount('$100', 'TotalAmount') + .should.equal(0); + mParticle + .getInstance() + ._Ecommerce.sanitizeAmount('first', 'Position') + .should.equal(0); + mParticle + .getInstance() + ._Ecommerce.sanitizeAmount('two', 'Quantity') + .should.equal(0); + mParticle + .getInstance() + ._Ecommerce.sanitizeAmount('string', 'Shipping') + .should.equal(0); + mParticle + .getInstance() + ._Ecommerce.sanitizeAmount('$5.80', 'Tax') + .should.equal(0); }); - it('should convert transactionAttributes strings to numbers or zero', function() { - const mparticle = mParticle.getInstance() + it('should convert transactionAttributes strings to numbers or zero', function () { + const mparticle = mParticle.getInstance(); const transactionAttributes = { - Id: "id", - Affiliation: "affiliation", - CouponCode: "couponCode", - Revenue: "revenue", - Shipping: "shipping", - Tax: "tax" + Id: 'id', + Affiliation: 'affiliation', + CouponCode: 'couponCode', + Revenue: 'revenue', + Shipping: 'shipping', + Tax: 'tax', }; const productAction = {}; - mparticle._Ecommerce.convertTransactionAttributesToProductAction(transactionAttributes, productAction) - productAction.TransactionId.should.equal("id") - productAction.Affiliation.should.equal("affiliation") - productAction.CouponCode.should.equal("couponCode") - - // convert strings to 0 - productAction.TotalAmount.should.equal(0) - productAction.ShippingAmount.should.equal(0) - productAction.TaxAmount.should.equal(0) - }); - - it('should allow a user to pass in a source_message_id to a commerce event', function() { - waitForCondition(hasIdentifyReturned) - .then(() => { - const product = mParticle.eCommerce.createProduct( - 'iPhone', - '12345', - '400', - 2, - 'Plus', - 'Phones', - 'Apple', - 1, - 'my-coupon-code', - { customkey: 'customvalue' } - ), - - transactionAttributes = mParticle.eCommerce.createTransactionAttributes( - '12345', - 'test-affiliation', - 'coupon-code', - 44334, - 600, - 200 - ); - - mParticle.eCommerce.logProductAction( - mParticle.ProductActionType.Purchase, - product, - null, - null, + mparticle._Ecommerce.convertTransactionAttributesToProductAction( transactionAttributes, - { - sourceMessageId: 'foo-bar' - } + productAction, ); + productAction.TransactionId.should.equal('id'); + productAction.Affiliation.should.equal('affiliation'); + productAction.CouponCode.should.equal('couponCode'); + + // convert strings to 0 + productAction.TotalAmount.should.equal(0); + productAction.ShippingAmount.should.equal(0); + productAction.TaxAmount.should.equal(0); + }); - const purchaseEvent1 = findEventFromRequest(fetchMock.calls(), 'purchase'); - purchaseEvent1.data.source_message_id.should.equal('foo-bar'); - }) + it('should allow a user to pass in a source_message_id to a commerce event', function () { + waitForCondition(hasIdentifyReturned).then(() => { + const product = mParticle.eCommerce.createProduct( + 'iPhone', + '12345', + '400', + 2, + 'Plus', + 'Phones', + 'Apple', + 1, + 'my-coupon-code', + { customkey: 'customvalue' }, + ), + transactionAttributes = + mParticle.eCommerce.createTransactionAttributes( + '12345', + 'test-affiliation', + 'coupon-code', + 44334, + 600, + 200, + ); + + mParticle.eCommerce.logProductAction( + mParticle.ProductActionType.Purchase, + product, + null, + null, + transactionAttributes, + { + sourceMessageId: 'foo-bar', + }, + ); + + const purchaseEvent1 = findEventFromRequest( + fetchMock.calls(), + 'purchase', + ); + purchaseEvent1.data.source_message_id.should.equal('foo-bar'); + }); }); }); -}); \ No newline at end of file +}); diff --git a/test/src/tests-event-logging.js b/test/src/tests-event-logging.js index 6c52f6570..c766af285 100644 --- a/test/src/tests-event-logging.js +++ b/test/src/tests-event-logging.js @@ -10,1549 +10,1570 @@ import { } from './config/constants'; let mockServer; -const { findEventFromRequest, findBatch, getIdentityEvent, waitForCondition, fetchMockSuccess, hasIdentifyReturned } = Utils; - -describe('event logging', function() { - beforeEach(function() { +const { + findEventFromRequest, + findBatch, + getIdentityEvent, + waitForCondition, + fetchMockSuccess, + hasIdentifyReturned, +} = Utils; + +describe('event logging', function () { + beforeEach(function () { mParticle._resetForTests(MPConfig); fetchMock.post(urls.events, 200); delete mParticle._instances['default_instance']; - + fetchMockSuccess(urls.identify, { - mpid: testMPID, is_logged_in: false + mpid: testMPID, + is_logged_in: false, }); mParticle.init(apiKey, window.mParticle.config); }); - afterEach(function() { + afterEach(function () { fetchMock.restore(); mParticle._resetForTests(MPConfig); }); - it('should log an event', function(done) { - waitForCondition(hasIdentifyReturned) - .then(() => { - window.mParticle.logEvent( - 'Test Event', - mParticle.EventType.Navigation, - { mykey: 'myvalue' } - ); - const testEvent = findEventFromRequest(fetchMock.calls(), 'Test Event'); - const testEventBatch = findBatch(fetchMock.calls(), 'Test Event'); - - testEvent.data.should.have.property('event_name', 'Test Event'); - testEvent.data.should.have.property('custom_event_type', 'navigation'); - testEvent.data.should.have.property('custom_attributes'); - testEvent.data.custom_attributes.should.have.property( - 'mykey', - 'myvalue' - ); - - testEventBatch.should.have.property('mpid', testMPID); - - done(); - }) + it('should log an event', function (done) { + waitForCondition(hasIdentifyReturned).then(() => { + window.mParticle.logEvent( + 'Test Event', + mParticle.EventType.Navigation, + { mykey: 'myvalue' }, + ); + const testEvent = findEventFromRequest( + fetchMock.calls(), + 'Test Event', + ); + const testEventBatch = findBatch(fetchMock.calls(), 'Test Event'); + + testEvent.data.should.have.property('event_name', 'Test Event'); + testEvent.data.should.have.property( + 'custom_event_type', + 'navigation', + ); + testEvent.data.should.have.property('custom_attributes'); + testEvent.data.custom_attributes.should.have.property( + 'mykey', + 'myvalue', + ); + + testEventBatch.should.have.property('mpid', testMPID); + + done(); + }); }); - it('should log an event with new device id when set on setDeviceId', function(done) { - waitForCondition(hasIdentifyReturned) - .then(() => { - window.mParticle.logEvent( - 'Test Event', - mParticle.EventType.Navigation, - { mykey: 'myvalue' } - ); + it('should log an event with new device id when set on setDeviceId', function (done) { + waitForCondition(hasIdentifyReturned).then(() => { + window.mParticle.logEvent( + 'Test Event', + mParticle.EventType.Navigation, + { mykey: 'myvalue' }, + ); - const testEventBatch = findBatch(fetchMock.calls(), 'Test Event'); - // this das should be the SDK auto generated one, which is 36 characters long - testEventBatch.mp_deviceid.should.have.length(36); + const testEventBatch = findBatch(fetchMock.calls(), 'Test Event'); + // this das should be the SDK auto generated one, which is 36 characters long + testEventBatch.mp_deviceid.should.have.length(36); - mParticle.setDeviceId('foo-guid'); + mParticle.setDeviceId('foo-guid'); - window.mParticle.logEvent('Test Event2'); - const testEvent2Batch = findBatch(fetchMock.calls(), 'Test Event2'); + window.mParticle.logEvent('Test Event2'); + const testEvent2Batch = findBatch(fetchMock.calls(), 'Test Event2'); - // das should be the one passed to setDeviceId() - testEvent2Batch.should.have.property('mp_deviceid', 'foo-guid'); + // das should be the one passed to setDeviceId() + testEvent2Batch.should.have.property('mp_deviceid', 'foo-guid'); - done(); - }) + done(); + }); }); - it('should log an event with new device id when set via mParticle.config', function(done) { + it('should log an event with new device id when set via mParticle.config', function (done) { mParticle._resetForTests(MPConfig); - + window.mParticle.config.deviceId = 'foo-guid'; mParticle.init(apiKey, window.mParticle.config); - waitForCondition(hasIdentifyReturned) - .then(() => { + waitForCondition(hasIdentifyReturned).then(() => { + window.mParticle.logEvent('Test Event'); + const testEventBatch = findBatch(fetchMock.calls(), 'Test Event'); - window.mParticle.logEvent('Test Event'); - const testEventBatch = findBatch(fetchMock.calls(), 'Test Event'); + // this das should be the SDK auto generated one + testEventBatch.should.have.property('mp_deviceid', 'foo-guid'); - // this das should be the SDK auto generated one - testEventBatch.should.have.property('mp_deviceid', 'foo-guid'); - - done(); - }) + done(); + }); }); - it('should allow an event to bypass server upload', function(done) { - waitForCondition(hasIdentifyReturned) - .then(() => { - window.mParticle.logEvent( - 'Test Standard Upload', - mParticle.EventType.Navigation, - { mykey: 'myvalue' }, - {}, - { - shouldUploadEvent: true, - } - ); - - window.mParticle.logEvent( - 'Test Upload Bypass', - mParticle.EventType.Navigation, - { mykey: 'myvalue' }, - {}, - { - shouldUploadEvent: false, - } - ); - - const uploadEvent = findEventFromRequest( - fetchMock.calls(), - 'Test Standard Upload' - ); - const uploadEventBatch = findBatch( - fetchMock.calls(), - 'Test Standard Upload' - ); - - const bypassedEvent = findEventFromRequest( - fetchMock.calls(), - 'Test Upload Bypass' - ); - - uploadEvent.should.be.ok(); - uploadEvent.data.should.have.property( - 'event_name', - 'Test Standard Upload' - ); - uploadEvent.data.should.have.property( - 'custom_event_type', - 'navigation' - ); - uploadEvent.data.should.have.property('custom_attributes'); - uploadEvent.data.custom_attributes.should.have.property( - 'mykey', - 'myvalue' - ); - uploadEventBatch.should.have.property('mpid', testMPID); - - Should(bypassedEvent).not.be.ok(); - - done(); - }) - }); + it('should allow an event to bypass server upload', function (done) { + waitForCondition(hasIdentifyReturned).then(() => { + window.mParticle.logEvent( + 'Test Standard Upload', + mParticle.EventType.Navigation, + { mykey: 'myvalue' }, + {}, + { + shouldUploadEvent: true, + }, + ); - it('should allow an event to bypass server upload via logBaseEvent', function(done) { - waitForCondition(hasIdentifyReturned) - .then(() => { - window.mParticle.logBaseEvent( - { - name: 'Test Standard Upload', - messageType: MessageType.PageEvent, - eventType: mParticle.EventType.Navigation, - data: { mykey: 'myvalue' }, - customFlags: {}, - }, - { - shouldUploadEvent: true, - } - ); - - window.mParticle.logBaseEvent( - { - name: 'Test Upload Bypass', - messageType: MessageType.PageEvent, - eventType: mParticle.EventType.Navigation, - data: { mykey: 'myvalue' }, - customFlags: {}, - }, - { - shouldUploadEvent: false, - } - ); - - const uploadEvent = findEventFromRequest( - fetchMock.calls(), - 'Test Standard Upload' - ); - const uploadEventBatch = findBatch( - fetchMock.calls(), - 'Test Standard Upload' - ); - - const bypassedEvent = findEventFromRequest( - fetchMock.calls(), - 'Test Upload Bypass' - ); - - uploadEvent.should.be.ok(); - - uploadEvent.data.should.have.property( - 'event_name', - 'Test Standard Upload' - ); - uploadEvent.data.should.have.property( - 'custom_event_type', - 'navigation' - ); - uploadEvent.data.should.have.property('custom_attributes'); - uploadEvent.data.custom_attributes.should.have.property( - 'mykey', - 'myvalue' - ); - uploadEventBatch.should.have.property('mpid', testMPID); - - Should(bypassedEvent).not.be.ok(); - - done(); - }) - }); + window.mParticle.logEvent( + 'Test Upload Bypass', + mParticle.EventType.Navigation, + { mykey: 'myvalue' }, + {}, + { + shouldUploadEvent: false, + }, + ); - it('should log an error', function(done) { - waitForCondition(hasIdentifyReturned) - .then(() => { - mParticle.logError('my error'); + const uploadEvent = findEventFromRequest( + fetchMock.calls(), + 'Test Standard Upload', + ); + const uploadEventBatch = findBatch( + fetchMock.calls(), + 'Test Standard Upload', + ); - const errorEvent = findEventFromRequest(fetchMock.calls(), 'my error'); + const bypassedEvent = findEventFromRequest( + fetchMock.calls(), + 'Test Upload Bypass', + ); - Should(errorEvent).be.ok(); + uploadEvent.should.be.ok(); + uploadEvent.data.should.have.property( + 'event_name', + 'Test Standard Upload', + ); + uploadEvent.data.should.have.property( + 'custom_event_type', + 'navigation', + ); + uploadEvent.data.should.have.property('custom_attributes'); + uploadEvent.data.custom_attributes.should.have.property( + 'mykey', + 'myvalue', + ); + uploadEventBatch.should.have.property('mpid', testMPID); - errorEvent.data.should.have.property('message', 'Error'); - errorEvent.data.should.have.property('custom_attributes'); - errorEvent.data.custom_attributes.should.have.property('m', 'my error'); + Should(bypassedEvent).not.be.ok(); - done(); - }) + done(); + }); }); - it('should log an error with name, message, stack', function(done) { - waitForCondition(hasIdentifyReturned) - .then(() => { - const error = new Error('my error'); - error.stack = 'my stacktrace'; - - mParticle.logError(error); + it('should allow an event to bypass server upload via logBaseEvent', function (done) { + waitForCondition(hasIdentifyReturned).then(() => { + window.mParticle.logBaseEvent( + { + name: 'Test Standard Upload', + messageType: MessageType.PageEvent, + eventType: mParticle.EventType.Navigation, + data: { mykey: 'myvalue' }, + customFlags: {}, + }, + { + shouldUploadEvent: true, + }, + ); - const errorEvent = findEventFromRequest(fetchMock.calls(), 'my error'); + window.mParticle.logBaseEvent( + { + name: 'Test Upload Bypass', + messageType: MessageType.PageEvent, + eventType: mParticle.EventType.Navigation, + data: { mykey: 'myvalue' }, + customFlags: {}, + }, + { + shouldUploadEvent: false, + }, + ); - Should(errorEvent).be.ok(); + const uploadEvent = findEventFromRequest( + fetchMock.calls(), + 'Test Standard Upload', + ); + const uploadEventBatch = findBatch( + fetchMock.calls(), + 'Test Standard Upload', + ); - errorEvent.data.should.have.property('message', 'Error'); - errorEvent.data.should.have.property('custom_attributes'); - errorEvent.data.custom_attributes.should.have.property('m', 'my error'); - errorEvent.data.custom_attributes.should.have.property('s', 'Error'); - errorEvent.data.custom_attributes.should.have.property( - 't', - 'my stacktrace' - ); + const bypassedEvent = findEventFromRequest( + fetchMock.calls(), + 'Test Upload Bypass', + ); - done(); - }) + uploadEvent.should.be.ok(); - }); + uploadEvent.data.should.have.property( + 'event_name', + 'Test Standard Upload', + ); + uploadEvent.data.should.have.property( + 'custom_event_type', + 'navigation', + ); + uploadEvent.data.should.have.property('custom_attributes'); + uploadEvent.data.custom_attributes.should.have.property( + 'mykey', + 'myvalue', + ); + uploadEventBatch.should.have.property('mpid', testMPID); - it('should log an error with custom attrs', function(done) { - waitForCondition(hasIdentifyReturned) - .then(() => { - const error = new Error('my error'); - error.stack = 'my stacktrace'; - - mParticle.logError(error, { location: 'my path', myData: 'my data' }); - - const errorEvent = findEventFromRequest(fetchMock.calls(), 'my error'); - - Should(errorEvent).be.ok(); - errorEvent.data.should.have.property('message', 'Error'); - errorEvent.data.should.have.property('custom_attributes'); - errorEvent.data.custom_attributes.should.have.property( - 'location', - 'my path' - ); - errorEvent.data.custom_attributes.should.have.property( - 'myData', - 'my data' - ); - - done(); - }) - }); + Should(bypassedEvent).not.be.ok(); - it('should sanitize error custom attrs', function(done) { - waitForCondition(hasIdentifyReturned) - .then(() => { - const bond = sinon.spy(mParticle.getInstance().Logger, 'warning'); - mParticle.logError('my error', { - invalid: ['my invalid attr'], - valid: 10, + done(); }); + }); - const errorEvent = findEventFromRequest(fetchMock.calls(), 'my error'); + it('should log an error', function (done) { + waitForCondition(hasIdentifyReturned).then(() => { + mParticle.logError('my error'); - Should(errorEvent).be.ok(); - errorEvent.data.should.have.property('message', 'Error'); - errorEvent.data.should.have.property('custom_attributes'); - errorEvent.data.custom_attributes.should.have.property('valid', 10); - errorEvent.data.custom_attributes.should.not.have.property('invalid'); + const errorEvent = findEventFromRequest( + fetchMock.calls(), + 'my error', + ); - bond.called.should.eql(true); - bond.callCount.should.equal(1); + Should(errorEvent).be.ok(); - bond.getCalls()[0].args[0].should.eql( - "For 'my error', the corresponding attribute value of 'invalid' must be a string, number, boolean, or null." - ); + errorEvent.data.should.have.property('message', 'Error'); + errorEvent.data.should.have.property('custom_attributes'); + errorEvent.data.custom_attributes.should.have.property( + 'm', + 'my error', + ); - done(); - }) + done(); + }); }); - it('should log an AST with firstRun = true when first visiting a page, and firstRun = false when reloading the page', function(done) { - waitForCondition(hasIdentifyReturned) - .then(() => { - const astEvent = findEventFromRequest( - fetchMock.calls(), - 'application_state_transition' - ); - - astEvent.data.should.have.property( - 'application_transition_type', - 'application_initialized' - ); - astEvent.data.should.have.property('is_first_run', true); - astEvent.data.should.have.property('is_upgrade', false); - - if (document.referrer && document.referrer.length > 0) { - astEvent.data.should.have.property( - 'launch_referral', - window.location.href - ); - } + it('should log an error with name, message, stack', function (done) { + waitForCondition(hasIdentifyReturned).then(() => { + const error = new Error('my error'); + error.stack = 'my stacktrace'; - fetchMock.resetHistory(); + mParticle.logError(error); - mParticle.init(apiKey, window.mParticle.config); - waitForCondition(() => { - return ( - mParticle.getInstance()._Store.identityCallInFlight === false + const errorEvent = findEventFromRequest( + fetchMock.calls(), + 'my error', ); - }) - .then(() => { - - const astEvent2 = findEventFromRequest( - fetchMock.calls(), - 'application_state_transition' - ); - astEvent2.data.should.have.property('is_first_run', false); - - done(); - }) - }) - }); + Should(errorEvent).be.ok(); - it('should log an AST on init with firstRun = false when cookies already exist', function(done) { - waitForCondition(hasIdentifyReturned) - .then(() => { - // cookies currently exist, mParticle.init called from beforeEach - fetchMock.resetHistory(); - // log second AST - waitForCondition(() => { - return ( - mParticle.getInstance()._Store.identityCallInFlight === false + errorEvent.data.should.have.property('message', 'Error'); + errorEvent.data.should.have.property('custom_attributes'); + errorEvent.data.custom_attributes.should.have.property( + 'm', + 'my error', + ); + errorEvent.data.custom_attributes.should.have.property( + 's', + 'Error', + ); + errorEvent.data.custom_attributes.should.have.property( + 't', + 'my stacktrace', ); - }) - .then(() => { - mParticle.init(apiKey, window.mParticle.config); - - const astEvent = findEventFromRequest( - fetchMock.calls(), - 'application_state_transition' - ); - astEvent.data.should.have.property('is_first_run', false); - done(); - }) + done(); }); }); - it('should log a page view', function(done) { - waitForCondition(hasIdentifyReturned) - .then(() => { - mParticle.logPageView(); - - const pageViewEvent = findEventFromRequest( - fetchMock.calls(), - 'screen_view' - ); - - Should(pageViewEvent).be.ok(); - - pageViewEvent.data.should.have.property('custom_attributes'); - pageViewEvent.data.custom_attributes.should.have.property( - 'hostname', - window.location.hostname - ); - pageViewEvent.data.custom_attributes.should.have.property( - 'title', - window.document.title - ); - - done(); - }) - }); - - it('should log custom page view', function(done) { - waitForCondition(hasIdentifyReturned) - .then(() => { - mParticle.logPageView( - 'My Page View', - { testattr: 1 }, - { - 'MyCustom.Flag': 'Test', - } - ); - - const pageViewEvent = findEventFromRequest( - fetchMock.calls(), - 'My Page View' - ); - - Should(pageViewEvent).be.ok(); - - pageViewEvent.data.should.have.property('custom_attributes'); - pageViewEvent.data.should.have.property('screen_name', 'My Page View'); - pageViewEvent.data.custom_attributes.should.have.property( - 'testattr', - 1 - ); - pageViewEvent.data.custom_flags.should.have.property( - 'MyCustom.Flag', - 'Test' - ); - - done(); - }) - }); + it('should log an error with custom attrs', function (done) { + waitForCondition(hasIdentifyReturned).then(() => { + const error = new Error('my error'); + error.stack = 'my stacktrace'; - it('should pass custom flags in page views', function(done) { - waitForCondition(hasIdentifyReturned) - .then(() => { - mParticle.logPageView('test', null, { - 'MyCustom.Flag': 'Test', - }); - - const pageViewEvent = findEventFromRequest( - fetchMock.calls(), - 'test' - ); - - Should(pageViewEvent).be.ok(); + mParticle.logError(error, { + location: 'my path', + myData: 'my data', + }); - pageViewEvent.data.should.have.property('custom_flags'); - pageViewEvent.data.custom_flags.should.have.property( - 'MyCustom.Flag', - 'Test' - ); + const errorEvent = findEventFromRequest( + fetchMock.calls(), + 'my error', + ); - done(); - }) - }); + Should(errorEvent).be.ok(); + errorEvent.data.should.have.property('message', 'Error'); + errorEvent.data.should.have.property('custom_attributes'); + errorEvent.data.custom_attributes.should.have.property( + 'location', + 'my path', + ); + errorEvent.data.custom_attributes.should.have.property( + 'myData', + 'my data', + ); - it('should allow a page view to bypass server upload', function(done) { - waitForCondition(hasIdentifyReturned) - .then(() => { - mParticle.logPageView('test bypass', null, null, { - shouldUploadEvent: false, + done(); }); - - const pageViewEvent = findEventFromRequest( - fetchMock.calls(), - 'test bypass' - ); - - Should(pageViewEvent).not.be.ok(); - done(); - }) }); - it('should not log a PageView event if there are invalid attrs', function(done) { - waitForCondition(hasIdentifyReturned) - .then(() => { - mParticle.logPageView('test1', 'invalid', null); - const pageViewEvent = findEventFromRequest( - fetchMock.calls(), - 'test1' - ); - - Should(pageViewEvent).not.be.ok(); + it('should sanitize error custom attrs', function (done) { + waitForCondition(hasIdentifyReturned).then(() => { + const bond = sinon.spy(mParticle.getInstance().Logger, 'warning'); + mParticle.logError('my error', { + invalid: ['my invalid attr'], + valid: 10, + }); - done(); - }) - }); + const errorEvent = findEventFromRequest( + fetchMock.calls(), + 'my error', + ); - it('should not log an event that has an invalid customFlags', function(done) { - waitForCondition(hasIdentifyReturned) - .then(() => { - mParticle.logPageView('test', null, 'invalid'); + Should(errorEvent).be.ok(); + errorEvent.data.should.have.property('message', 'Error'); + errorEvent.data.should.have.property('custom_attributes'); + errorEvent.data.custom_attributes.should.have.property('valid', 10); + errorEvent.data.custom_attributes.should.not.have.property( + 'invalid', + ); - const pageViewEvent = findEventFromRequest( - fetchMock.calls(), - 'test' - ); - Should(pageViewEvent).not.be.ok(); + bond.called.should.eql(true); + bond.callCount.should.equal(1); - done(); - }) - }); + bond.getCalls()[0].args[0].should.eql( + "For 'my error', the corresponding attribute value of 'invalid' must be a string, number, boolean, or null.", + ); - it('should log event with name PageView when an invalid event name is passed', function(done) { - waitForCondition(hasIdentifyReturned) - .then(() => { - fetchMock.resetHistory(); - - mParticle.logPageView(null); - fetchMock.calls().length.should.equal(1); - const pageViewEvent = findEventFromRequest( - fetchMock.calls(), - 'screen_view' - ); - pageViewEvent.data.screen_name.should.equal('PageView'); - - fetchMock.resetHistory(); - mParticle.logPageView({ test: 'test' }); - fetchMock.calls().length.should.equal(1); - const pageViewEvent2 = findEventFromRequest( - fetchMock.calls(), - 'screen_view' - ); - pageViewEvent2.data.screen_name.should.equal('PageView'); - - fetchMock.resetHistory(); - mParticle.logPageView([1, 2, 3]); - fetchMock.calls().length.should.equal(1); - const pageViewEvent3 = findEventFromRequest( - fetchMock.calls(), - 'screen_view' - ); - pageViewEvent3.data.screen_name.should.equal('PageView'); - - done(); - }) + done(); + }); }); - it('should log opt out', function(done) { - waitForCondition(hasIdentifyReturned) - .then(() => { - mParticle.setOptOut(true); - - const optOutEvent = findEventFromRequest(fetchMock.calls(), 'opt_out'); - - optOutEvent.event_type.should.equal('opt_out'); - optOutEvent.data.should.have.property('is_opted_out', true); - - done(); - }) - }); + it('should log an AST with firstRun = true when first visiting a page, and firstRun = false when reloading the page', function (done) { + waitForCondition(hasIdentifyReturned).then(() => { + const astEvent = findEventFromRequest( + fetchMock.calls(), + 'application_state_transition', + ); - it('log event requires name', function(done) { - waitForCondition(hasIdentifyReturned) - .then(() => { - fetchMock.resetHistory(); - mParticle.logEvent(); - - fetchMock.calls().should.have.lengthOf(0); - - done(); - }) - }); + astEvent.data.should.have.property( + 'application_transition_type', + 'application_initialized', + ); + astEvent.data.should.have.property('is_first_run', true); + astEvent.data.should.have.property('is_upgrade', false); + + if (document.referrer && document.referrer.length > 0) { + astEvent.data.should.have.property( + 'launch_referral', + window.location.href, + ); + } - it('log event requires valid event type', function(done) { - waitForCondition(hasIdentifyReturned) - .then(() => { - fetchMock.resetHistory(); + fetchMock.resetHistory(); - mParticle.logEvent('test', 100); + mParticle.init(apiKey, window.mParticle.config); + waitForCondition(() => { + return ( + mParticle.getInstance()._Store.identityCallInFlight === + false + ); + }).then(() => { + const astEvent2 = findEventFromRequest( + fetchMock.calls(), + 'application_state_transition', + ); - fetchMock.calls().should.have.lengthOf(0); + astEvent2.data.should.have.property('is_first_run', false); - done(); + done(); + }); }); }); - it('event attributes must be object', function(done) { - waitForCondition(hasIdentifyReturned) - .then(() => { - mParticle.logEvent('Test Event', null, 1); - - const testEvent = findEventFromRequest(fetchMock.calls(), 'Test Event'); - - testEvent.data.should.have.property('custom_attributes', null); - - done(); + it('should log an AST on init with firstRun = false when cookies already exist', function (done) { + waitForCondition(hasIdentifyReturned).then(() => { + // cookies currently exist, mParticle.init called from beforeEach + fetchMock.resetHistory(); + // log second AST + waitForCondition(() => { + return ( + mParticle.getInstance()._Store.identityCallInFlight === + false + ); + }).then(() => { + mParticle.init(apiKey, window.mParticle.config); + + const astEvent = findEventFromRequest( + fetchMock.calls(), + 'application_state_transition', + ); + astEvent.data.should.have.property('is_first_run', false); + + done(); + }); }); }); - it('opting out should prevent events being sent', function(done) { - waitForCondition(hasIdentifyReturned) - .then(() => { - mParticle.setOptOut(true); - fetchMock.resetHistory(); + it('should log a page view', function (done) { + waitForCondition(hasIdentifyReturned).then(() => { + mParticle.logPageView(); - mParticle.logEvent('test'); - fetchMock.calls().should.have.lengthOf(0); - - done(); - }); - }); + const pageViewEvent = findEventFromRequest( + fetchMock.calls(), + 'screen_view', + ); - it('after logging optout, and reloading, events still should not be sent until opt out is enabled when using local storage', function(done) { - waitForCondition(hasIdentifyReturned) - .then(() => { - mParticle.setOptOut(true); - fetchMock.resetHistory(); + Should(pageViewEvent).be.ok(); - mParticle.logEvent('test'); - fetchMock.calls().should.have.lengthOf(0); + pageViewEvent.data.should.have.property('custom_attributes'); + pageViewEvent.data.custom_attributes.should.have.property( + 'hostname', + window.location.hostname, + ); + pageViewEvent.data.custom_attributes.should.have.property( + 'title', + window.document.title, + ); - mParticle.setOptOut(false); + done(); + }); + }); - mParticle.init(apiKey, window.mParticle.config); - fetchMock.resetHistory(); + it('should log custom page view', function (done) { + waitForCondition(hasIdentifyReturned).then(() => { + mParticle.logPageView( + 'My Page View', + { testattr: 1 }, + { + 'MyCustom.Flag': 'Test', + }, + ); - mParticle.logEvent('test'); - fetchMock.calls().should.have.lengthOf(1); + const pageViewEvent = findEventFromRequest( + fetchMock.calls(), + 'My Page View', + ); - mParticle.setOptOut(true); - mParticle.init(apiKey, window.mParticle.config); - fetchMock.resetHistory(); + Should(pageViewEvent).be.ok(); - mParticle.logEvent('test'); - fetchMock.calls().should.have.lengthOf(0); + pageViewEvent.data.should.have.property('custom_attributes'); + pageViewEvent.data.should.have.property( + 'screen_name', + 'My Page View', + ); + pageViewEvent.data.custom_attributes.should.have.property( + 'testattr', + 1, + ); + pageViewEvent.data.custom_flags.should.have.property( + 'MyCustom.Flag', + 'Test', + ); - done(); - }) + done(); + }); }); - it('after logging optout, and reloading, events still should not be sent until opt out is enabled when using cookie storage', function(done) { - waitForCondition(hasIdentifyReturned) - .then(() => { - mParticle.config.useCookieStorage = true; - mParticle.init(apiKey, window.mParticle.config); - mParticle.setOptOut(true); - fetchMock.resetHistory(); + it('should pass custom flags in page views', function (done) { + waitForCondition(hasIdentifyReturned).then(() => { + mParticle.logPageView('test', null, { + 'MyCustom.Flag': 'Test', + }); - mParticle.logEvent('test'); - fetchMock.calls().should.have.lengthOf(0); + const pageViewEvent = findEventFromRequest( + fetchMock.calls(), + 'test', + ); - mParticle.setOptOut(false); + Should(pageViewEvent).be.ok(); - mParticle.init(apiKey, window.mParticle.config); - waitForCondition(() => { - return ( - mParticle.getInstance()._Store.identityCallInFlight === false - ); - }) - .then(() => { - fetchMock.resetHistory(); - mParticle.logEvent('test'); - fetchMock.calls().should.have.lengthOf(1); - - mParticle.setOptOut(true); - mParticle.init(apiKey, window.mParticle.config); - waitForCondition(() => { - return ( - mParticle.getInstance()._Store.identityCallInFlight === false + pageViewEvent.data.should.have.property('custom_flags'); + pageViewEvent.data.custom_flags.should.have.property( + 'MyCustom.Flag', + 'Test', ); - }) - .then(() => { - fetchMock.resetHistory(); - mParticle.logEvent('test'); - fetchMock.calls().should.have.lengthOf(0); - - done(); - }); + + done(); }); - }) }); - it('should log identify event', function(done) { - fetchMockSuccess(urls.identify, { - mpid: testMPID, is_logged_in: false + it('should allow a page view to bypass server upload', function (done) { + waitForCondition(hasIdentifyReturned).then(() => { + mParticle.logPageView('test bypass', null, null, { + shouldUploadEvent: false, }); - waitForCondition(hasIdentifyReturned) - .then(() => { - mParticle.Identity.identify(); - waitForCondition(() => { - return ( - mParticle.getInstance()._Store.identityCallInFlight === false + + const pageViewEvent = findEventFromRequest( + fetchMock.calls(), + 'test bypass', ); - }) - .then(() => { - const data = getIdentityEvent(mockServer.requests, 'identify'); - data.should.have.properties( - 'client_sdk', - 'environment', - 'known_identities', - 'previous_mpid', - 'request_id', - 'request_timestamp_ms', - 'context' - ); - }); - done(); - }); - }); - it('should log logout event', function(done) { - fetchMockSuccess(urls.logout, { - mpid: 'logoutMPID', is_logged_in: false + Should(pageViewEvent).not.be.ok(); + done(); }); + }); - waitForCondition(hasIdentifyReturned) - .then(() => { - mParticle.Identity.logout(); - waitForCondition(() => { - return ( - mParticle.Identity.getCurrentUser()?.getMPID() === 'logoutMPID' + it('should not log a PageView event if there are invalid attrs', function (done) { + waitForCondition(hasIdentifyReturned).then(() => { + mParticle.logPageView('test1', 'invalid', null); + const pageViewEvent = findEventFromRequest( + fetchMock.calls(), + 'test1', ); - }) - .then(() => { - const data = getIdentityEvent(fetchMock.calls(), 'logout'); - data.should.have.properties( - 'client_sdk', - 'environment', - 'known_identities', - 'previous_mpid', - 'request_id', - 'request_timestamp_ms', - 'context' - ); - - done(); - }) - }) - }); - it('should log login event', function(done) { - fetchMockSuccess(urls.login, { - mpid: 'loginMPID', is_logged_in: false + Should(pageViewEvent).not.be.ok(); + + done(); }); + }); + + it('should not log an event that has an invalid customFlags', function (done) { + waitForCondition(hasIdentifyReturned).then(() => { + mParticle.logPageView('test', null, 'invalid'); - waitForCondition(hasIdentifyReturned) - .then(() => { - mParticle.Identity.login(); - waitForCondition(() => { - return ( - mParticle.Identity.getCurrentUser()?.getMPID() === 'loginMPID' + const pageViewEvent = findEventFromRequest( + fetchMock.calls(), + 'test', ); - }) - .then(() => { - const data = getIdentityEvent(fetchMock.calls(), 'login'); - data.should.have.properties( - 'client_sdk', - 'environment', - 'known_identities', - 'previous_mpid', - 'request_id', - 'request_timestamp_ms', - 'context' - ); - - done(); - }) - }) - }); + Should(pageViewEvent).not.be.ok(); - it('should log modify event', function(done) { - waitForCondition(hasIdentifyReturned) - .then(() => { - fetchMockSuccess(urls.modify, { - change_results: [ - { - identity_type: 'email', - modified_mpid: testMPID, - }, - ] + done(); }); - mParticle.Identity.modify(); - waitForCondition(() => { - return ( - mParticle.getInstance()._Store.identityCallInFlight === false - ); - }).then(() => { - const data = getIdentityEvent(fetchMock.calls(), 'modify'); - data.should.have.properties( - 'client_sdk', - 'environment', - 'identity_changes', - 'request_id', - 'request_timestamp_ms', - 'context' - ); - - done(); - }) - }) }); - it('should send das with each event logged', function(done) { - waitForCondition(hasIdentifyReturned) - .then(() => { - window.mParticle.logEvent('Test Event'); - const testEventBatch = findBatch(fetchMock.calls(), 'Test Event'); + it('should log event with name PageView when an invalid event name is passed', function (done) { + waitForCondition(hasIdentifyReturned).then(() => { + fetchMock.resetHistory(); - testEventBatch.should.have.property('mp_deviceid'); - testEventBatch.mp_deviceid.length.should.equal(36); - done(); - }) - }); - - it('should send consent state with each event logged', function(done) { - waitForCondition(hasIdentifyReturned) - .then(() => { - const consentState = mParticle.Consent.createConsentState(); - consentState.addGDPRConsentState( - 'foo purpose', - mParticle.Consent.createGDPRConsent( - true, - 10, - 'foo document', - 'foo location', - 'foo hardwareId' - ) - ); - mParticle.Identity.getCurrentUser().setConsentState(consentState); - - window.mParticle.logEvent('Test Event'); - const testEvent = findBatch(fetchMock.calls(), 'Test Event'); - - testEvent.should.have.property('consent_state'); - testEvent.consent_state.should.have.property('gdpr'); - testEvent.consent_state.gdpr.should.have.property('foo purpose'); - - const purpose = testEvent.consent_state.gdpr['foo purpose']; - purpose.should.have.property('timestamp_unixtime_ms', 10); - purpose.should.have.property('document', 'foo document'); - purpose.should.have.property('location', 'foo location'); - purpose.should.have.property('hardware_id', 'foo hardwareId'); - - mParticle.Identity.getCurrentUser().setConsentState(null); - - window.mParticle.logEvent('Test Event2'); - const testEvent2 = findBatch(fetchMock.calls(), 'Test Event2'); - - testEvent2.should.have.property('consent_state', null); - - done(); - }) + mParticle.logPageView(null); + fetchMock.calls().length.should.equal(1); + const pageViewEvent = findEventFromRequest( + fetchMock.calls(), + 'screen_view', + ); + pageViewEvent.data.screen_name.should.equal('PageView'); + + fetchMock.resetHistory(); + mParticle.logPageView({ test: 'test' }); + fetchMock.calls().length.should.equal(1); + const pageViewEvent2 = findEventFromRequest( + fetchMock.calls(), + 'screen_view', + ); + pageViewEvent2.data.screen_name.should.equal('PageView'); + + fetchMock.resetHistory(); + mParticle.logPageView([1, 2, 3]); + fetchMock.calls().length.should.equal(1); + const pageViewEvent3 = findEventFromRequest( + fetchMock.calls(), + 'screen_view', + ); + pageViewEvent3.data.screen_name.should.equal('PageView'); + done(); + }); }); - it('should log integration attributes with each event', function(done) { - waitForCondition(hasIdentifyReturned) - .then(() => { - mParticle.setIntegrationAttribute(128, { MCID: 'abcdefg' }); - mParticle.logEvent('Test Event'); - const testEvent = findBatch(fetchMock.calls(), 'Test Event'); + it('should log opt out', function (done) { + waitForCondition(hasIdentifyReturned).then(() => { + mParticle.setOptOut(true); - testEvent.should.have.property('integration_attributes'); - testEvent.integration_attributes.should.have.property('128'); - testEvent.integration_attributes['128'].should.have.property( - 'MCID', - 'abcdefg' - ); + const optOutEvent = findEventFromRequest( + fetchMock.calls(), + 'opt_out', + ); - done(); - }) + optOutEvent.event_type.should.equal('opt_out'); + optOutEvent.data.should.have.property('is_opted_out', true); + done(); + }); }); - it('should run the callback once when tracking succeeds', function(done) { - waitForCondition(hasIdentifyReturned) - .then(() => { - const clock = sinon.useFakeTimers(); - - mParticle.init(apiKey, window.mParticle.config); + it('log event requires name', function (done) { + waitForCondition(hasIdentifyReturned).then(() => { + fetchMock.resetHistory(); + mParticle.logEvent(); - let successCallbackCalled = false; - let numberTimesCalled = 0; + fetchMock.calls().should.have.lengthOf(0); - mParticle.startTrackingLocation(function() { - numberTimesCalled += 1; - successCallbackCalled = true; - mParticle.logEvent('Test Event'); + done(); }); + }); - // mock geo will successfully run after 1 second (geomock.js // navigator.geolocation.delay) - clock.tick(1000); - successCallbackCalled.should.equal(true); - let testEvent = findEventFromRequest(fetchMock.calls(), 'Test Event'); + it('log event requires valid event type', function (done) { + waitForCondition(hasIdentifyReturned).then(() => { + fetchMock.resetHistory(); - testEvent.data.location.latitude.should.equal(52.5168); - testEvent.data.location.longitude.should.equal(13.3889); - fetchMock.resetHistory(); + mParticle.logEvent('test', 100); - //this will hit the watch position again, but won't call the callback again - clock.tick(1000); - numberTimesCalled.should.equal(1); + fetchMock.calls().should.have.lengthOf(0); - testEvent = findEventFromRequest(fetchMock.calls(), 'Test Event'); + done(); + }); + }); - Should(testEvent).not.be.ok(); + it('event attributes must be object', function (done) { + waitForCondition(hasIdentifyReturned).then(() => { + mParticle.logEvent('Test Event', null, 1); - clock.restore(); + const testEvent = findEventFromRequest( + fetchMock.calls(), + 'Test Event', + ); - done(); - }) + testEvent.data.should.have.property('custom_attributes', null); + done(); + }); }); - it('should run the callback once when tracking fails', function(done) { - waitForCondition(hasIdentifyReturned) - .then(() => { - const clock = sinon.useFakeTimers(); + it('opting out should prevent events being sent', function (done) { + waitForCondition(hasIdentifyReturned).then(() => { + mParticle.setOptOut(true); + fetchMock.resetHistory(); - mParticle.init(apiKey, window.mParticle.config); - - waitForCondition(() => { - return ( - mParticle.getInstance()._Store.identityCallInFlight === false - ); - }) - .then(() => { - - let successCallbackCalled = false; - let numberTimesCalled = 0; - - navigator.geolocation.shouldFail = true; + mParticle.logEvent('test'); + fetchMock.calls().should.have.lengthOf(0); - mParticle.startTrackingLocation(function() { - numberTimesCalled += 1; - successCallbackCalled = true; - mParticle.logEvent('Test Event'); + done(); }); + }); + + it('after logging optout, and reloading, events still should not be sent until opt out is enabled when using local storage', function (done) { + waitForCondition(hasIdentifyReturned).then(() => { + mParticle.setOptOut(true); + fetchMock.resetHistory(); - // mock geo will successfully run after 1 second (geomock.js // navigator.geolocation.delay) - clock.tick(1000); - successCallbackCalled.should.equal(true); + mParticle.logEvent('test'); + fetchMock.calls().should.have.lengthOf(0); - let testEvent = findEventFromRequest(fetchMock.calls(), 'Test Event'); + mParticle.setOptOut(false); - testEvent.data.should.have.property('location', null); - fetchMock.resetHistory(); + mParticle.init(apiKey, window.mParticle.config); + fetchMock.resetHistory(); - //this will hit the watch position again, but won't call the callback again - clock.tick(1000); - numberTimesCalled.should.equal(1); - testEvent = findEventFromRequest(fetchMock.calls(), 'Test Event'); - Should(testEvent).not.be.ok(); + mParticle.logEvent('test'); + fetchMock.calls().should.have.lengthOf(1); - navigator.geolocation.shouldFail = false; + mParticle.setOptOut(true); + mParticle.init(apiKey, window.mParticle.config); + fetchMock.resetHistory(); - clock.restore(); + mParticle.logEvent('test'); + fetchMock.calls().should.have.lengthOf(0); - done(); - }) - }) + done(); + }); }); - it('should pass the found or existing position to the callback in startTrackingLocation', function(done) { - waitForCondition(hasIdentifyReturned) - .then(() => { - mParticle.init(apiKey, window.mParticle.config); - waitForCondition(() => { - return ( - mParticle.getInstance()._Store.identityCallInFlight === false - ); - }) - .then(() => { - let currentPosition; + it('after logging optout, and reloading, events still should not be sent until opt out is enabled when using cookie storage', function (done) { + waitForCondition(hasIdentifyReturned).then(() => { + mParticle.config.useCookieStorage = true; + mParticle.init(apiKey, window.mParticle.config); + mParticle.setOptOut(true); + fetchMock.resetHistory(); + + mParticle.logEvent('test'); + fetchMock.calls().should.have.lengthOf(0); + + mParticle.setOptOut(false); + + mParticle.init(apiKey, window.mParticle.config); + waitForCondition(() => { + return ( + mParticle.getInstance()._Store.identityCallInFlight === + false + ); + }).then(() => { + fetchMock.resetHistory(); + mParticle.logEvent('test'); + fetchMock.calls().should.have.lengthOf(1); + + mParticle.setOptOut(true); + mParticle.init(apiKey, window.mParticle.config); + waitForCondition(() => { + return ( + mParticle.getInstance()._Store.identityCallInFlight === + false + ); + }).then(() => { + fetchMock.resetHistory(); + mParticle.logEvent('test'); + fetchMock.calls().should.have.lengthOf(0); + + done(); + }); + }); + }); + }); - function callback(position) { - currentPosition = position; - } - const clock = sinon.useFakeTimers(); - mParticle.startTrackingLocation(callback); + it('should log identify event', function (done) { + fetchMockSuccess(urls.identify, { + mpid: testMPID, + is_logged_in: false, + }); + waitForCondition(hasIdentifyReturned).then(() => { + mParticle.Identity.identify(); + waitForCondition(() => { + return ( + mParticle.getInstance()._Store.identityCallInFlight === + false + ); + }).then(() => { + const data = getIdentityEvent(mockServer.requests, 'identify'); + data.should.have.properties( + 'client_sdk', + 'environment', + 'known_identities', + 'previous_mpid', + 'request_id', + 'request_timestamp_ms', + 'context', + ); + }); + done(); + }); + }); - // mock geo will successfully run after 1 second (geomock.js // navigator.geolocation.delay) + it('should log logout event', function (done) { + fetchMockSuccess(urls.logout, { + mpid: 'logoutMPID', + is_logged_in: false, + }); - clock.tick(1000); - const latitudeResult = 52.5168; - const longitudeResult = 13.3889; + waitForCondition(hasIdentifyReturned).then(() => { + mParticle.Identity.logout(); + waitForCondition(() => { + return ( + mParticle.Identity.getCurrentUser()?.getMPID() === + 'logoutMPID' + ); + }).then(() => { + const data = getIdentityEvent(fetchMock.calls(), 'logout'); + data.should.have.properties( + 'client_sdk', + 'environment', + 'known_identities', + 'previous_mpid', + 'request_id', + 'request_timestamp_ms', + 'context', + ); + + done(); + }); + }); + }); - currentPosition.coords.latitude.should.equal(latitudeResult); - currentPosition.coords.longitude.should.equal(longitudeResult); + it('should log login event', function (done) { + fetchMockSuccess(urls.login, { + mpid: 'loginMPID', + is_logged_in: false, + }); - clock.restore(); + waitForCondition(hasIdentifyReturned).then(() => { + mParticle.Identity.login(); + waitForCondition(() => { + return ( + mParticle.Identity.getCurrentUser()?.getMPID() === + 'loginMPID' + ); + }).then(() => { + const data = getIdentityEvent(fetchMock.calls(), 'login'); + data.should.have.properties( + 'client_sdk', + 'environment', + 'known_identities', + 'previous_mpid', + 'request_id', + 'request_timestamp_ms', + 'context', + ); + + done(); + }); + }); + }); - done(); - }) - }) + it('should log modify event', function (done) { + waitForCondition(hasIdentifyReturned).then(() => { + fetchMockSuccess(urls.modify, { + change_results: [ + { + identity_type: 'email', + modified_mpid: testMPID, + }, + ], + }); + mParticle.Identity.modify(); + waitForCondition(() => { + return ( + mParticle.getInstance()._Store.identityCallInFlight === + false + ); + }).then(() => { + const data = getIdentityEvent(fetchMock.calls(), 'modify'); + data.should.have.properties( + 'client_sdk', + 'environment', + 'identity_changes', + 'request_id', + 'request_timestamp_ms', + 'context', + ); + + done(); + }); + }); }); - it('should run the callback if tracking already exists', function(done) { - waitForCondition(hasIdentifyReturned) - .then(() => { + it('should send das with each event logged', function (done) { + waitForCondition(hasIdentifyReturned).then(() => { + window.mParticle.logEvent('Test Event'); + const testEventBatch = findBatch(fetchMock.calls(), 'Test Event'); - mParticle.init(apiKey, window.mParticle.config); + testEventBatch.should.have.property('mp_deviceid'); + testEventBatch.mp_deviceid.length.should.equal(36); + done(); + }); + }); - waitForCondition(() => { - return ( - mParticle.getInstance()._Store.identityCallInFlight === false + it('should send consent state with each event logged', function (done) { + waitForCondition(hasIdentifyReturned).then(() => { + const consentState = mParticle.Consent.createConsentState(); + consentState.addGDPRConsentState( + 'foo purpose', + mParticle.Consent.createGDPRConsent( + true, + 10, + 'foo document', + 'foo location', + 'foo hardwareId', + ), ); - }) - .then(() => { + mParticle.Identity.getCurrentUser().setConsentState(consentState); - const clock = sinon.useFakeTimers(); + window.mParticle.logEvent('Test Event'); + const testEvent = findBatch(fetchMock.calls(), 'Test Event'); - mParticle.startTrackingLocation(); - let successCallbackCalled = false; - function callback() { - successCallbackCalled = true; - mParticle.logEvent('Test Event'); - } - mParticle.startTrackingLocation(callback); + testEvent.should.have.property('consent_state'); + testEvent.consent_state.should.have.property('gdpr'); + testEvent.consent_state.gdpr.should.have.property('foo purpose'); + + const purpose = testEvent.consent_state.gdpr['foo purpose']; + purpose.should.have.property('timestamp_unixtime_ms', 10); + purpose.should.have.property('document', 'foo document'); + purpose.should.have.property('location', 'foo location'); + purpose.should.have.property('hardware_id', 'foo hardwareId'); - // mock geo will successfully run after 1 second (geomock.js // navigator.geolocation.delay) - clock.tick(1000); - successCallbackCalled.should.equal(true); - const testEvent = findEventFromRequest(fetchMock.calls(), 'Test Event'); + mParticle.Identity.getCurrentUser().setConsentState(null); - const latitudeResult = 52.5168; - const longitudeResult = 13.3889; - testEvent.data.location.latitude.should.equal(latitudeResult); - testEvent.data.location.longitude.should.equal(longitudeResult); + window.mParticle.logEvent('Test Event2'); + const testEvent2 = findBatch(fetchMock.calls(), 'Test Event2'); - clock.restore(); + testEvent2.should.have.property('consent_state', null); - done(); - }) - }) + done(); + }); }); - it('should log appName in the payload on v3 endpoint when set on config prior to init', function(done) { - mParticle.config.appName = 'a name'; - mParticle.config.flags = { - eventBatchingIntervalMillis: 0, - }; + it('should log integration attributes with each event', function (done) { + waitForCondition(hasIdentifyReturned).then(() => { + mParticle.setIntegrationAttribute(128, { MCID: 'abcdefg' }); + mParticle.logEvent('Test Event'); + const testEvent = findBatch(fetchMock.calls(), 'Test Event'); - waitForCondition(hasIdentifyReturned) - .then(() => { - mParticle.init(apiKey, mParticle.config); - waitForCondition(() => { - return ( - mParticle.getInstance()._Store.identityCallInFlight === false + testEvent.should.have.property('integration_attributes'); + testEvent.integration_attributes.should.have.property('128'); + testEvent.integration_attributes['128'].should.have.property( + 'MCID', + 'abcdefg', ); - }) - .then(() => { - - window.mParticle.logEvent('Test Event'); - const batch = JSON.parse(fetchMock.lastOptions().body); - - batch.application_info.should.have.property( - 'application_name', - 'a name' - ); - - delete window.mParticle.config.flags; - - done(); - }) - }) + done(); + }); }); - it('should log AST first_run as true on new page loads, and false for when a page has previously been loaded', function(done) { - waitForCondition(hasIdentifyReturned) - .then(() => { - mParticle._resetForTests(MPConfig); + it('should run the callback once when tracking succeeds', function (done) { + waitForCondition(hasIdentifyReturned).then(() => { + const clock = sinon.useFakeTimers(); - mParticle.init(apiKey, mParticle.config); + mParticle.init(apiKey, window.mParticle.config); - waitForCondition(() => { - return ( - mParticle.getInstance()._Store.identityCallInFlight === false - ); - }) - .then(() => { + let successCallbackCalled = false; + let numberTimesCalled = 0; - const batch = JSON.parse(fetchMock.lastOptions().body); - batch.events[0].data.should.have.property('is_first_run', true); + mParticle.startTrackingLocation(function () { + numberTimesCalled += 1; + successCallbackCalled = true; + mParticle.logEvent('Test Event'); + }); - waitForCondition(() => { - return ( - mParticle.getInstance()._Store.identityCallInFlight === false + // mock geo will successfully run after 1 second (geomock.js // navigator.geolocation.delay) + clock.tick(1000); + successCallbackCalled.should.equal(true); + let testEvent = findEventFromRequest( + fetchMock.calls(), + 'Test Event', ); - }) - .then(() => { - mParticle.init(apiKey, mParticle.config); - const batch2 = JSON.parse(fetchMock.lastOptions().body); - batch2.events[0].data.should.have.property('is_first_run', false); + testEvent.data.location.latitude.should.equal(52.5168); + testEvent.data.location.longitude.should.equal(13.3889); + fetchMock.resetHistory(); - delete window.mParticle.config.flags; + //this will hit the watch position again, but won't call the callback again + clock.tick(1000); + numberTimesCalled.should.equal(1); - done(); - }) - }) - }) - }); + testEvent = findEventFromRequest(fetchMock.calls(), 'Test Event'); - it('should log AST with launch_referral with a url', function(done) { - waitForCondition(hasIdentifyReturned) - .then(() => { - mParticle._resetForTests(MPConfig); + Should(testEvent).not.be.ok(); - mParticle.config.flags = { - eventBatchingIntervalMillis: 0, - }; + clock.restore(); - mParticle.init(apiKey, mParticle.config); - waitForCondition(() => { - return ( - mParticle.getInstance()._Store.identityCallInFlight === false - ); - }) - .then(() => { + done(); + }); + }); + it('should run the callback once when tracking fails', function (done) { + waitForCondition(hasIdentifyReturned).then(() => { + const clock = sinon.useFakeTimers(); - const batch = JSON.parse(fetchMock.lastOptions().body); - batch.events[0].data.should.have.property('launch_referral'); - batch.events[0].data.launch_referral.should.startWith( - 'http://localhost' - ); + mParticle.init(apiKey, window.mParticle.config); - delete window.mParticle.config.flags; + waitForCondition(() => { + return ( + mParticle.getInstance()._Store.identityCallInFlight === + false + ); + }).then(() => { + let successCallbackCalled = false; + let numberTimesCalled = 0; - done(); - }) - }) + navigator.geolocation.shouldFail = true; - }); + mParticle.startTrackingLocation(function () { + numberTimesCalled += 1; + successCallbackCalled = true; + mParticle.logEvent('Test Event'); + }); - it('should log appName in the payload on v3 endpoint when set on config prior to init', function(done) { - waitForCondition(hasIdentifyReturned) - .then(() => { - mParticle.config.flags = { - eventBatchingIntervalMillis: 0, - }; - waitForCondition(() => { - return ( - mParticle.getInstance()._Store.identityCallInFlight === false - ); - }).then(() => { + // mock geo will successfully run after 1 second (geomock.js // navigator.geolocation.delay) + clock.tick(1000); + successCallbackCalled.should.equal(true); + let testEvent = findEventFromRequest( + fetchMock.calls(), + 'Test Event', + ); - mParticle.init(apiKey, mParticle.config); - mParticle.setAppName('another name'); + testEvent.data.should.have.property('location', null); + fetchMock.resetHistory(); - window.mParticle.logEvent('Test Event'); + //this will hit the watch position again, but won't call the callback again + clock.tick(1000); + numberTimesCalled.should.equal(1); + testEvent = findEventFromRequest( + fetchMock.calls(), + 'Test Event', + ); + Should(testEvent).not.be.ok(); - const batch = JSON.parse(fetchMock.lastOptions().body); - batch.application_info.should.have.property( - 'application_name', - 'another name' - ); + navigator.geolocation.shouldFail = false; - delete window.mParticle.config.flags; + clock.restore(); - done(); - }) - }) + done(); + }); + }); }); - it('should log a batch to v3 with data planning in the payload', function(done) { - mParticle.config.logLevel = 'verbose'; - mParticle.config.flags = { - eventBatchingIntervalMillis: 0, - }; - mParticle.config.dataPlan = { - planId: 'plan_slug', - planVersion: 10, - }; - - waitForCondition(hasIdentifyReturned) - .then(() => { - mParticle.init(apiKey, mParticle.config); + it('should pass the found or existing position to the callback in startTrackingLocation', function (done) { + waitForCondition(hasIdentifyReturned).then(() => { + mParticle.init(apiKey, window.mParticle.config); + waitForCondition(() => { + return ( + mParticle.getInstance()._Store.identityCallInFlight === + false + ); + }).then(() => { + let currentPosition; + + function callback(position) { + currentPosition = position; + } + const clock = sinon.useFakeTimers(); + mParticle.startTrackingLocation(callback); - waitForCondition(() => { - return ( - mParticle.getInstance()._Store.identityCallInFlight === false - ); - }) - .then(() => { - window.mParticle.logEvent('Test Event'); + // mock geo will successfully run after 1 second (geomock.js // navigator.geolocation.delay) - const batch = JSON.parse(fetchMock.lastOptions().body); + clock.tick(1000); + const latitudeResult = 52.5168; + const longitudeResult = 13.3889; - batch.should.have.property('context'); - batch.context.should.have.property('data_plan'); - batch.context.data_plan.should.have.property('plan_version', 10); - batch.context.data_plan.should.have.property('plan_id', 'plan_slug'); + currentPosition.coords.latitude.should.equal(latitudeResult); + currentPosition.coords.longitude.should.equal(longitudeResult); - delete window.mParticle.config.flags; + clock.restore(); - done(); - }) - }) + done(); + }); + }); }); - it('should log a batch to v3 with no version if no version is passed', function(done) { - waitForCondition(hasIdentifyReturned) - .then(() => { - mParticle.config.flags = { - eventBatchingIntervalMillis: 0, - }; - mParticle.config.dataPlan = { - planId: 'plan_slug', - }; - - mParticle.init(apiKey, mParticle.config); - waitForCondition(() => { - return ( - mParticle.getInstance()._Store.identityCallInFlight === false - ); - }) - .then(() => { - window.mParticle.logEvent('Test Event'); + it('should run the callback if tracking already exists', function (done) { + waitForCondition(hasIdentifyReturned).then(() => { + mParticle.init(apiKey, window.mParticle.config); + + waitForCondition(() => { + return ( + mParticle.getInstance()._Store.identityCallInFlight === + false + ); + }).then(() => { + const clock = sinon.useFakeTimers(); + + mParticle.startTrackingLocation(); + let successCallbackCalled = false; + function callback() { + successCallbackCalled = true; + mParticle.logEvent('Test Event'); + } + mParticle.startTrackingLocation(callback); - const batch = JSON.parse(fetchMock.lastOptions().body); + // mock geo will successfully run after 1 second (geomock.js // navigator.geolocation.delay) + clock.tick(1000); + successCallbackCalled.should.equal(true); + const testEvent = findEventFromRequest( + fetchMock.calls(), + 'Test Event', + ); - batch.should.have.property('context'); - batch.context.should.have.property('data_plan'); - batch.context.data_plan.should.not.have.property('plan_version'); - batch.context.data_plan.should.have.property('plan_id', 'plan_slug'); + const latitudeResult = 52.5168; + const longitudeResult = 13.3889; + testEvent.data.location.latitude.should.equal(latitudeResult); + testEvent.data.location.longitude.should.equal(longitudeResult); - delete window.mParticle.config.flags; + clock.restore(); - done(); - }) - }) + done(); + }); + }); }); - it('should log a batch to v3 with no context if no data plan is passed', function(done) { - waitForCondition(hasIdentifyReturned) - .then(() => { + it('should log appName in the payload on v3 endpoint when set on config prior to init', function (done) { + mParticle.config.appName = 'a name'; mParticle.config.flags = { eventBatchingIntervalMillis: 0, }; - mParticle.config.dataPlan = { - planVersion: 10, - }; - mParticle.init(apiKey, mParticle.config); - waitForCondition(() => { - return ( - mParticle.getInstance()._Store.identityCallInFlight === false - ); - }) - .then(() => { - window.mParticle.logEvent('Test Event'); + waitForCondition(hasIdentifyReturned).then(() => { + mParticle.init(apiKey, mParticle.config); + waitForCondition(() => { + return ( + mParticle.getInstance()._Store.identityCallInFlight === + false + ); + }).then(() => { + window.mParticle.logEvent('Test Event'); - const batch = JSON.parse(fetchMock.lastOptions().body); + const batch = JSON.parse(fetchMock.lastOptions().body); - batch.should.not.have.property('context'); + batch.application_info.should.have.property( + 'application_name', + 'a name', + ); - delete window.mParticle.config.flags; + delete window.mParticle.config.flags; - done(); - }) - }) + done(); + }); + }); }); - it('should log an error if a non slug string is passed as the dataplan planId', function(done) { - waitForCondition(hasIdentifyReturned) - .then(() => { - let errorMessage; + it('should log AST first_run as true on new page loads, and false for when a page has previously been loaded', function (done) { + waitForCondition(hasIdentifyReturned).then(() => { + mParticle._resetForTests(MPConfig); + + mParticle.init(apiKey, mParticle.config); + + waitForCondition(() => { + return ( + mParticle.getInstance()._Store.identityCallInFlight === + false + ); + }).then(() => { + const batch = JSON.parse(fetchMock.lastOptions().body); + batch.events[0].data.should.have.property('is_first_run', true); + + waitForCondition(() => { + return ( + mParticle.getInstance()._Store.identityCallInFlight === + false + ); + }).then(() => { + mParticle.init(apiKey, mParticle.config); + const batch2 = JSON.parse(fetchMock.lastOptions().body); + batch2.events[0].data.should.have.property( + 'is_first_run', + false, + ); + + delete window.mParticle.config.flags; + + done(); + }); + }); + }); + }); - mParticle.config.logLevel = 'verbose'; - mParticle.config.logger = { - error: function(msg) { - if (!errorMessage) { - errorMessage = msg; - } - }, - }; - mParticle.config.flags = { - eventBatchingIntervalMillis: 0, - }; - mParticle.config.dataPlan = { - planId: 'not a slug', - planVersion: 10, - }; + it('should log AST with launch_referral with a url', function (done) { + waitForCondition(hasIdentifyReturned).then(() => { + mParticle._resetForTests(MPConfig); + + mParticle.config.flags = { + eventBatchingIntervalMillis: 0, + }; + + mParticle.init(apiKey, mParticle.config); + waitForCondition(() => { + return ( + mParticle.getInstance()._Store.identityCallInFlight === + false + ); + }).then(() => { + const batch = JSON.parse(fetchMock.lastOptions().body); + batch.events[0].data.should.have.property('launch_referral'); + batch.events[0].data.launch_referral.should.startWith( + 'http://localhost', + ); + + delete window.mParticle.config.flags; + + done(); + }); + }); + }); - mParticle.init(apiKey, mParticle.config); - waitForCondition(() => { - return ( - mParticle.getInstance()._Store.identityCallInFlight === false - ); - }) - .then(() => { - window.mParticle.logEvent('Test Event'); - - errorMessage.should.equal( - 'Your data plan id must be a string and match the data plan slug format (i.e. under_case_slug)' - ); - const batch = JSON.parse(fetchMock.lastOptions().body); - batch.should.not.have.property('context'); - delete window.mParticle.config.flags; - - done(); - }) - }) + it('should log appName in the payload on v3 endpoint when set on config prior to init', function (done) { + waitForCondition(hasIdentifyReturned).then(() => { + mParticle.config.flags = { + eventBatchingIntervalMillis: 0, + }; + waitForCondition(() => { + return ( + mParticle.getInstance()._Store.identityCallInFlight === + false + ); + }).then(() => { + mParticle.init(apiKey, mParticle.config); + mParticle.setAppName('another name'); + + window.mParticle.logEvent('Test Event'); + + const batch = JSON.parse(fetchMock.lastOptions().body); + batch.application_info.should.have.property( + 'application_name', + 'another name', + ); + + delete window.mParticle.config.flags; + + done(); + }); + }); }); - it('should log consent properly to v3 endpoint ', function(done) { - waitForCondition(hasIdentifyReturned) - .then(() => { + it('should log a batch to v3 with data planning in the payload', function (done) { + mParticle.config.logLevel = 'verbose'; mParticle.config.flags = { eventBatchingIntervalMillis: 0, }; mParticle.config.dataPlan = { + planId: 'plan_slug', planVersion: 10, }; - mParticle.init(apiKey, mParticle.config); - waitForCondition(() => { - return ( - mParticle.getInstance()._Store.identityCallInFlight === false - ); - }) - .then(() => { - const user = mParticle.Identity.getCurrentUser(); - // Add to your consent state - const consentState = mParticle.Consent.createConsentState(); - - const ccpa = mParticle.Consent.createCCPAConsent( - true, - Date.now(), - 'doc1', - 'location1', - 'hardwareid' - ); - - consentState.setCCPAConsentState(ccpa); - const location_collection_consent = mParticle.Consent.createGDPRConsent( - true, - Date.now(), - 'doc1', - 'location1', - 'hardwareid' - ); - - // Add to your consent state - consentState.addGDPRConsentState( - 'My GDPR Purpose', - location_collection_consent - ); - user.setConsentState(consentState); - - window.mParticle.logEvent('Test Event'); - - const batch = JSON.parse(fetchMock.lastOptions().body); - - batch.should.have.property('consent_state'); - batch.consent_state.should.have.properties(['gdpr', 'ccpa']); - batch.consent_state.gdpr.should.have.property('my gdpr purpose'); - batch.consent_state.gdpr['my gdpr purpose'].should.have.property( - 'consented', - true - ); - batch.consent_state.gdpr['my gdpr purpose'].should.have.property( - 'document', - 'doc1' - ); - batch.consent_state.gdpr['my gdpr purpose'].should.have.property( - 'location', - 'location1' - ); - batch.consent_state.gdpr['my gdpr purpose'].should.have.property( - 'hardware_id', - 'hardwareid' - ); - batch.consent_state.gdpr['my gdpr purpose'].should.have.property( - 'timestamp_unixtime_ms' - ); - - batch.consent_state.ccpa['data_sale_opt_out'].should.have.property( - 'consented', - true - ); - batch.consent_state.ccpa['data_sale_opt_out'].should.have.property( - 'document', - 'doc1' - ); - batch.consent_state.ccpa['data_sale_opt_out'].should.have.property( - 'location', - 'location1' - ); - batch.consent_state.ccpa['data_sale_opt_out'].should.have.property( - 'hardware_id', - 'hardwareid' - ); - batch.consent_state.ccpa['data_sale_opt_out'].should.have.property( - 'timestamp_unixtime_ms' - ); - - delete window.mParticle.config.flags; - - done(); - }) - }) + waitForCondition(hasIdentifyReturned).then(() => { + mParticle.init(apiKey, mParticle.config); + + waitForCondition(() => { + return ( + mParticle.getInstance()._Store.identityCallInFlight === + false + ); + }).then(() => { + window.mParticle.logEvent('Test Event'); + + const batch = JSON.parse(fetchMock.lastOptions().body); + + batch.should.have.property('context'); + batch.context.should.have.property('data_plan'); + batch.context.data_plan.should.have.property( + 'plan_version', + 10, + ); + batch.context.data_plan.should.have.property( + 'plan_id', + 'plan_slug', + ); + + delete window.mParticle.config.flags; + + done(); + }); + }); }); - it('should sanitize transaction attributes in the payload on v3 endpoint', function(done) { - waitForCondition(hasIdentifyReturned) - .then(() => { - mParticle.config.flags = { - eventBatchingIntervalMillis: 0, - }; + it('should log a batch to v3 with no version if no version is passed', function (done) { + waitForCondition(hasIdentifyReturned).then(() => { + mParticle.config.flags = { + eventBatchingIntervalMillis: 0, + }; + mParticle.config.dataPlan = { + planId: 'plan_slug', + }; + + mParticle.init(apiKey, mParticle.config); + waitForCondition(() => { + return ( + mParticle.getInstance()._Store.identityCallInFlight === + false + ); + }).then(() => { + window.mParticle.logEvent('Test Event'); + + const batch = JSON.parse(fetchMock.lastOptions().body); + + batch.should.have.property('context'); + batch.context.should.have.property('data_plan'); + batch.context.data_plan.should.not.have.property( + 'plan_version', + ); + batch.context.data_plan.should.have.property( + 'plan_id', + 'plan_slug', + ); + + delete window.mParticle.config.flags; + + done(); + }); + }); + }); - mParticle.init(apiKey, mParticle.config); - waitForCondition(() => { - return ( - mParticle.getInstance()._Store.identityCallInFlight === false - ); - }) - .then(() => { - const product1 = mParticle.eCommerce.createProduct( - 'iphone', - 'iphoneSKU', - 999, - 1 - ); - const product2 = mParticle.eCommerce.createProduct( - 'galaxy', - 'galaxySKU', - 799, - 1 - ); - - const transactionAttributes = { - Id: 'foo-transaction-id', - Revenue: 'string', - Tax: 'string', - Shipping: 'string', - }; + it('should log a batch to v3 with no context if no data plan is passed', function (done) { + waitForCondition(hasIdentifyReturned).then(() => { + mParticle.config.flags = { + eventBatchingIntervalMillis: 0, + }; + mParticle.config.dataPlan = { + planVersion: 10, + }; - const customAttributes = { sale: true }; - const customFlags = { 'Google.Category': 'travel' }; + mParticle.init(apiKey, mParticle.config); + waitForCondition(() => { + return ( + mParticle.getInstance()._Store.identityCallInFlight === + false + ); + }).then(() => { + window.mParticle.logEvent('Test Event'); - mParticle.eCommerce.logProductAction( - mParticle.ProductActionType.Purchase, - [product1, product2], - customAttributes, - customFlags, - transactionAttributes - ); + const batch = JSON.parse(fetchMock.lastOptions().body); - const batch = JSON.parse(fetchMock.lastOptions().body); + batch.should.not.have.property('context'); - batch.events[0].data.product_action.total_amount.should.equal(0); - batch.events[0].data.product_action.shipping_amount.should.equal(0); - batch.events[0].data.product_action.tax_amount.should.equal(0); + delete window.mParticle.config.flags; - delete window.mParticle.config.flags; + done(); + }); + }); + }); - done(); - }) - }) + it('should log an error if a non slug string is passed as the dataplan planId', function (done) { + waitForCondition(hasIdentifyReturned).then(() => { + let errorMessage; + + mParticle.config.logLevel = 'verbose'; + mParticle.config.logger = { + error: function (msg) { + if (!errorMessage) { + errorMessage = msg; + } + }, + }; + mParticle.config.flags = { + eventBatchingIntervalMillis: 0, + }; + mParticle.config.dataPlan = { + planId: 'not a slug', + planVersion: 10, + }; + + mParticle.init(apiKey, mParticle.config); + waitForCondition(() => { + return ( + mParticle.getInstance()._Store.identityCallInFlight === + false + ); + }).then(() => { + window.mParticle.logEvent('Test Event'); + + errorMessage.should.equal( + 'Your data plan id must be a string and match the data plan slug format (i.e. under_case_slug)', + ); + const batch = JSON.parse(fetchMock.lastOptions().body); + batch.should.not.have.property('context'); + delete window.mParticle.config.flags; + + done(); + }); + }); }); - it('should sanitize product attributes in the payload on v3 endpoint', function(done) { - waitForCondition(hasIdentifyReturned) - .then(() => { - mParticle.config.flags = { - eventBatchingIntervalMillis: 0, - }; + it('should log consent properly to v3 endpoint ', function (done) { + waitForCondition(hasIdentifyReturned).then(() => { + mParticle.config.flags = { + eventBatchingIntervalMillis: 0, + }; + mParticle.config.dataPlan = { + planVersion: 10, + }; + + mParticle.init(apiKey, mParticle.config); + waitForCondition(() => { + return ( + mParticle.getInstance()._Store.identityCallInFlight === + false + ); + }).then(() => { + const user = mParticle.Identity.getCurrentUser(); + // Add to your consent state + const consentState = mParticle.Consent.createConsentState(); + + const ccpa = mParticle.Consent.createCCPAConsent( + true, + Date.now(), + 'doc1', + 'location1', + 'hardwareid', + ); + + consentState.setCCPAConsentState(ccpa); + const location_collection_consent = + mParticle.Consent.createGDPRConsent( + true, + Date.now(), + 'doc1', + 'location1', + 'hardwareid', + ); + + // Add to your consent state + consentState.addGDPRConsentState( + 'My GDPR Purpose', + location_collection_consent, + ); + user.setConsentState(consentState); + + window.mParticle.logEvent('Test Event'); + + const batch = JSON.parse(fetchMock.lastOptions().body); + + batch.should.have.property('consent_state'); + batch.consent_state.should.have.properties(['gdpr', 'ccpa']); + batch.consent_state.gdpr.should.have.property( + 'my gdpr purpose', + ); + batch.consent_state.gdpr[ + 'my gdpr purpose' + ].should.have.property('consented', true); + batch.consent_state.gdpr[ + 'my gdpr purpose' + ].should.have.property('document', 'doc1'); + batch.consent_state.gdpr[ + 'my gdpr purpose' + ].should.have.property('location', 'location1'); + batch.consent_state.gdpr[ + 'my gdpr purpose' + ].should.have.property('hardware_id', 'hardwareid'); + batch.consent_state.gdpr[ + 'my gdpr purpose' + ].should.have.property('timestamp_unixtime_ms'); + + batch.consent_state.ccpa[ + 'data_sale_opt_out' + ].should.have.property('consented', true); + batch.consent_state.ccpa[ + 'data_sale_opt_out' + ].should.have.property('document', 'doc1'); + batch.consent_state.ccpa[ + 'data_sale_opt_out' + ].should.have.property('location', 'location1'); + batch.consent_state.ccpa[ + 'data_sale_opt_out' + ].should.have.property('hardware_id', 'hardwareid'); + batch.consent_state.ccpa[ + 'data_sale_opt_out' + ].should.have.property('timestamp_unixtime_ms'); + + delete window.mParticle.config.flags; + + done(); + }); + }); + }); - mParticle.init(apiKey, mParticle.config); - waitForCondition(() => { - return ( - mParticle.getInstance()._Store.identityCallInFlight === false - ); - }) - .then(() => { - const product1 = mParticle.eCommerce.createProduct( - 'iphone', - 'iphoneSKU', - 'string', - 'string', - 'variant', - 'category', - 'brand', - 'string', - 'coupon' - ); - const product2 = mParticle.eCommerce.createProduct( - 'galaxy', - 'galaxySKU', - 'string', - 'string', - 'variant', - 'category', - 'brand', - 'string', - 'coupon' - ); - - const transactionAttributes = { - Id: 'foo-transaction-id', - Revenue: 'string', - Tax: 'string', - Shipping: 'string', - }; + it('should sanitize transaction attributes in the payload on v3 endpoint', function (done) { + waitForCondition(hasIdentifyReturned).then(() => { + mParticle.config.flags = { + eventBatchingIntervalMillis: 0, + }; + + mParticle.init(apiKey, mParticle.config); + waitForCondition(() => { + return ( + mParticle.getInstance()._Store.identityCallInFlight === + false + ); + }).then(() => { + const product1 = mParticle.eCommerce.createProduct( + 'iphone', + 'iphoneSKU', + 999, + 1, + ); + const product2 = mParticle.eCommerce.createProduct( + 'galaxy', + 'galaxySKU', + 799, + 1, + ); + + const transactionAttributes = { + Id: 'foo-transaction-id', + Revenue: 'string', + Tax: 'string', + Shipping: 'string', + }; + + const customAttributes = { sale: true }; + const customFlags = { 'Google.Category': 'travel' }; + + mParticle.eCommerce.logProductAction( + mParticle.ProductActionType.Purchase, + [product1, product2], + customAttributes, + customFlags, + transactionAttributes, + ); + + const batch = JSON.parse(fetchMock.lastOptions().body); + + batch.events[0].data.product_action.total_amount.should.equal( + 0, + ); + batch.events[0].data.product_action.shipping_amount.should.equal( + 0, + ); + batch.events[0].data.product_action.tax_amount.should.equal(0); + + delete window.mParticle.config.flags; + + done(); + }); + }); + }); - const customAttributes = { sale: true }; - const customFlags = { 'Google.Category': 'travel' }; - mParticle.eCommerce.logProductAction( - mParticle.ProductActionType.Purchase, - [product1, product2], - customAttributes, - customFlags, - transactionAttributes - ); - - const batch = JSON.parse(fetchMock.lastOptions().body); - ( - batch.events[0].data.product_action.products[0].position === null - ).should.equal(true); - batch.events[0].data.product_action.products[0].price.should.equal(0); - batch.events[0].data.product_action.products[0].quantity.should.equal( - 0 - ); - batch.events[0].data.product_action.products[0].total_product_amount.should.equal( - 0 - ); - - ( - batch.events[0].data.product_action.products[1].position === null - ).should.equal(true); - batch.events[0].data.product_action.products[1].price.should.equal(0); - batch.events[0].data.product_action.products[1].quantity.should.equal( - 0 - ); - batch.events[0].data.product_action.products[1].total_product_amount.should.equal( - 0 - ); - - delete window.mParticle.config.flags; - - done(); - }) - }) + it('should sanitize product attributes in the payload on v3 endpoint', function (done) { + waitForCondition(hasIdentifyReturned).then(() => { + mParticle.config.flags = { + eventBatchingIntervalMillis: 0, + }; + + mParticle.init(apiKey, mParticle.config); + waitForCondition(() => { + return ( + mParticle.getInstance()._Store.identityCallInFlight === + false + ); + }).then(() => { + const product1 = mParticle.eCommerce.createProduct( + 'iphone', + 'iphoneSKU', + 'string', + 'string', + 'variant', + 'category', + 'brand', + 'string', + 'coupon', + ); + const product2 = mParticle.eCommerce.createProduct( + 'galaxy', + 'galaxySKU', + 'string', + 'string', + 'variant', + 'category', + 'brand', + 'string', + 'coupon', + ); + + const transactionAttributes = { + Id: 'foo-transaction-id', + Revenue: 'string', + Tax: 'string', + Shipping: 'string', + }; + + const customAttributes = { sale: true }; + const customFlags = { 'Google.Category': 'travel' }; + mParticle.eCommerce.logProductAction( + mParticle.ProductActionType.Purchase, + [product1, product2], + customAttributes, + customFlags, + transactionAttributes, + ); + + const batch = JSON.parse(fetchMock.lastOptions().body); + ( + batch.events[0].data.product_action.products[0].position === + null + ).should.equal(true); + batch.events[0].data.product_action.products[0].price.should.equal( + 0, + ); + batch.events[0].data.product_action.products[0].quantity.should.equal( + 0, + ); + batch.events[0].data.product_action.products[0].total_product_amount.should.equal( + 0, + ); + + ( + batch.events[0].data.product_action.products[1].position === + null + ).should.equal(true); + batch.events[0].data.product_action.products[1].price.should.equal( + 0, + ); + batch.events[0].data.product_action.products[1].quantity.should.equal( + 0, + ); + batch.events[0].data.product_action.products[1].total_product_amount.should.equal( + 0, + ); + + delete window.mParticle.config.flags; + + done(); + }); + }); }); -}); \ No newline at end of file +}); diff --git a/test/src/tests-feature-flags.ts b/test/src/tests-feature-flags.ts index bbabc86ea..59e63e860 100644 --- a/test/src/tests-feature-flags.ts +++ b/test/src/tests-feature-flags.ts @@ -2,10 +2,7 @@ import Constants from '../../src/constants'; import sinon from 'sinon'; import { expect } from 'chai'; import fetchMock from 'fetch-mock/esm/client'; -import { urls, apiKey, - testMPID, - MPConfig, -} from './config/constants'; +import { urls, apiKey, testMPID, MPConfig } from './config/constants'; import Utils from './config/utils'; import { IMParticleInstanceManager } from '../../src/sdkRuntimeModels'; @@ -21,13 +18,14 @@ const hasIdentifyReturned = () => { return window.mParticle.Identity.getCurrentUser()?.getMPID() === testMPID; }; -describe('feature-flags', function() { - describe('user audiences', function() { - beforeEach(function() { +describe('feature-flags', function () { + describe('user audiences', function () { + beforeEach(function () { fetchMock.post(urls.events, 200); fetchMockSuccess(urls.identify, { - mpid: testMPID, is_logged_in: false + mpid: testMPID, + is_logged_in: false, }); window.mParticle.init(apiKey, window.mParticle.config); @@ -38,28 +36,30 @@ describe('feature-flags', function() { fetchMock.restore(); }); - it('should not be able to access user audience API if feature flag is false', function() { + it('should not be able to access user audience API if feature flag is false', function () { window.mParticle.config.flags = { - audienceAPI: 'False' + audienceAPI: 'False', }; window.mParticle._resetForTests(MPConfig); - // initialize mParticle with feature flag + // initialize mParticle with feature flag window.mParticle.init(apiKey, window.mParticle.config); - waitForCondition(hasIdentifyReturned) - .then(() => { - const bond = sinon.spy(window.mParticle.getInstance().Logger, 'error'); - window.mParticle.Identity.getCurrentUser().getUserAudiences(); - - bond.called.should.eql(true); - bond.getCalls()[0].args[0].should.eql( - Constants.Messages.ErrorMessages.AudienceAPINotEnabled - ); - }) + waitForCondition(hasIdentifyReturned).then(() => { + const bond = sinon.spy( + window.mParticle.getInstance().Logger, + 'error', + ); + window.mParticle.Identity.getCurrentUser().getUserAudiences(); + + bond.called.should.eql(true); + bond.getCalls()[0].args[0].should.eql( + Constants.Messages.ErrorMessages.AudienceAPINotEnabled, + ); + }); }); - it('should be able to call user audience API if feature flag is false', function() { + it('should be able to call user audience API if feature flag is false', function () { const userAudienceUrl = `https://${Constants.DefaultBaseUrls.userAudienceUrl}${apiKey}/audience`; const audienceMembershipServerResponse = { ct: 1710441407915, @@ -72,31 +72,35 @@ describe('feature-flags', function() { { audience_id: 5432, }, - ] + ], }; fetchMock.get(`${userAudienceUrl}?mpid=${testMPID}`, { status: 200, - body: JSON.stringify(audienceMembershipServerResponse) + body: JSON.stringify(audienceMembershipServerResponse), }); - + window.mParticle._resetForTests(MPConfig); window.mParticle.config.flags = { - audienceAPI: 'True' + audienceAPI: 'True', }; - // initialize mParticle with feature flag + // initialize mParticle with feature flag window.mParticle.init(apiKey, window.mParticle.config); - waitForCondition(hasIdentifyReturned) - .then(() => { - const bond = sinon.spy(window.mParticle.getInstance().Logger, 'error'); - - window.mParticle.Identity.getCurrentUser().getUserAudiences((result) => { - console.log(result); + waitForCondition(hasIdentifyReturned).then(() => { + const bond = sinon.spy( + window.mParticle.getInstance().Logger, + 'error', + ); + + window.mParticle.Identity.getCurrentUser().getUserAudiences( + (result) => { + console.log(result); + }, + ); + bond.called.should.eql(false); }); - bond.called.should.eql(false); - }) }); }); @@ -105,7 +109,8 @@ describe('feature-flags', function() { fetchMock.post(urls.events, 200); fetchMockSuccess(urls.identify, { - mpid: testMPID, is_logged_in: false + mpid: testMPID, + is_logged_in: false, }); window.document.cookie = '_cookie1=1234'; @@ -124,49 +129,75 @@ describe('feature-flags', function() { it('should capture click ids when feature flag is true', async () => { window.mParticle.config.flags = { - captureIntegrationSpecificIds: 'True' + captureIntegrationSpecificIds: 'True', }; window.mParticle._resetForTests(MPConfig); - sinon.stub(window.mParticle.getInstance()._IntegrationCapture, 'getQueryParams').returns({ - fbclid: '1234', - }); - - const captureSpy = sinon.spy(window.mParticle.getInstance()._IntegrationCapture, 'capture'); - const clickIdSpy = sinon.spy(window.mParticle.getInstance()._IntegrationCapture, 'getClickIdsAsCustomFlags'); + sinon + .stub( + window.mParticle.getInstance()._IntegrationCapture, + 'getQueryParams', + ) + .returns({ + fbclid: '1234', + }); + + const captureSpy = sinon.spy( + window.mParticle.getInstance()._IntegrationCapture, + 'capture', + ); + const clickIdSpy = sinon.spy( + window.mParticle.getInstance()._IntegrationCapture, + 'getClickIdsAsCustomFlags', + ); - // initialize mParticle with feature flag + // initialize mParticle with feature flag window.mParticle.init(apiKey, window.mParticle.config); - await waitForCondition(hasIdentifyReturned) + await waitForCondition(hasIdentifyReturned); - const initialTimestamp = window.mParticle.getInstance()._IntegrationCapture.initialTimestamp; + const initialTimestamp = + window.mParticle.getInstance()._IntegrationCapture + .initialTimestamp; expect(initialTimestamp).to.be.a('number'); - expect(window.mParticle.getInstance()._IntegrationCapture.clickIds).to.deep.equal({ + expect( + window.mParticle.getInstance()._IntegrationCapture.clickIds, + ).to.deep.equal({ fbclid: `fb.1.${initialTimestamp}.1234`, - '_fbp': '54321', + _fbp: '54321', }); expect(captureSpy.called, 'capture()').to.equal(true); - expect(clickIdSpy.called, 'getClickIdsAsCustomFlags').to.equal(true); + expect(clickIdSpy.called, 'getClickIdsAsCustomFlags').to.equal( + true, + ); }); it('should NOT capture click ids when feature flag is false', async () => { window.mParticle.config.flags = { - captureIntegrationSpecificIds: 'False' + captureIntegrationSpecificIds: 'False', }; window.mParticle._resetForTests(MPConfig); - const captureSpy = sinon.spy(window.mParticle.getInstance()._IntegrationCapture, 'capture'); - const clickIdSpy = sinon.spy(window.mParticle.getInstance()._IntegrationCapture, 'getClickIdsAsCustomFlags'); + const captureSpy = sinon.spy( + window.mParticle.getInstance()._IntegrationCapture, + 'capture', + ); + const clickIdSpy = sinon.spy( + window.mParticle.getInstance()._IntegrationCapture, + 'getClickIdsAsCustomFlags', + ); - // initialize mParticle with feature flag + // initialize mParticle with feature flag window.mParticle.init(apiKey, window.mParticle.config); - await waitForCondition(hasIdentifyReturned) + await waitForCondition(hasIdentifyReturned); - expect(window.mParticle.getInstance()._IntegrationCapture.clickIds).not.be.ok; + expect(window.mParticle.getInstance()._IntegrationCapture.clickIds) + .not.be.ok; expect(captureSpy.called, 'capture()').to.equal(false); - expect(clickIdSpy.called, 'getClickIdsAsCustomFlags').to.equal(false); + expect(clickIdSpy.called, 'getClickIdsAsCustomFlags').to.equal( + false, + ); }); }); -}); \ No newline at end of file +}); diff --git a/test/src/tests-forwarders.ts b/test/src/tests-forwarders.ts index 11156d7cf..116170b29 100644 --- a/test/src/tests-forwarders.ts +++ b/test/src/tests-forwarders.ts @@ -10,14 +10,20 @@ import { MessageType, } from './config/constants'; import { expect } from 'chai'; -import { IMParticleInstanceManager, SDKEvent, SDKInitConfig } from '../../src/sdkRuntimeModels'; -import { IMParticleUser, UserAttributes } from '../../src/identity-user-interfaces'; +import { + IMParticleInstanceManager, + SDKEvent, + SDKInitConfig, +} from '../../src/sdkRuntimeModels'; +import { + IMParticleUser, + UserAttributes, +} from '../../src/identity-user-interfaces'; import { IdentityType } from '../../src/types'; import { IntegrationAttribute } from '../../src/store'; import { IConsentRules } from '../../src/consent'; import { UserIdentities } from '@mparticle/web-sdk'; - const { findEventFromRequest, waitForCondition, @@ -56,7 +62,7 @@ interface IMockForwarderInstance { // https://go.mparticle.com/work/SQDSDKS-4475 export interface IMockForwarder { - instance: IMockForwarderInstance + instance: IMockForwarderInstance; register: (config?: SDKInitConfig) => void; } @@ -65,10 +71,10 @@ interface UserIdentitiesFilter { Type: typeof IdentityType; } -interface MockMParticleForForwarders extends IMParticleInstanceManager{ - userIdentitiesFilterOnInitTest: UserIdentitiesFilter[] +interface MockMParticleForForwarders extends IMParticleInstanceManager { + userIdentitiesFilterOnInitTest: UserIdentitiesFilter[]; userAttributesFilterOnInitTest: UserAttributes; -}; +} declare global { interface Window { @@ -85,8 +91,8 @@ const mParticle = window.mParticle as unknown as MockMParticleForForwarders; let mockServer; -describe('forwarders', function() { - beforeEach(function() { +describe('forwarders', function () { + beforeEach(function () { mParticle._resetForTests(MPConfig); delete mParticle._instances['default_instance']; fetchMock.post(urls.events, 200); @@ -98,53 +104,51 @@ describe('forwarders', function() { }); fetchMockSuccess(urls.login, { - mpid: testMPID, is_logged_in: false + mpid: testMPID, + is_logged_in: false, }); fetchMockSuccess(urls.logout, { - mpid: testMPID, is_logged_in: true - }) + mpid: testMPID, + is_logged_in: true, + }); fetchMockSuccess(urls.modify, { change_results: [ - { - identity_type: 'email', - modified_mpid: testMPID, - }, - ], - }) + { + identity_type: 'email', + modified_mpid: testMPID, + }, + ], + }); - fetchMockSuccess(urls.forwarding, { mpid: testMPID, is_logged_in: false }) + fetchMockSuccess(urls.forwarding, { + mpid: testMPID, + is_logged_in: false, + }); // https://go.mparticle.com/work/SQDSDKS-6850 - mockServer.respondWith(urls.forwarding, [ - 202, - {}, - JSON.stringify({}), - ]); + mockServer.respondWith(urls.forwarding, [202, {}, JSON.stringify({})]); }); - afterEach(function() { + afterEach(function () { fetchMock.restore(); delete window.MockForwarder1; }); - it('should add forwarders via dynamic script loading via the addForwarder method', function(done) { + it('should add forwarders via dynamic script loading via the addForwarder method', function (done) { mParticle._resetForTests(MPConfig); const mockForwarder = new MockForwarder(); mParticle.addForwarder(mockForwarder); window.mParticle.config.kitConfigs.push( - forwarderDefaultConfiguration('MockForwarder') + forwarderDefaultConfiguration('MockForwarder'), ); mParticle.init(apiKey, window.mParticle.config); - mParticle - .getInstance() - ._getActiveForwarders() - .length.should.equal(1); + mParticle.getInstance()._getActiveForwarders().length.should.equal(1); done(); }); @@ -159,25 +163,28 @@ describe('forwarders', function() { const mockForwarder = new MockForwarder(); mockForwarder.register(window.mParticle.config); window.mParticle.config.kitConfigs.push( - forwarderDefaultConfiguration('MockForwarder') + forwarderDefaultConfiguration('MockForwarder'), ); mParticle.init(apiKey, window.mParticle.config); - await waitForCondition(() => window.mParticle.getInstance()?._Store?.identityCallInFlight === false); - + await waitForCondition( + () => + window.mParticle.getInstance()?._Store?.identityCallInFlight === + false, + ); window.MockForwarder1.instance.should.have.property( 'setUserIdentityCalled', - true + true, ); window.MockForwarder1.instance.userIdentities.should.have.property( '4', - 'google123' + 'google123', ); }); - it('should permit forwarder if no consent configured.', function(done) { + it('should permit forwarder if no consent configured.', function (done) { mParticle.config.isDevelopmentMode = false; const mockForwarder = new MockForwarder(); mockForwarder.register(window.mParticle.config); @@ -191,13 +198,13 @@ describe('forwarders', function() { .getInstance() ._Consent.isEnabledForUserConsent( window.MockForwarder1.instance.filteringConsentRuleValues, - null + null, ); expect(enabled).to.be.ok; done(); }); - it('should not permit forwarder if consent configured but there is no user.', function(done) { + it('should not permit forwarder if consent configured but there is no user.', function (done) { const enableForwarder = true; const consented = false; mParticle._resetForTests(MPConfig); @@ -221,25 +228,25 @@ describe('forwarders', function() { .getInstance() ._Consent.isEnabledForUserConsent( window.MockForwarder1.instance.filteringConsentRuleValues, - null + null, ); expect(enabled).to.not.be.ok; done(); }); - const MockUser = function() { + const MockUser = function () { let consentState = null; return { - setConsentState: function(state) { + setConsentState: function (state) { consentState = state; }, - getConsentState: function() { + getConsentState: function () { return consentState; }, } as IMParticleUser; }; - it("should disable forwarder if 'Do Not Forward' when 'Consent Rejected' is selected and user consent has been rejected", function(done) { + it("should disable forwarder if 'Do Not Forward' when 'Consent Rejected' is selected and user consent has been rejected", function (done) { const enableForwarder = false; // 'Do Not Forward' chosen in UI, 'includeOnMatch' in config const consented = false; const userConsent = false; @@ -255,7 +262,7 @@ describe('forwarders', function() { values: [ { consentPurpose: mParticle.generateHash( - '1' + 'foo purpose 1' + '1' + 'foo purpose 1', ), hasConsented: consented, }, @@ -270,7 +277,7 @@ describe('forwarders', function() { .Consent.createConsentState() .addGDPRConsentState( 'foo purpose 1', - mParticle.getInstance().Consent.createGDPRConsent(userConsent) + mParticle.getInstance().Consent.createGDPRConsent(userConsent), ); const user = MockUser(); @@ -279,14 +286,14 @@ describe('forwarders', function() { .getInstance() ._Consent.isEnabledForUserConsent( window.MockForwarder1.instance.filteringConsentRuleValues, - user + user, ); expect(enabled).to.not.be.ok; done(); }); - it("should disable forwarder if 'Do Not Forward' when 'Consent Accepted' is selected and consent has been accepted", function(done) { + it("should disable forwarder if 'Do Not Forward' when 'Consent Accepted' is selected and consent has been accepted", function (done) { const enableForwarder = false; // 'Do Not Forward' chosen in UI, 'includeOnMatch' in config const consented = true; const userConsent = true; @@ -301,7 +308,7 @@ describe('forwarders', function() { values: [ { consentPurpose: mParticle.generateHash( - '1' + 'foo purpose 1' + '1' + 'foo purpose 1', ), hasConsented: consented, }, @@ -316,7 +323,7 @@ describe('forwarders', function() { .Consent.createConsentState() .addGDPRConsentState( 'foo purpose 1', - mParticle.getInstance().Consent.createGDPRConsent(userConsent) + mParticle.getInstance().Consent.createGDPRConsent(userConsent), ); const user = MockUser(); user.setConsentState(consentState); @@ -324,14 +331,14 @@ describe('forwarders', function() { .getInstance() ._Consent.isEnabledForUserConsent( window.MockForwarder1.instance.filteringConsentRuleValues, - user + user, ); expect(enabled).to.not.be.ok; done(); }); - it("should enable forwarder if 'Only Forward' when 'Consent Rejected' is selected and consent has been rejected", function(done) { + it("should enable forwarder if 'Only Forward' when 'Consent Rejected' is selected and consent has been rejected", function (done) { const enableForwarder = true; // 'Only Forward' chosen in UI, 'includeOnMatch' in config const consented = false; const userConsent = false; @@ -345,7 +352,7 @@ describe('forwarders', function() { values: [ { consentPurpose: mParticle.generateHash( - '1' + 'foo purpose 1' + '1' + 'foo purpose 1', ), hasConsented: consented, }, @@ -360,7 +367,7 @@ describe('forwarders', function() { .Consent.createConsentState() .addGDPRConsentState( 'foo purpose 1', - mParticle.getInstance().Consent.createGDPRConsent(userConsent) + mParticle.getInstance().Consent.createGDPRConsent(userConsent), ); const user = MockUser(); user.setConsentState(consentState); @@ -368,14 +375,14 @@ describe('forwarders', function() { .getInstance() ._Consent.isEnabledForUserConsent( window.MockForwarder1.instance.filteringConsentRuleValues, - user + user, ); expect(enabled).to.be.ok; done(); }); - it("should enable forwarder if 'Only Forward' when 'Consent Accepted' is selected and consent has been accepted", function(done) { + it("should enable forwarder if 'Only Forward' when 'Consent Accepted' is selected and consent has been accepted", function (done) { const enableForwarder = true; // 'Only Forward' chosen in UI, 'includeOnMatch' in config const consented = true; const userConsent = true; @@ -390,7 +397,7 @@ describe('forwarders', function() { values: [ { consentPurpose: mParticle.generateHash( - '1' + 'foo purpose 1' + '1' + 'foo purpose 1', ), hasConsented: consented, }, @@ -405,7 +412,7 @@ describe('forwarders', function() { .Consent.createConsentState() .addGDPRConsentState( 'foo purpose 1', - mParticle.getInstance().Consent.createGDPRConsent(userConsent) + mParticle.getInstance().Consent.createGDPRConsent(userConsent), ); const user = MockUser(); user.setConsentState(consentState); @@ -413,14 +420,14 @@ describe('forwarders', function() { .getInstance() ._Consent.isEnabledForUserConsent( window.MockForwarder1.instance.filteringConsentRuleValues, - user + user, ); expect(enabled).to.be.ok; done(); }); - it("should disable forwarder if 'Only Forward' when 'Consent Accepted' is selected and consent has been rejected", function(done) { + it("should disable forwarder if 'Only Forward' when 'Consent Accepted' is selected and consent has been rejected", function (done) { const enableForwarder = true; // 'Only Forward' chosen in UI, 'includeOnMatch' in config const consented = true; const userConsent = false; @@ -435,7 +442,7 @@ describe('forwarders', function() { values: [ { consentPurpose: mParticle.generateHash( - '1' + 'foo purpose 1' + '1' + 'foo purpose 1', ), hasConsented: consented, }, @@ -450,7 +457,7 @@ describe('forwarders', function() { .Consent.createConsentState() .addGDPRConsentState( 'foo purpose 1', - mParticle.getInstance().Consent.createGDPRConsent(userConsent) + mParticle.getInstance().Consent.createGDPRConsent(userConsent), ); const user = MockUser(); user.setConsentState(consentState); @@ -458,14 +465,14 @@ describe('forwarders', function() { .getInstance() ._Consent.isEnabledForUserConsent( window.MockForwarder1.instance.filteringConsentRuleValues, - user + user, ); expect(enabled).to.not.be.ok; done(); }); - it("should enable forwarder if 'Do Not Forward' when 'Consent Rejected' is selected and consent has been accepted", function(done) { + it("should enable forwarder if 'Do Not Forward' when 'Consent Rejected' is selected and consent has been accepted", function (done) { const enableForwarder = false; // 'Do Not Forward' chosen in UI, 'includeOnMatch' in config const consented = false; const userConsent = true; @@ -480,7 +487,7 @@ describe('forwarders', function() { values: [ { consentPurpose: mParticle.generateHash( - '1' + 'foo purpose 1' + '1' + 'foo purpose 1', ), hasConsented: consented, }, @@ -495,7 +502,7 @@ describe('forwarders', function() { .Consent.createConsentState() .addGDPRConsentState( 'foo purpose 1', - mParticle.getInstance().Consent.createGDPRConsent(userConsent) + mParticle.getInstance().Consent.createGDPRConsent(userConsent), ); const user = MockUser(); user.setConsentState(consentState); @@ -503,14 +510,14 @@ describe('forwarders', function() { .getInstance() ._Consent.isEnabledForUserConsent( window.MockForwarder1.instance.filteringConsentRuleValues, - user + user, ); expect(enabled).to.be.ok; done(); }); - it("should enable forwarder if 'Do Not Forward' when 'Consent Accepted' is selected and consent has been rejected", function(done) { + it("should enable forwarder if 'Do Not Forward' when 'Consent Accepted' is selected and consent has been rejected", function (done) { const enableForwarder = false; // 'Do Not Forward' chosen in UI, 'includeOnMatch' in config const consented = true; const userConsent = false; @@ -525,7 +532,7 @@ describe('forwarders', function() { values: [ { consentPurpose: mParticle.generateHash( - '1' + 'foo purpose 1' + '1' + 'foo purpose 1', ), hasConsented: consented, }, @@ -540,7 +547,7 @@ describe('forwarders', function() { .Consent.createConsentState() .addGDPRConsentState( 'foo purpose 1', - mParticle.getInstance().Consent.createGDPRConsent(userConsent) + mParticle.getInstance().Consent.createGDPRConsent(userConsent), ); const user = MockUser(); user.setConsentState(consentState); @@ -548,14 +555,14 @@ describe('forwarders', function() { .getInstance() ._Consent.isEnabledForUserConsent( window.MockForwarder1.instance.filteringConsentRuleValues, - user + user, ); expect(enabled).to.be.ok; done(); }); - it("should enable forwarder if 'Do Not Forward' when 'Consent Rejected' is selected and consent has been accepted", function(done) { + it("should enable forwarder if 'Do Not Forward' when 'Consent Rejected' is selected and consent has been accepted", function (done) { const enableForwarder = false; // 'Do Not Forward' chosen in UI, 'includeOnMatch' in config const consented = false; const userConsent = true; @@ -570,7 +577,7 @@ describe('forwarders', function() { values: [ { consentPurpose: mParticle.generateHash( - '1' + 'foo purpose 1' + '1' + 'foo purpose 1', ), hasConsented: consented, }, @@ -585,7 +592,7 @@ describe('forwarders', function() { .Consent.createConsentState() .addGDPRConsentState( 'foo purpose 1', - mParticle.getInstance().Consent.createGDPRConsent(userConsent) + mParticle.getInstance().Consent.createGDPRConsent(userConsent), ); const user = MockUser(); user.setConsentState(consentState); @@ -593,14 +600,14 @@ describe('forwarders', function() { .getInstance() ._Consent.isEnabledForUserConsent( window.MockForwarder1.instance.filteringConsentRuleValues, - user + user, ); expect(enabled).to.be.ok; done(); }); - it("should disable forwarder if 'Do Not Forward' when CCPA is 'Not Present' is selected and user CCPA is not present", function(done) { + it("should disable forwarder if 'Do Not Forward' when CCPA is 'Not Present' is selected and user CCPA is not present", function (done) { const enableForwarder = false; // 'Do Not Forward' chosen in UI, 'includeOnMatch' in config const consentPresent = false; const userConsentPresent = false; @@ -616,7 +623,7 @@ describe('forwarders', function() { values: [ { consentPurpose: mParticle.generateHash( - '2' + 'data_sale_opt_out' + '2' + 'data_sale_opt_out', ), hasConsented: consentPresent, }, @@ -632,7 +639,7 @@ describe('forwarders', function() { .setCCPAConsentState( mParticle .getInstance() - .Consent.createCCPAConsent(userConsentPresent) + .Consent.createCCPAConsent(userConsentPresent), ); const user = MockUser(); user.setConsentState(consentState); @@ -641,14 +648,14 @@ describe('forwarders', function() { .getInstance() ._Consent.isEnabledForUserConsent( window.MockForwarder1.instance.filteringConsentRuleValues, - user + user, ); expect(enabled).to.not.be.ok; done(); }); - it("should disable forwarder if 'Do Not Forward' when CCPA is 'Present' is selected and user CCPA is present", function(done) { + it("should disable forwarder if 'Do Not Forward' when CCPA is 'Present' is selected and user CCPA is present", function (done) { const enableForwarder = false; // 'Do Not Forward' chosen in UI, 'includeOnMatch' in config const consentPresent = true; const userConsentPresent = true; @@ -664,7 +671,7 @@ describe('forwarders', function() { values: [ { consentPurpose: mParticle.generateHash( - '2' + 'data_sale_opt_out' + '2' + 'data_sale_opt_out', ), hasConsented: consentPresent, }, @@ -680,7 +687,7 @@ describe('forwarders', function() { .setCCPAConsentState( mParticle .getInstance() - .Consent.createCCPAConsent(userConsentPresent) + .Consent.createCCPAConsent(userConsentPresent), ); const user = MockUser(); user.setConsentState(consentState); @@ -689,14 +696,14 @@ describe('forwarders', function() { .getInstance() ._Consent.isEnabledForUserConsent( window.MockForwarder1.instance.filteringConsentRuleValues, - user + user, ); expect(enabled).to.not.be.ok; done(); }); - it("should enable forwarder if 'Only Forward' when CCPA is 'Not Present' is selected and user CCPA is not present", function(done) { + it("should enable forwarder if 'Only Forward' when CCPA is 'Not Present' is selected and user CCPA is not present", function (done) { const enableForwarder = true; // 'Only Forward' chosen in UI, 'includeOnMatch' in config const consentPresent = false; const userConsentPresent = false; @@ -712,7 +719,7 @@ describe('forwarders', function() { values: [ { consentPurpose: mParticle.generateHash( - '2' + 'data_sale_opt_out' + '2' + 'data_sale_opt_out', ), hasConsented: consentPresent, }, @@ -728,7 +735,7 @@ describe('forwarders', function() { .setCCPAConsentState( mParticle .getInstance() - .Consent.createCCPAConsent(userConsentPresent) + .Consent.createCCPAConsent(userConsentPresent), ); const user = MockUser(); user.setConsentState(consentState); @@ -737,7 +744,7 @@ describe('forwarders', function() { .getInstance() ._Consent.isEnabledForUserConsent( window.MockForwarder1.instance.filteringConsentRuleValues, - user + user, ); expect(enabled).to.be.ok; @@ -745,7 +752,7 @@ describe('forwarders', function() { done(); }); - it("should enable forwarder if 'Only Forward' when CCPA data sale opt out is present is selected and user CCPA is present.", function(done) { + it("should enable forwarder if 'Only Forward' when CCPA data sale opt out is present is selected and user CCPA is present.", function (done) { const enableForwarder = true; // 'Only Forward' chosen in UI, 'includeOnMatch' in config const consentPresent = true; const userConsentPresent = true; @@ -761,7 +768,7 @@ describe('forwarders', function() { values: [ { consentPurpose: mParticle.generateHash( - '2' + 'data_sale_opt_out' + '2' + 'data_sale_opt_out', ), hasConsented: consentPresent, }, @@ -777,7 +784,7 @@ describe('forwarders', function() { .setCCPAConsentState( mParticle .getInstance() - .Consent.createCCPAConsent(userConsentPresent) + .Consent.createCCPAConsent(userConsentPresent), ); const user = MockUser(); user.setConsentState(consentState); @@ -786,14 +793,14 @@ describe('forwarders', function() { .getInstance() ._Consent.isEnabledForUserConsent( window.MockForwarder1.instance.filteringConsentRuleValues, - user + user, ); expect(enabled).to.be.ok; done(); }); - it("should disable forwarder if 'Only Forward' when CCPA is 'Present' is selected and user CCPA is not present", function(done) { + it("should disable forwarder if 'Only Forward' when CCPA is 'Present' is selected and user CCPA is not present", function (done) { const enableForwarder = true; // 'Only Forward' chosen in UI, 'includeOnMatch' in config const consentPresent = true; const userConsentPresent = false; @@ -809,7 +816,7 @@ describe('forwarders', function() { values: [ { consentPurpose: mParticle.generateHash( - '2' + 'data_sale_opt_out' + '2' + 'data_sale_opt_out', ), hasConsented: consentPresent, }, @@ -825,7 +832,7 @@ describe('forwarders', function() { .setCCPAConsentState( mParticle .getInstance() - .Consent.createCCPAConsent(userConsentPresent) + .Consent.createCCPAConsent(userConsentPresent), ); const user = MockUser(); user.setConsentState(consentState); @@ -834,14 +841,14 @@ describe('forwarders', function() { .getInstance() ._Consent.isEnabledForUserConsent( window.MockForwarder1.instance.filteringConsentRuleValues, - user + user, ); expect(enabled).to.not.be.ok; done(); }); - it("should enable forwarder if 'Do Not Forward' when CCPA is 'Not Present' is selected and user CCPA is present", function(done) { + it("should enable forwarder if 'Do Not Forward' when CCPA is 'Not Present' is selected and user CCPA is present", function (done) { const enableForwarder = false; // 'Do Not Forward' chosen in UI, 'includeOnMatch' in config const consentPresent = false; const userConsentPresent = true; @@ -857,7 +864,7 @@ describe('forwarders', function() { values: [ { consentPurpose: mParticle.generateHash( - '2' + 'data_sale_opt_out' + '2' + 'data_sale_opt_out', ), hasConsented: consentPresent, }, @@ -873,7 +880,7 @@ describe('forwarders', function() { .setCCPAConsentState( mParticle .getInstance() - .Consent.createCCPAConsent(userConsentPresent) + .Consent.createCCPAConsent(userConsentPresent), ); const user = MockUser(); user.setConsentState(consentState); @@ -882,14 +889,14 @@ describe('forwarders', function() { .getInstance() ._Consent.isEnabledForUserConsent( window.MockForwarder1.instance.filteringConsentRuleValues, - user + user, ); expect(enabled).to.be.ok; done(); }); - it("should enable forwarder if 'Do Not Forward' when CCPA is 'Present' is selected and user CCPA is not present", function(done) { + it("should enable forwarder if 'Do Not Forward' when CCPA is 'Present' is selected and user CCPA is not present", function (done) { const enableForwarder = false; // 'Do Not Forward' chosen in UI, 'includeOnMatch' in config const consentPresent = true; const userConsentPresent = false; @@ -905,7 +912,7 @@ describe('forwarders', function() { values: [ { consentPurpose: mParticle.generateHash( - '2' + 'data_sale_opt_out' + '2' + 'data_sale_opt_out', ), hasConsented: consentPresent, }, @@ -921,7 +928,7 @@ describe('forwarders', function() { .setCCPAConsentState( mParticle .getInstance() - .Consent.createCCPAConsent(userConsentPresent) + .Consent.createCCPAConsent(userConsentPresent), ); const user = MockUser(); user.setConsentState(consentState); @@ -930,14 +937,14 @@ describe('forwarders', function() { .getInstance() ._Consent.isEnabledForUserConsent( window.MockForwarder1.instance.filteringConsentRuleValues, - user + user, ); expect(enabled).to.be.ok; done(); }); - it("does not initialize a forwarder when forwarder's isDebug != mParticle.isDevelopmentMode", function(done) { + it("does not initialize a forwarder when forwarder's isDebug != mParticle.isDevelopmentMode", function (done) { mParticle._resetForTests(MPConfig); mParticle.config.isDevelopmentMode = false; const mockForwarder = new MockForwarder(); @@ -951,15 +958,12 @@ describe('forwarders', function() { mParticle.init(apiKey, window.mParticle.config); expect(window.MockForwarder1).not.be.ok; - mParticle - .getInstance() - ._getActiveForwarders() - .length.should.equal(0); + mParticle.getInstance()._getActiveForwarders().length.should.equal(0); done(); }); - it('initializes a forwarder with isDebug = false && mParticle.config.isDevelopmentMode = false', function(done) { + it('initializes a forwarder with isDebug = false && mParticle.config.isDevelopmentMode = false', function (done) { mParticle._resetForTests(MPConfig); mParticle.config.isDevelopmentMode = false; const mockForwarder = new MockForwarder(); @@ -970,18 +974,15 @@ describe('forwarders', function() { mParticle.init(apiKey, window.mParticle.config); window.MockForwarder1.instance.should.have.property('initCalled', true); - mParticle - .getInstance() - ._getActiveForwarders() - .length.should.equal(1); - expect( - mParticle.getInstance()._Store.configuredForwarders.length + mParticle.getInstance()._getActiveForwarders().length.should.equal(1); + expect( + mParticle.getInstance()._Store.configuredForwarders.length, ).equal(1); done(); }); - it('initializes a forwarder with isDebug = true && mParticle.config.isDevelopmentMode = true', function(done) { + it('initializes a forwarder with isDebug = true && mParticle.config.isDevelopmentMode = true', function (done) { mParticle._resetForTests(MPConfig); mParticle.config.isDevelopmentMode = true; const mockForwarder = new MockForwarder(); @@ -993,14 +994,14 @@ describe('forwarders', function() { mParticle.init(apiKey, window.mParticle.config); window.MockForwarder1.instance.should.have.property('initCalled', true); - expect( - mParticle.getInstance()._Store.configuredForwarders.length + expect( + mParticle.getInstance()._Store.configuredForwarders.length, ).equal(1); done(); }); - it('initializes forwarders when isDebug = mParticle.config.isDevelopmentMode', function(done) { + it('initializes forwarders when isDebug = mParticle.config.isDevelopmentMode', function (done) { mParticle._resetForTests(MPConfig); mParticle.config.isDevelopmentMode = false; const mockForwarder = new MockForwarder(); @@ -1015,12 +1016,9 @@ describe('forwarders', function() { window.mParticle.config.kitConfigs.push(config2); mParticle.init(apiKey, window.mParticle.config); - mParticle - .getInstance() - ._getActiveForwarders() - .length.should.equal(1); - expect( - mParticle.getInstance()._Store.configuredForwarders.length + mParticle.getInstance()._getActiveForwarders().length.should.equal(1); + expect( + mParticle.getInstance()._Store.configuredForwarders.length, ).equal(1); done(); @@ -1042,7 +1040,7 @@ describe('forwarders', function() { mParticle.logEvent('send this event to forwarder'); window.MockForwarder1.instance.should.have.property( 'processCalled', - true + true, ); }); @@ -1063,16 +1061,14 @@ describe('forwarders', function() { window.MockForwarder1.instance.should.have.property( 'processCalled', - true + true, ); - fetchMock.lastCall().includes( - '/v1/JS/test_key/Forwarding' - ); + fetchMock.lastCall().includes('/v1/JS/test_key/Forwarding'); }); // https://go.mparticle.com/work/SQDSDKS-6850 - it.skip('sends forwarding stats to v2 endpoint when featureFlag setting of batching is true', function(done) { + it.skip('sends forwarding stats to v2 endpoint when featureFlag setting of batching is true', function (done) { mParticle._resetForTests(MPConfig); const mockForwarder = new MockForwarder(); mockForwarder.register(window.mParticle.config); @@ -1087,55 +1083,54 @@ describe('forwarders', function() { window.mParticle.config.flags = { reportBatching: true, }; - + const clock = sinon.useFakeTimers(); mParticle.init(apiKey, window.mParticle.config); - waitForCondition(hasIdentifyReturned) - .then(() => { - fetchMock.resetHistory(); - mockServer.requests = []; + waitForCondition(hasIdentifyReturned).then(() => { + fetchMock.resetHistory(); + mockServer.requests = []; - mParticle.logEvent( - 'send this event to forwarder', - mParticle.EventType.Navigation, - { 'my-key': 'my-value' } - ); + mParticle.logEvent( + 'send this event to forwarder', + mParticle.EventType.Navigation, + { 'my-key': 'my-value' }, + ); - clock.tick(10000); + clock.tick(10000); - const event = getForwarderEvent( - fetchMock.calls(), - 'send this event to forwarder', - true - ); - expect(event).should.be.ok; - - mockServer.requests[mockServer.requests.length - 1].url.includes( - '/v2/JS/test_key/Forwarding' - ); - event.should.have.property('mid', 1); - event.should.have.property('esid', 1234567890); - event.should.have.property('n', 'send this event to forwarder'); - event.should.have.property('attrs'); - event.should.have.property('dp'); - event.dp.should.have.property('PlanVersion', 10); - event.dp.should.have.property('PlanId', 'plan_slug'); - event.should.have.property('dp'); - event.should.have.property('sdk', mParticle.getVersion()); - event.should.have.property('dt', MessageType.PageEvent); - event.should.have.property('et', mParticle.EventType.Navigation); - event.should.have.property( - 'dbg', - mParticle.getInstance()._Store.SDKConfig.isDevelopmentMode - ); - event.should.have.property('ct'); - event.should.have.property('eec', 0); + const event = getForwarderEvent( + fetchMock.calls(), + 'send this event to forwarder', + true, + ); + expect(event).should.be.ok; - done(); - }); + mockServer.requests[mockServer.requests.length - 1].url.includes( + '/v2/JS/test_key/Forwarding', + ); + event.should.have.property('mid', 1); + event.should.have.property('esid', 1234567890); + event.should.have.property('n', 'send this event to forwarder'); + event.should.have.property('attrs'); + event.should.have.property('dp'); + event.dp.should.have.property('PlanVersion', 10); + event.dp.should.have.property('PlanId', 'plan_slug'); + event.should.have.property('dp'); + event.should.have.property('sdk', mParticle.getVersion()); + event.should.have.property('dt', MessageType.PageEvent); + event.should.have.property('et', mParticle.EventType.Navigation); + event.should.have.property( + 'dbg', + mParticle.getInstance()._Store.SDKConfig.isDevelopmentMode, + ); + event.should.have.property('ct'); + event.should.have.property('eec', 0); + + done(); + }); }); - it('should not send forwarding stats to invisible forwarders', function(done) { + it('should not send forwarding stats to invisible forwarders', function (done) { mParticle._resetForTests(MPConfig); const mockForwarder = new MockForwarder(); mockForwarder.register(window.mParticle.config); @@ -1148,13 +1143,13 @@ describe('forwarders', function() { mParticle.logEvent( 'send this event to forwarder', mParticle.EventType.Navigation, - { 'my-key': 'my-value' } + { 'my-key': 'my-value' }, ); const event = findEventFromRequest( fetchMock.calls(), 'send this event to forwarder', - true + true, ); expect(event).should.not.have.property('n'); @@ -1176,11 +1171,11 @@ describe('forwarders', function() { window.MockForwarder1.instance.should.have.property( 'setOptOutCalled', - true + true, ); }); - it('should invoke forwarder setuserattribute', function(done) { + it('should invoke forwarder setuserattribute', function (done) { mParticle._resetForTests(MPConfig); const mockForwarder = new MockForwarder(); @@ -1189,16 +1184,18 @@ describe('forwarders', function() { window.mParticle.config.kitConfigs.push(config1); mParticle.init(apiKey, window.mParticle.config); - waitForCondition(hasIdentifyReturned) - .then(() => { - mParticle.Identity.getCurrentUser().setUserAttribute('gender', 'male'); + waitForCondition(hasIdentifyReturned).then(() => { + mParticle.Identity.getCurrentUser().setUserAttribute( + 'gender', + 'male', + ); - window.MockForwarder1.instance.should.have.property( - 'setUserAttributeCalled', - true - ); + window.MockForwarder1.instance.should.have.property( + 'setUserAttributeCalled', + true, + ); - done(); + done(); }); }); @@ -1218,7 +1215,7 @@ describe('forwarders', function() { window.MockForwarder1.instance.should.have.property( 'setUserAttributeCalled', - true + true, ); }); @@ -1237,7 +1234,7 @@ describe('forwarders', function() { window.MockForwarder1.instance.should.have.property( 'removeUserAttributeCalled', - true + true, ); }); @@ -1282,20 +1279,28 @@ describe('forwarders', function() { customerid: '123', }, }); - await waitForCondition(() => window.mParticle.getInstance()?._Store?.identityCallInFlight === false); + await waitForCondition( + () => + window.mParticle.getInstance()?._Store?.identityCallInFlight === + false, + ); mParticle.init(apiKey, window.mParticle.config); - await waitForCondition(() => window.mParticle.getInstance()?._Store?.identityCallInFlight === false); + await waitForCondition( + () => + window.mParticle.getInstance()?._Store?.identityCallInFlight === + false, + ); mParticle.userIdentitiesFilterOnInitTest.length.should.equal(2); mParticle.userIdentitiesFilterOnInitTest[0].Type.should.equal(1); mParticle.userIdentitiesFilterOnInitTest[0].Identity.should.equal( - '123' + '123', ); mParticle.userIdentitiesFilterOnInitTest[1].Type.should.equal(7); mParticle.userIdentitiesFilterOnInitTest[1].Identity.should.equal( - 'test@gmail.com' + 'test@gmail.com', ); expect(mParticle.userIdentitiesFilterOnInitTest[2]).to.be.undefined; }); @@ -1310,7 +1315,11 @@ describe('forwarders', function() { window.mParticle.config.kitConfigs.push(config1); mParticle.init(apiKey, window.mParticle.config); - await waitForCondition(() => window.mParticle.getInstance()?._Store?.identityCallInFlight === false); + await waitForCondition( + () => + window.mParticle.getInstance()?._Store?.identityCallInFlight === + false, + ); mParticle.Identity.modify({ userIdentities: { @@ -1320,14 +1329,18 @@ describe('forwarders', function() { }, }); - await waitForCondition(() => window.mParticle.getInstance()?._Store?.identityCallInFlight === false); + await waitForCondition( + () => + window.mParticle.getInstance()?._Store?.identityCallInFlight === + false, + ); mParticle.logEvent('test event'); const event = window.MockForwarder1.instance.receivedEvent; Object.keys(event.UserIdentities).length.should.equal(2); let googleUserIdentityExits = false; - event.UserIdentities.forEach(function(identity) { + event.UserIdentities.forEach(function (identity) { if (identity.Type === mParticle.IdentityType.Google) { googleUserIdentityExits = true; } @@ -1335,7 +1348,7 @@ describe('forwarders', function() { expect(googleUserIdentityExits).to.be.false; expect(event.UserIdentities[0].Type).to.equal( - mParticle.IdentityType.CustomerId + mParticle.IdentityType.CustomerId, ); }); @@ -1351,25 +1364,33 @@ describe('forwarders', function() { ]; window.mParticle.config.kitConfigs.push(config1); mParticle.init(apiKey, window.mParticle.config); - await waitForCondition(() => window.mParticle.getInstance()?._Store?.identityCallInFlight === false); + await waitForCondition( + () => + window.mParticle.getInstance()?._Store?.identityCallInFlight === + false, + ); mParticle.Identity.getCurrentUser().setUserAttribute('gender', 'male'); mParticle.userAttributesFilterOnInitTest.should.not.have.property( - 'gender' + 'gender', ); mParticle.init(apiKey, window.mParticle.config); - await waitForCondition(() => window.mParticle.getInstance()?._Store?.identityCallInFlight === false); + await waitForCondition( + () => + window.mParticle.getInstance()?._Store?.identityCallInFlight === + false, + ); mParticle.Identity.getCurrentUser().setUserAttribute('age', 32); mParticle.Identity.getCurrentUser().setUserAttribute('weight', 150); window.MockForwarder1.instance.userAttributes.should.have.property( 'weight', - 150 + 150, ); window.MockForwarder1.instance.userAttributes.should.not.have.property( - 'age' + 'age', ); }); @@ -1388,18 +1409,26 @@ describe('forwarders', function() { window.mParticle.config.kitConfigs.push(config1); mParticle.init(apiKey, window.mParticle.config); - await waitForCondition(() => window.mParticle.getInstance()?._Store?.identityCallInFlight === false); + await waitForCondition( + () => + window.mParticle.getInstance()?._Store?.identityCallInFlight === + false, + ); // force filtered UA in mock forwarder (due to filtering affecting setUserAttribute) and test init window.MockForwarder1.instance.userAttributes['weight'] = 150; mParticle.Identity.getCurrentUser().removeUserAttribute('weight'); window.MockForwarder1.instance.removeUserAttributeCalled.should.equal( - false + false, ); mParticle.userAttributesFilterOnInitTest.should.have.property('weight'); mParticle.init(apiKey, window.mParticle.config); - await waitForCondition(() => window.mParticle.getInstance()?._Store?.identityCallInFlight === false); + await waitForCondition( + () => + window.mParticle.getInstance()?._Store?.identityCallInFlight === + false, + ); const dummyUserAttributes = { gender: 'male', @@ -1407,7 +1436,7 @@ describe('forwarders', function() { }; // force filtered UA in mock forwarder (due to filtering affecting setUserAttribute) and non filtered UA - for (let key of Object.keys(dummyUserAttributes)) { + for (const key of Object.keys(dummyUserAttributes)) { window.MockForwarder1.instance.userAttributes[key] = dummyUserAttributes[key]; } @@ -1415,20 +1444,20 @@ describe('forwarders', function() { // "age" is filtered and should not call removeUserAttribute on forwarder mParticle.Identity.getCurrentUser().removeUserAttribute('age'); window.MockForwarder1.instance.removeUserAttributeCalled.should.equal( - false + false, ); window.MockForwarder1.instance.userAttributes.should.have.property( 'age', - 20 + 20, ); // "gender" is not filtered and should call removeUserAttribute on forwarder mParticle.Identity.getCurrentUser().removeUserAttribute('gender'); window.MockForwarder1.instance.removeUserAttributeCalled.should.equal( - true + true, ); window.MockForwarder1.instance.userAttributes.should.not.have.property( - 'gender' + 'gender', ); }); @@ -1441,13 +1470,17 @@ describe('forwarders', function() { const config1 = forwarderDefaultConfiguration('MockForwarder', 1); config1.eventNameFilters = [ mParticle.generateHash( - mParticle.EventType.Navigation + 'test event' + mParticle.EventType.Navigation + 'test event', ), ]; window.mParticle.config.kitConfigs.push(config1); mParticle.init(apiKey, window.mParticle.config); - await waitForCondition(() => window.mParticle.getInstance()?._Store?.identityCallInFlight === false); + await waitForCondition( + () => + window.mParticle.getInstance()?._Store?.identityCallInFlight === + false, + ); mParticle.startNewSession(); window.MockForwarder1.instance.receivedEvent = null; @@ -1491,7 +1524,9 @@ describe('forwarders', function() { const config1 = forwarderDefaultConfiguration('MockForwarder', 1); config1.attributeFilters = [ mParticle.generateHash( - mParticle.EventType.Navigation + 'test event' + 'test attribute' + mParticle.EventType.Navigation + + 'test event' + + 'test attribute', ), ]; window.mParticle.config.kitConfigs.push(config1); @@ -1499,7 +1534,8 @@ describe('forwarders', function() { mParticle.init(apiKey, window.mParticle.config); await waitForCondition(() => { return ( - window.mParticle.getInstance()?._Store?.identityCallInFlight === false + window.mParticle.getInstance()?._Store?.identityCallInFlight === + false ); }); @@ -1523,20 +1559,26 @@ describe('forwarders', function() { const config1 = forwarderDefaultConfiguration('MockForwarder', 1); config1.attributeFilters = [ mParticle.generateHash( - mParticle.EventType.Navigation + 'test event' + 'test attribute' + mParticle.EventType.Navigation + + 'test event' + + 'test attribute', ), ]; config1.screenAttributeFilters = [ mParticle.generateHash( mParticle.EventType.Unknown + 'ScreenA' + - 'filteredScreenAttribute' + 'filteredScreenAttribute', ), ]; window.mParticle.config.kitConfigs.push(config1); mParticle.init(apiKey, window.mParticle.config); - await waitForCondition(() => window.mParticle.getInstance()?._Store?.identityCallInFlight === false); + await waitForCondition( + () => + window.mParticle.getInstance()?._Store?.identityCallInFlight === + false, + ); mParticle.logPageView('ScreenA', { filteredScreenAttribute: 'this will be filtered', @@ -1546,11 +1588,11 @@ describe('forwarders', function() { const event = window.MockForwarder1.instance.receivedEvent; event.EventAttributes.should.not.have.property( - 'filteredScreenAttribute' + 'filteredScreenAttribute', ); event.EventAttributes.should.have.property( 'unfilteredScreenAttribute', - 'this will not be filtered' + 'this will not be filtered', ); }); @@ -1562,19 +1604,27 @@ describe('forwarders', function() { window.mParticle.config.kitConfigs.push(config1); mParticle.init(apiKey, window.mParticle.config); - await waitForCondition(() => window.mParticle.getInstance()?._Store?.identityCallInFlight === false); + await waitForCondition( + () => + window.mParticle.getInstance()?._Store?.identityCallInFlight === + false, + ); mParticle.Identity.logout(); - await waitForCondition(() => window.mParticle.getInstance()?._Store?.identityCallInFlight === false); + await waitForCondition( + () => + window.mParticle.getInstance()?._Store?.identityCallInFlight === + false, + ); window.MockForwarder1.instance.should.have.property( 'logOutCalled', - true + true, ); window.MockForwarder1.instance.should.have.property( 'onLogoutCompleteCalled', - true + true, ); }); @@ -1587,15 +1637,19 @@ describe('forwarders', function() { window.mParticle.config.kitConfigs.push(config1); mParticle.init(apiKey, window.mParticle.config); - await waitForCondition(() => window.mParticle.getInstance()?._Store?.identityCallInFlight === false); + await waitForCondition( + () => + window.mParticle.getInstance()?._Store?.identityCallInFlight === + false, + ); window.MockForwarder1.instance.should.have.property( 'appName', - 'Unit Tests' + 'Unit Tests', ); }); - it('should pass in app version to forwarder on initialize', function(done) { + it('should pass in app version to forwarder on initialize', function (done) { const mockForwarder = new MockForwarder(); mockForwarder.register(window.mParticle.config); const config1 = forwarderDefaultConfiguration('MockForwarder', 1); @@ -1606,13 +1660,13 @@ describe('forwarders', function() { window.MockForwarder1.instance.should.have.property( 'appVersion', - '3.0' + '3.0', ); done(); }); - it('should pass in user identities to forwarder on initialize', function(done) { + it('should pass in user identities to forwarder on initialize', function (done) { setLocalStorage(); const mockForwarder = new MockForwarder(); @@ -1623,13 +1677,13 @@ describe('forwarders', function() { mParticle.init(apiKey, window.mParticle.config); Object.keys( - window.MockForwarder1.instance.userIdentities + window.MockForwarder1.instance.userIdentities, ).length.should.equal(1); done(); }); - it('should pass in user attributes to forwarder on initialize', function(done) { + it('should pass in user attributes to forwarder on initialize', function (done) { setLocalStorage(); const mockForwarder = new MockForwarder(); @@ -1641,7 +1695,7 @@ describe('forwarders', function() { window.MockForwarder1.instance.should.have.property('userAttributes'); window.MockForwarder1.instance.userAttributes.should.have.property( 'color', - 'blue' + 'blue', ); done(); @@ -1660,7 +1714,8 @@ describe('forwarders', function() { mParticle.init(apiKey, window.mParticle.config); await waitForCondition(() => { return ( - window.mParticle.getInstance()?._Store?.identityCallInFlight === false + window.mParticle.getInstance()?._Store?.identityCallInFlight === + false ); }); @@ -1674,17 +1729,18 @@ describe('forwarders', function() { await waitForCondition(() => { return ( - window.mParticle.getInstance()?._Store?.identityCallInFlight === false + window.mParticle.getInstance()?._Store?.identityCallInFlight === + false ); }); expect(window.MockForwarder1.instance.onIdentifyCompleteCalled).to.eq( - true + true, ); expect(window.MockForwarder1.instance.onIdentifyCompleteUser).to.be.ok; expect( window.MockForwarder1.instance - .onIdentifyCompleteFilteredUserIdentities + .onIdentifyCompleteFilteredUserIdentities, ).to.deep.equal({ userIdentities: { // Filtered Identity should no longer have `google` as an identity @@ -1706,7 +1762,11 @@ describe('forwarders', function() { window.mParticle.config.kitConfigs.push(config1); mParticle.init(apiKey, window.mParticle.config); - await waitForCondition(() => window.mParticle.getInstance()?._Store?.identityCallInFlight === false); + await waitForCondition( + () => + window.mParticle.getInstance()?._Store?.identityCallInFlight === + false, + ); mParticle.Identity.login({ userIdentities: { @@ -1716,14 +1776,19 @@ describe('forwarders', function() { }, }); - await waitForCondition(() => window.mParticle.getInstance()?._Store?.identityCallInFlight === false); + await waitForCondition( + () => + window.mParticle.getInstance()?._Store?.identityCallInFlight === + false, + ); expect(window.MockForwarder1.instance.onLoginCompleteCalled).to.eq( - true + true, ); expect(window.MockForwarder1.instance.onLoginCompleteUser).to.be.ok; expect( - window.MockForwarder1.instance.onLoginCompleteFilteredUserIdentities + window.MockForwarder1.instance + .onLoginCompleteFilteredUserIdentities, ).to.deep.equal({ userIdentities: { // Filtered Identity should no longer have `google` as an identity @@ -1745,7 +1810,11 @@ describe('forwarders', function() { window.mParticle.config.kitConfigs.push(config1); mParticle.init(apiKey, window.mParticle.config); - await waitForCondition(() => window.mParticle.getInstance()?._Store?.identityCallInFlight === false); + await waitForCondition( + () => + window.mParticle.getInstance()?._Store?.identityCallInFlight === + false, + ); mParticle.Identity.logout({ userIdentities: { @@ -1755,15 +1824,19 @@ describe('forwarders', function() { }, }); - await waitForCondition(() => window.mParticle.getInstance()?._Store?.identityCallInFlight === false); + await waitForCondition( + () => + window.mParticle.getInstance()?._Store?.identityCallInFlight === + false, + ); expect(window.MockForwarder1.instance.onLogoutCompleteCalled).to.eq( - true + true, ); expect(window.MockForwarder1.instance.onLogoutCompleteUser).to.be.ok; expect( window.MockForwarder1.instance - .onLogoutCompleteFilteredUserIdentities + .onLogoutCompleteFilteredUserIdentities, ).to.deep.equal({ userIdentities: { // Filtered Identity should no longer have `google` as an identity @@ -1785,7 +1858,11 @@ describe('forwarders', function() { window.mParticle.config.kitConfigs.push(config1); mParticle.init(apiKey, window.mParticle.config); - await waitForCondition(() => window.mParticle.getInstance()?._Store?.identityCallInFlight === false); + await waitForCondition( + () => + window.mParticle.getInstance()?._Store?.identityCallInFlight === + false, + ); mParticle.Identity.modify({ userIdentities: { @@ -1795,15 +1872,19 @@ describe('forwarders', function() { }, }); - await waitForCondition(() => window.mParticle.getInstance()?._Store?.identityCallInFlight === false); + await waitForCondition( + () => + window.mParticle.getInstance()?._Store?.identityCallInFlight === + false, + ); expect(window.MockForwarder1.instance.onModifyCompleteCalled).to.eq( - true + true, ); expect(window.MockForwarder1.instance.onModifyCompleteUser).to.be.ok; expect( window.MockForwarder1.instance - .onModifyCompleteFilteredUserIdentities + .onModifyCompleteFilteredUserIdentities, ).to.deep.equal({ userIdentities: { // Filtered Identity should no longer have `google` as an identity @@ -1829,21 +1910,25 @@ describe('forwarders', function() { window.mParticle.config.kitConfigs.push(config1); mParticle.init(apiKey, window.mParticle.config); - await waitForCondition(() => window.mParticle.getInstance()?._Store?.identityCallInFlight === false); + await waitForCondition( + () => + window.mParticle.getInstance()?._Store?.identityCallInFlight === + false, + ); mParticle.logEvent( 'send this event to forwarder', mParticle.EventType.Navigation, { ForwardingRule: 'Forward', - } + }, ); const event = window.MockForwarder1.instance.receivedEvent; event.should.not.have.property( 'EventName', - 'send this event to forwarder' + 'send this event to forwarder', ); }); @@ -1863,7 +1948,11 @@ describe('forwarders', function() { window.mParticle.config.kitConfigs.push(config1); mParticle.init(apiKey, window.mParticle.config); - await waitForCondition(() => window.mParticle.getInstance()?._Store?.identityCallInFlight === false); + await waitForCondition( + () => + window.mParticle.getInstance()?._Store?.identityCallInFlight === + false, + ); mParticle.logEvent( 'send this event to forwarder', @@ -1871,7 +1960,7 @@ describe('forwarders', function() { { Foo: 'Bar', ForwardingRule: 'Forward', - } + }, ); const event = window.MockForwarder1.instance.receivedEvent; @@ -1895,21 +1984,25 @@ describe('forwarders', function() { window.mParticle.config.kitConfigs.push(config1); mParticle.init(apiKey, window.mParticle.config); - await waitForCondition(() => window.mParticle.getInstance()?._Store?.identityCallInFlight === false); + await waitForCondition( + () => + window.mParticle.getInstance()?._Store?.identityCallInFlight === + false, + ); mParticle.logEvent( 'send this event to forwarder', mParticle.EventType.Navigation, { Forwarding: 'Non-Matching', - } + }, ); const event = window.MockForwarder1.instance.receivedEvent; event.should.not.have.property( 'EventName', - 'send this event to forwarder' + 'send this event to forwarder', ); }); @@ -1939,13 +2032,12 @@ describe('forwarders', function() { mParticle.EventType.Navigation, { ForwardingRule: 'Forward', - } + }, ); const event = window.MockForwarder1.instance.receivedEvent; expect(event).to.not.be.ok; - }); it('should forward event if event attribute forwarding rule is set and includeOnMatch is false but attributes do not match', async () => { @@ -1975,7 +2067,7 @@ describe('forwarders', function() { mParticle.EventType.Navigation, { Test: 'does not match', - } + }, ); const event = window.MockForwarder1.instance.receivedEvent; @@ -1998,7 +2090,11 @@ describe('forwarders', function() { window.mParticle.config.kitConfigs.push(config1); mParticle.init(apiKey, window.mParticle.config); - await waitForCondition(() => window.mParticle.getInstance()?._Store?.identityCallInFlight === false); + await waitForCondition( + () => + window.mParticle.getInstance()?._Store?.identityCallInFlight === + false, + ); mParticle.Identity.getCurrentUser().setUserAttribute('Gender', 'Male'); @@ -2025,7 +2121,11 @@ describe('forwarders', function() { window.mParticle.config.kitConfigs.push(config1); mParticle.init(apiKey, window.mParticle.config); - await waitForCondition(() => window.mParticle.getInstance()?._Store?.identityCallInFlight === false); + await waitForCondition( + () => + window.mParticle.getInstance()?._Store?.identityCallInFlight === + false, + ); mParticle.Identity.getCurrentUser().setUserAttribute('Gender', 'Male'); //reset received event, which will have the initial session start event on it @@ -2039,7 +2139,11 @@ describe('forwarders', function() { it('should permit forwarder if no user attribute value filters configured', async () => { mParticle.init(apiKey, window.mParticle.config); - await waitForCondition(() => window.mParticle.getInstance()?._Store?.identityCallInFlight === false); + await waitForCondition( + () => + window.mParticle.getInstance()?._Store?.identityCallInFlight === + false, + ); let enabled = mParticle .getInstance() @@ -2066,12 +2170,16 @@ describe('forwarders', function() { window.mParticle.config.kitConfigs.push(config1); mParticle.init(apiKey, window.mParticle.config); - await waitForCondition(() => window.mParticle.getInstance()?._Store?.identityCallInFlight === false); + await waitForCondition( + () => + window.mParticle.getInstance()?._Store?.identityCallInFlight === + false, + ); mParticle.logEvent('test event'); const event = window.MockForwarder1.instance.receivedEvent; window.MockForwarder1.instance.receivedEvent.EventName.should.equal( - 'test event' + 'test event', ); expect(event).to.be.ok; }); @@ -2090,7 +2198,11 @@ describe('forwarders', function() { window.mParticle.config.kitConfigs.push(config1); mParticle.init(apiKey, window.mParticle.config); - await waitForCondition(() => window.mParticle.getInstance()?._Store?.identityCallInFlight === false); + await waitForCondition( + () => + window.mParticle.getInstance()?._Store?.identityCallInFlight === + false, + ); mParticle.logEvent('test event'); @@ -2113,11 +2225,15 @@ describe('forwarders', function() { window.mParticle.config.kitConfigs.push(config1); mParticle.init(apiKey, window.mParticle.config); - await waitForCondition(() => window.mParticle.getInstance()?._Store?.identityCallInFlight === false); + await waitForCondition( + () => + window.mParticle.getInstance()?._Store?.identityCallInFlight === + false, + ); mParticle.Identity.getCurrentUser().setUserAttribute( 'gender', - 'female' + 'female', ); mParticle.logEvent('test event'); @@ -2141,11 +2257,15 @@ describe('forwarders', function() { window.mParticle.config.kitConfigs.push(config1); mParticle.init(apiKey, window.mParticle.config); - await waitForCondition(() => window.mParticle.getInstance()?._Store?.identityCallInFlight === false); + await waitForCondition( + () => + window.mParticle.getInstance()?._Store?.identityCallInFlight === + false, + ); mParticle.Identity.getCurrentUser().setUserAttribute( 'gender', - 'female' + 'female', ); mParticle.logEvent('test event'); @@ -2167,7 +2287,11 @@ describe('forwarders', function() { window.mParticle.config.kitConfigs.push(config1); mParticle.init(apiKey, window.mParticle.config); - await waitForCondition(() => window.mParticle.getInstance()?._Store?.identityCallInFlight === false); + await waitForCondition( + () => + window.mParticle.getInstance()?._Store?.identityCallInFlight === + false, + ); mParticle.Identity.getCurrentUser().setUserAttribute('Gender', 'Male'); @@ -2183,7 +2307,7 @@ describe('forwarders', function() { mParticle.Identity.getCurrentUser().setUserAttribute( 'Gender', - 'famale' + 'famale', ); activeForwarders = mParticle.getInstance()._getActiveForwarders(); @@ -2208,7 +2332,11 @@ describe('forwarders', function() { window.mParticle.config.kitConfigs.push(config1); mParticle.init(apiKey, window.mParticle.config); - await waitForCondition(() => window.mParticle.getInstance()?._Store?.identityCallInFlight === false); + await waitForCondition( + () => + window.mParticle.getInstance()?._Store?.identityCallInFlight === + false, + ); mParticle.Identity.getCurrentUser().setUserAttribute('Gender', 'Male'); mParticle.logEvent('test event'); @@ -2216,11 +2344,11 @@ describe('forwarders', function() { expect(event).to.be.ok; window.MockForwarder1.instance.receivedEvent.EventName.should.equal( - 'test event' + 'test event', ); }); - it('should call forwarder onUserIdentified method when identity is returned', async function() { + it('should call forwarder onUserIdentified method when identity is returned', async function () { mParticle._resetForTests(MPConfig); const mockForwarder = new MockForwarder(); @@ -2230,11 +2358,15 @@ describe('forwarders', function() { window.mParticle.config.kitConfigs.push(config1); mParticle.init(apiKey, window.mParticle.config); - await waitForCondition(() => window.mParticle.getInstance()?._Store?.identityCallInFlight === false); + await waitForCondition( + () => + window.mParticle.getInstance()?._Store?.identityCallInFlight === + false, + ); window.MockForwarder1.instance.should.have.property( 'onUserIdentifiedCalled', - true + true, ); }); @@ -2260,7 +2392,7 @@ describe('forwarders', function() { 'iphone', 'sku', 123, - 1 + 1, ); mParticle.eCommerce.Cart.add(product, true); @@ -2272,10 +2404,7 @@ describe('forwarders', function() { result = getForwarderEvent(fetchMock.calls(), 'not in forwarder'); expect(result).to.be.ok; - result = getForwarderEvent( - fetchMock.calls(), - 'eCommerce - AddToCart' - ); + result = getForwarderEvent(fetchMock.calls(), 'eCommerce - AddToCart'); expect(result).to.be.ok; clock.restore(); @@ -2304,14 +2433,16 @@ describe('forwarders', function() { }); mParticle.init(apiKey, window.mParticle.config); - await waitForCondition(() => window.mParticle.getInstance()?._Store?.identityCallInFlight === false); + await waitForCondition( + () => + window.mParticle.getInstance()?._Store?.identityCallInFlight === + false, + ); const activeForwarders = mParticle.getInstance()._getActiveForwarders(); activeForwarders.length.should.equal(1); - mParticle.Identity.getCurrentUser() - .isLoggedIn() - .should.equal(false); + mParticle.Identity.getCurrentUser().isLoggedIn().should.equal(false); }); it('should only initialize forwarders with excludeUnknownUser = false for non-logged-in users', async () => { @@ -2335,17 +2466,19 @@ describe('forwarders', function() { }); mParticle.init(apiKey, window.mParticle.config); - await waitForCondition(() => window.mParticle.getInstance()?._Store?.identityCallInFlight === false); + await waitForCondition( + () => + window.mParticle.getInstance()?._Store?.identityCallInFlight === + false, + ); const activeForwarders = mParticle.getInstance()._getActiveForwarders(); activeForwarders.length.should.equal(1); - mParticle.Identity.getCurrentUser() - .isLoggedIn() - .should.equal(false); + mParticle.Identity.getCurrentUser().isLoggedIn().should.equal(false); }); - it('should initialize all forwarders when a user is logged in and the page reloads', async() => { + it('should initialize all forwarders when a user is logged in and the page reloads', async () => { const mockForwarder = new MockForwarder(); const mockForwarder2 = new MockForwarder('MockForwarder2', 2); @@ -2362,11 +2495,13 @@ describe('forwarders', function() { window.mParticle.config.kitConfigs.push(config2); mParticle.init(apiKey, window.mParticle.config); - await waitForCondition(() => window.mParticle.getInstance()?._Store?.identityCallInFlight === false); + await waitForCondition( + () => + window.mParticle.getInstance()?._Store?.identityCallInFlight === + false, + ); - mParticle.Identity.getCurrentUser() - .isLoggedIn() - .should.equal(false); + mParticle.Identity.getCurrentUser().isLoggedIn().should.equal(false); const user = { userIdentities: { customerid: 'customerid3', @@ -2380,19 +2515,23 @@ describe('forwarders', function() { }); mParticle.Identity.login(user); - await waitForCondition(() => window.mParticle.getInstance()?._Store?.identityCallInFlight === false); + await waitForCondition( + () => + window.mParticle.getInstance()?._Store?.identityCallInFlight === + false, + ); - expect(mParticle.Identity.getCurrentUser() - .isLoggedIn()) - .to.equal(true); + expect(mParticle.Identity.getCurrentUser().isLoggedIn()).to.equal(true); const activeForwarders = mParticle.getInstance()._getActiveForwarders(); expect(activeForwarders.length).to.equal(2); mParticle.init(apiKey, window.mParticle.config); - await waitForCondition(() => window.mParticle.getInstance()?._Store?.identityCallInFlight === false); - mParticle.Identity.getCurrentUser() - .isLoggedIn() - .should.equal(true); + await waitForCondition( + () => + window.mParticle.getInstance()?._Store?.identityCallInFlight === + false, + ); + mParticle.Identity.getCurrentUser().isLoggedIn().should.equal(true); const activeForwarders2 = mParticle .getInstance() ._getActiveForwarders(); @@ -2406,62 +2545,77 @@ describe('forwarders', function() { }); mParticle.init(apiKey, window.mParticle.config); - await waitForCondition(() => window.mParticle.getInstance()?._Store?.identityCallInFlight === false); + await waitForCondition( + () => + window.mParticle.getInstance()?._Store?.identityCallInFlight === + false, + ); const ls = mParticle.getInstance()._Persistence.getLocalStorage(); ls.l.should.equal(true); - + mParticle.init(apiKey, window.mParticle.config); - await waitForCondition(() => window.mParticle.getInstance()?._Store?.identityCallInFlight === false); + await waitForCondition( + () => + window.mParticle.getInstance()?._Store?.identityCallInFlight === + false, + ); const ls2 = mParticle.getInstance()._Persistence.getLocalStorage(); ls2.hasOwnProperty('l').should.equal(true); - + fetchMockSuccess(urls.logout, { - mpid: 'MPID1', is_logged_in: false + mpid: 'MPID1', + is_logged_in: false, }); - + mParticle.Identity.logout(); - await waitForCondition(() => window.mParticle.getInstance()?._Store?.identityCallInFlight === false); + await waitForCondition( + () => + window.mParticle.getInstance()?._Store?.identityCallInFlight === + false, + ); const ls3 = mParticle.getInstance()._Persistence.getLocalStorage(); ls3.l.should.equal(false); mParticle.init(apiKey, window.mParticle.config); - await waitForCondition(() => window.mParticle.getInstance()?._Store?.identityCallInFlight === false); + await waitForCondition( + () => + window.mParticle.getInstance()?._Store?.identityCallInFlight === + false, + ); const ls4 = mParticle.getInstance()._Persistence.getLocalStorage(); ls4.l.should.equal(false); }); it('should not set integration attributes on forwarders when a non-object attr is passed', () => { - const invalidIntegrationAttribute = '123' as unknown as IntegrationAttribute; - mParticle.init(apiKey, window.mParticle.config) + const invalidIntegrationAttribute = + '123' as unknown as IntegrationAttribute; + mParticle.init(apiKey, window.mParticle.config); mParticle.setIntegrationAttribute(128, invalidIntegrationAttribute); - const adobeIntegrationAttributes = mParticle.getIntegrationAttributes( - 128 - ); + const adobeIntegrationAttributes = + mParticle.getIntegrationAttributes(128); expect(adobeIntegrationAttributes).to.eqls({}); }); it('should set integration attributes on forwarders', async () => { - mParticle.init(apiKey, window.mParticle.config) + mParticle.init(apiKey, window.mParticle.config); await waitForCondition(hasIdentityCallInflightReturned); mParticle.setIntegrationAttribute(128, { MCID: 'abcdefg' }); - const adobeIntegrationAttributes = mParticle.getIntegrationAttributes( - 128 - ); + const adobeIntegrationAttributes = + mParticle.getIntegrationAttributes(128); adobeIntegrationAttributes.MCID.should.equal('abcdefg'); }); it('should clear integration attributes when an empty object or a null is passed', async () => { - mParticle.init(apiKey, window.mParticle.config) + mParticle.init(apiKey, window.mParticle.config); await waitForCondition(hasIdentityCallInflightReturned); mParticle.setIntegrationAttribute(128, { MCID: 'abcdefg' }); - let adobeIntegrationAttributes = mParticle.getIntegrationAttributes( - 128 - ); + let adobeIntegrationAttributes = + mParticle.getIntegrationAttributes(128); Object.keys(adobeIntegrationAttributes).length.should.equal(1); mParticle.setIntegrationAttribute(128, {}); @@ -2478,7 +2632,7 @@ describe('forwarders', function() { }); it('should sanitize any non-strings from integration attributes', async () => { - mParticle.init(apiKey, window.mParticle.config) + mParticle.init(apiKey, window.mParticle.config); await waitForCondition(hasIdentityCallInflightReturned); mParticle.setIntegrationAttribute(128, { @@ -2488,17 +2642,16 @@ describe('forwarders', function() { undefinedValue: undefined, }); - const adobeIntegrationAttributes = mParticle.getIntegrationAttributes( - 128 - ); + const adobeIntegrationAttributes = + mParticle.getIntegrationAttributes(128); expect(adobeIntegrationAttributes).to.eqls({ MCID: 'abcdefg', }); }); - it('should add integration delays to the integrationDelays object', function(done) { - mParticle.init(apiKey, window.mParticle.config) + it('should add integration delays to the integrationDelays object', function (done) { + mParticle.init(apiKey, window.mParticle.config); mParticle._setIntegrationDelay(128, true); mParticle._setIntegrationDelay(24, false); @@ -2520,7 +2673,11 @@ describe('forwarders', function() { mParticle._setIntegrationDelay(10, true); mParticle.init(apiKey, window.mParticle.config); - await waitForCondition(() => window.mParticle.getInstance()?._Store?.identityCallInFlight === false); + await waitForCondition( + () => + window.mParticle.getInstance()?._Store?.identityCallInFlight === + false, + ); fetchMock.resetHistory(); mParticle.logEvent('Test Event1'); @@ -2533,19 +2690,19 @@ describe('forwarders', function() { const sessionStartEvent = findEventFromRequest( fetchMock.calls(), - 'session_start' + 'session_start', ); const ASTEvent = findEventFromRequest( fetchMock.calls(), - 'application_state_transition' + 'application_state_transition', ); const testEvent1 = findEventFromRequest( fetchMock.calls(), - 'Test Event1' + 'Test Event1', ); const testEvent2 = findEventFromRequest( fetchMock.calls(), - 'Test Event2' + 'Test Event2', ); sessionStartEvent.should.be.ok(); @@ -2559,55 +2716,56 @@ describe('forwarders', function() { mParticle._setIntegrationDelay(128, true); expect( Object.keys(mParticle.getInstance()._preInit.integrationDelays) - .length + .length, ).equal(1); mParticle._setIntegrationDelay(24, false); expect( Object.keys(mParticle.getInstance()._preInit.integrationDelays) - .length + .length, ).equal(2); mParticle._setIntegrationDelay(10, true); expect( Object.keys(mParticle.getInstance()._preInit.integrationDelays) - .length + .length, ).equal(3); mParticle.init(apiKey, window.mParticle.config); - await waitForCondition(() => window.mParticle.getInstance()?._Store?.identityCallInFlight === false); + await waitForCondition( + () => + window.mParticle.getInstance()?._Store?.identityCallInFlight === + false, + ); mParticle.logEvent('Test Event1'); // Only the identity is in the calls fetchMock.calls().length.should.equal(1); - const identifyEvent = getIdentityEvent( - fetchMock.calls(), - 'identify' - ); - identifyEvent.should.be.ok() + const identifyEvent = getIdentityEvent(fetchMock.calls(), 'identify'); + identifyEvent.should.be.ok(); // Turn off delays manually because we cannot use sinon.useFakeTimers in the async identity paradigm mParticle._setIntegrationDelay(128, false); mParticle._setIntegrationDelay(24, false); mParticle._setIntegrationDelay(10, false); - mParticle.logEvent('Test Event2'); // this manually logs all the queued events + mParticle.logEvent('Test Event2'); // this manually logs all the queued events fetchMock.calls().length.should.equal(5); const sessionStartEvent = findEventFromRequest( fetchMock.calls(), - 'session_start' + 'session_start', ); const ASTEvent = findEventFromRequest( fetchMock.calls(), - 'application_state_transition' + 'application_state_transition', ); const testEvent1 = findEventFromRequest( fetchMock.calls(), - 'Test Event1' + 'Test Event1', ); const testEvent2 = findEventFromRequest( fetchMock.calls(), - 'Test Event2' + 'Test Event2', ); sessionStartEvent.should.be.ok(); @@ -2617,9 +2775,9 @@ describe('forwarders', function() { }); // https://go.mparticle.com/work/SQDSDKS-6844 - it.skip('integration test - should allow the user to configure the integrationDelayTimeout', function(done) { + it.skip('integration test - should allow the user to configure the integrationDelayTimeout', function (done) { // testing user-configured integrationDelayTimeout - let clock = sinon.useFakeTimers(); + const clock = sinon.useFakeTimers(); mParticle._resetForTests(MPConfig); mParticle.config.integrationDelayTimeout = 1000; mParticle._setIntegrationDelay(128, true); @@ -2627,47 +2785,55 @@ describe('forwarders', function() { mParticle._setIntegrationDelay(10, true); mParticle.init(apiKey, window.mParticle.config); - waitForCondition(() => { - console.log(window.mParticle.getInstance()?._Store?.identityCallInFlight) - return ( - window.mParticle.getInstance()?._Store?.identityCallInFlight === false + waitForCondition( + () => { + console.log( + window.mParticle.getInstance()?._Store + ?.identityCallInFlight, + ); + return ( + window.mParticle.getInstance()?._Store + ?.identityCallInFlight === false + ); + }, + 200, + 10, + clock, + ).then(() => { + fetchMock.resetHistory(); + mParticle.logEvent('Test Event3'); + fetchMock.calls().length.should.equal(0); + + clock.tick(1001); + + mParticle.logEvent('Test Event4'); + fetchMock.calls().length.should.equal(4); + + const sessionStartEvent2 = findEventFromRequest( + fetchMock.calls(), + 'session_start', + ); + const ASTEvent2 = findEventFromRequest( + fetchMock.calls(), + 'application_state_transition', + ); + const testEvent3 = findEventFromRequest( + fetchMock.calls(), + 'Test Event3', + ); + const testEvent4 = findEventFromRequest( + fetchMock.calls(), + 'Test Event4', ); - }, 200, 10, clock) - .then(() => { - fetchMock.resetHistory(); - mParticle.logEvent('Test Event3'); - fetchMock.calls().length.should.equal(0); - - clock.tick(1001); - - mParticle.logEvent('Test Event4'); - fetchMock.calls().length.should.equal(4); - - const sessionStartEvent2 = findEventFromRequest( - fetchMock.calls(), - 'session_start' - ); - const ASTEvent2 = findEventFromRequest( - fetchMock.calls(), - 'application_state_transition' - ); - const testEvent3 = findEventFromRequest( - fetchMock.calls(), - 'Test Event3' - ); - const testEvent4 = findEventFromRequest( - fetchMock.calls(), - 'Test Event4' - ); - sessionStartEvent2.should.be.ok(); - ASTEvent2.should.be.ok(); - testEvent3.should.be.ok(); - testEvent4.should.be.ok(); - clock.restore(); + sessionStartEvent2.should.be.ok(); + ASTEvent2.should.be.ok(); + testEvent3.should.be.ok(); + testEvent4.should.be.ok(); + clock.restore(); - done(); - }) + done(); + }); }); it('integration test - after an integration delay is set to false, should fire an event after the event timeout', async () => { @@ -2676,7 +2842,11 @@ describe('forwarders', function() { mParticle._setIntegrationDelay(128, true); mParticle._setIntegrationDelay(24, false); mParticle.init(apiKey, window.mParticle.config); - await waitForCondition(() => window.mParticle.getInstance()?._Store?.identityCallInFlight === false); + await waitForCondition( + () => + window.mParticle.getInstance()?._Store?.identityCallInFlight === + false, + ); const clock = sinon.useFakeTimers(); fetchMock.resetHistory(); @@ -2764,17 +2934,22 @@ describe('forwarders', function() { mParticle.init(apiKey, window.mParticle.config); - await waitForCondition(() => window.mParticle.getInstance()._Store.configurationLoaded === true && window.mParticle.getInstance()?._Store?.identityCallInFlight === false); + await waitForCondition( + () => + window.mParticle.getInstance()._Store.configurationLoaded === + true && + window.mParticle.getInstance()?._Store?.identityCallInFlight === + false, + ); const activeForwarders = mParticle.getInstance()._getActiveForwarders(); activeForwarders.length.should.equal(2); const moduleIds = [124, 128]; - activeForwarders.forEach(function(forwarder) { + activeForwarders.forEach(function (forwarder) { moduleIds.indexOf(forwarder.id).should.be.greaterThanOrEqual(0); }); }); - // This will pass when we add mpInstance._Store.isInitialized = true; to mp-instance before `processIdentityCallback` it('configures forwarders before events are logged via identify callback', async () => { mParticle._resetForTests(MPConfig); @@ -2784,21 +2959,21 @@ describe('forwarders', function() { }, }; - window.mParticle.config.identityCallback = function() { + window.mParticle.config.identityCallback = function () { mParticle.logEvent('test event'); }; const mockForwarder = new MockForwarder(); mockForwarder.register(window.mParticle.config); window.mParticle.config.kitConfigs.push( - forwarderDefaultConfiguration('MockForwarder') + forwarderDefaultConfiguration('MockForwarder'), ); window.mParticle.config.rq = []; mParticle.init(apiKey, window.mParticle.config); await waitForCondition(hasIdentityCallInflightReturned); window.MockForwarder1.instance.should.have.property( 'processCalled', - true + true, ); //mock a page reload which has no configuredForwarders @@ -2810,9 +2985,8 @@ describe('forwarders', function() { window.MockForwarder1.instance.should.have.property( 'processCalled', - true + true, ); - }); it('should retain preInit.forwarderConstructors, and reinitialize forwarders after calling reset, then init', async () => { @@ -2822,15 +2996,16 @@ describe('forwarders', function() { mParticle.addForwarder(mockForwarder); window.mParticle.config.kitConfigs.push( - forwarderDefaultConfiguration('MockForwarder') + forwarderDefaultConfiguration('MockForwarder'), ); mParticle.init(apiKey, window.mParticle.config); - await waitForCondition(() => window.mParticle.getInstance()?._Store?.identityCallInFlight === false); - mParticle - .getInstance() - ._getActiveForwarders() - .length.should.equal(1); + await waitForCondition( + () => + window.mParticle.getInstance()?._Store?.identityCallInFlight === + false, + ); + mParticle.getInstance()._getActiveForwarders().length.should.equal(1); // client calls reset mParticle.reset(); @@ -2842,17 +3017,18 @@ describe('forwarders', function() { // client reinitializes mParticle after a reset mParticle.init(apiKey, window.mParticle.config); - await waitForCondition(() => window.mParticle.getInstance()?._Store?.identityCallInFlight === false); + await waitForCondition( + () => + window.mParticle.getInstance()?._Store?.identityCallInFlight === + false, + ); // forwarderConstructors are still there - mParticle - .getInstance() - ._getActiveForwarders() - .length.should.equal(1); + mParticle.getInstance()._getActiveForwarders().length.should.equal(1); mParticle.logEvent('send this event to forwarder'); window.MockForwarder1.instance.should.have.property( 'processCalled', - true + true, ); }); @@ -2861,15 +3037,19 @@ describe('forwarders', function() { mParticle.addForwarder(mockForwarder); window.mParticle.config.kitConfigs.push( - forwarderDefaultConfiguration('MockForwarder') + forwarderDefaultConfiguration('MockForwarder'), ); mParticle.init(apiKey, window.mParticle.config); - await waitForCondition(() => window.mParticle.getInstance()?._Store?.identityCallInFlight === false); + await waitForCondition( + () => + window.mParticle.getInstance()?._Store?.identityCallInFlight === + false, + ); mParticle.logEvent('Test Event'); window.MockForwarder1.instance.receivedEvent.should.have.property( - 'SourceMessageId' + 'SourceMessageId', ); }); @@ -2880,11 +3060,15 @@ describe('forwarders', function() { mParticle.addForwarder(mockForwarder); window.mParticle.config.kitConfigs.push( - forwarderDefaultConfiguration('MockForwarder') + forwarderDefaultConfiguration('MockForwarder'), ); mParticle.init(apiKey, window.mParticle.config); - await waitForCondition(() => window.mParticle.getInstance()?._Store?.identityCallInFlight === false); + await waitForCondition( + () => + window.mParticle.getInstance()?._Store?.identityCallInFlight === + false, + ); mParticle.logBaseEvent({ messageType: 4, @@ -2897,7 +3081,7 @@ describe('forwarders', function() { window.MockForwarder1.instance.receivedEvent.should.have.property( 'SourceMessageId', - 'abcdefg' + 'abcdefg', ); }); @@ -2908,47 +3092,51 @@ describe('forwarders', function() { mParticle.addForwarder(mockForwarder); window.mParticle.config.kitConfigs.push( - forwarderDefaultConfiguration('MockForwarder') + forwarderDefaultConfiguration('MockForwarder'), ); window.mParticle.config.logLevel = 'verbose'; let infoMessage; window.mParticle.config.logger = { - verbose: function(msg) { + verbose: function (msg) { infoMessage = msg; }, }; mParticle.init(apiKey, window.mParticle.config); - await waitForCondition(() => window.mParticle.getInstance()?._Store?.identityCallInFlight === false); + await waitForCondition( + () => + window.mParticle.getInstance()?._Store?.identityCallInFlight === + false, + ); mParticle.logEvent('Test Event'); infoMessage.should.equal('Test Event sent'); }); - describe('kits with suffixes', function() { - it('should add forwarders with suffixes and initialize them accordingly if there is a coresponding kit config with the same suffix', function(done) { + describe('kits with suffixes', function () { + it('should add forwarders with suffixes and initialize them accordingly if there is a coresponding kit config with the same suffix', function (done) { mParticle._resetForTests(MPConfig); const mockForwarder = new MockForwarder( 'ForwarderWithSuffixV3', 1, - 'v3' + 'v3', ); const mockForwarder2 = new MockForwarder( 'ForwarderWithSuffixV4', 1, - 'v4' + 'v4', ); mParticle.addForwarder(mockForwarder); mParticle.addForwarder(mockForwarder2); window.mParticle.config.kitConfigs.push( - forwarderDefaultConfiguration('ForwarderWithSuffixV3', 1, 'v3') + forwarderDefaultConfiguration('ForwarderWithSuffixV3', 1, 'v3'), ); window.mParticle.config.kitConfigs.push( - forwarderDefaultConfiguration('ForwarderWithSuffixV4', 1, 'v4') + forwarderDefaultConfiguration('ForwarderWithSuffixV4', 1, 'v4'), ); mParticle.init(apiKey, window.mParticle.config); @@ -2961,18 +3149,18 @@ describe('forwarders', function() { done(); }); - it('should not add a forwarder with suffix if there is not a corresponding kit config with the same suffix', function(done) { + it('should not add a forwarder with suffix if there is not a corresponding kit config with the same suffix', function (done) { mParticle._resetForTests(MPConfig); const mockForwarder = new MockForwarder( 'ForwarderWithSuffix', 1, - 'v3' + 'v3', ); mParticle.addForwarder(mockForwarder); window.mParticle.config.kitConfigs.push( - forwarderDefaultConfiguration('ForwarderWithSuffix', 1, 'v4') + forwarderDefaultConfiguration('ForwarderWithSuffix', 1, 'v4'), ); mParticle.init(apiKey, window.mParticle.config); @@ -2986,33 +3174,33 @@ describe('forwarders', function() { }); }); - describe('side loaded kits', function() { - describe('initialization', function() { - beforeEach(function() { + describe('side loaded kits', function () { + describe('initialization', function () { + beforeEach(function () { mParticle._resetForTests(MPConfig); delete mParticle._instances['default_instance']; }); - afterEach(function() { + afterEach(function () { delete window.MockForwarder1; fetchMock.restore(); }); - it('should add sideloaded kits to the active forwarders', function() { + it('should add sideloaded kits to the active forwarders', function () { const sideloadedKit1 = new MockSideloadedKit( 'SideloadedKit1', - 1 + 1, ); const sideloadedKit2 = new MockSideloadedKit( 'SideloadedKit2', - 2 + 2, ); const mpSideloadedKit1 = new mParticle.MPSideloadedKit( - sideloadedKit1 + sideloadedKit1, ); const mpSideloadedKit2 = new mParticle.MPSideloadedKit( - sideloadedKit2 + sideloadedKit2, ); const sideloadedKits = [mpSideloadedKit1, mpSideloadedKit2]; @@ -3024,33 +3212,33 @@ describe('forwarders', function() { ._getActiveForwarders(); expect( activeForwarders.length, - 'active forwarders length' + 'active forwarders length', ).to.equal(sideloadedKits.length); expect( activeForwarders[0].name, - '1st active forwarder ' + '1st active forwarder ', ).to.deep.equal(sideloadedKit1.name); expect( activeForwarders[1].name, - '2nd active forwarder' + '2nd active forwarder', ).to.deep.equal(sideloadedKit2.name); }); - it('should add sideloaded kits along with configured forwarders from server to the active forwarders', function() { + it('should add sideloaded kits along with configured forwarders from server to the active forwarders', function () { const sideloadedKit1 = new MockSideloadedKit( 'SideloadedKit1', - 1 + 1, ); const sideloadedKit2 = new MockSideloadedKit( 'SideloadedKit2', - 2 + 2, ); const mpSideloadedKit1 = new mParticle.MPSideloadedKit( - sideloadedKit1 + sideloadedKit1, ); const mpSideloadedKit2 = new mParticle.MPSideloadedKit( - sideloadedKit2 + sideloadedKit2, ); const sideloadedKits = [mpSideloadedKit1, mpSideloadedKit2]; @@ -3062,7 +3250,7 @@ describe('forwarders', function() { mParticle.addForwarder(mockForwarder); window.mParticle.config.kitConfigs.push( - forwarderDefaultConfiguration('fooForwarder', 1) + forwarderDefaultConfiguration('fooForwarder', 1), ); mParticle.init(apiKey, window.mParticle.config); @@ -3072,37 +3260,37 @@ describe('forwarders', function() { expect( activeForwarders.length, - 'active forwarders length' + 'active forwarders length', ).to.equal(sideloadedKits.length + 1); expect( activeForwarders[0].name, - '1st active forwarder name' + '1st active forwarder name', ).to.equal('fooForwarder'); expect( activeForwarders[1].name, - '2nd active forwarder ' + '2nd active forwarder ', ).to.deep.equal(sideloadedKit1.name); expect( activeForwarders[2].name, - '3rd active forwarder' + '3rd active forwarder', ).to.deep.equal(sideloadedKit2.name); }); it('should add a flag in batches for reporting if sideloaded kits are used', async () => { const sideloadedKit1 = new MockSideloadedKit( 'SideloadedKit1', - 1 + 1, ); const sideloadedKit2 = new MockSideloadedKit( 'SideloadedKit2', - 2 + 2, ); const mpSideloadedKit1 = new mParticle.MPSideloadedKit( - sideloadedKit1 + sideloadedKit1, ); const mpSideloadedKit2 = new mParticle.MPSideloadedKit( - sideloadedKit2 + sideloadedKit2, ); const sideloadedKits = [mpSideloadedKit1, mpSideloadedKit2]; @@ -3114,12 +3302,16 @@ describe('forwarders', function() { mParticle.addForwarder(mockForwarder); window.mParticle.config.kitConfigs.push( - forwarderDefaultConfiguration('fooForwarder', 1) + forwarderDefaultConfiguration('fooForwarder', 1), ); mParticle.init(apiKey, window.mParticle.config); - await waitForCondition(() => window.mParticle.getInstance()?._Store?.identityCallInFlight === false); - + await waitForCondition( + () => + window.mParticle.getInstance()?._Store + ?.identityCallInFlight === false, + ); + const mpInstance = window.mParticle.getInstance(); expect(mpInstance._Store.sideloadedKitsCount).to.equal(2); @@ -3131,50 +3323,58 @@ describe('forwarders', function() { const eventCall = fetchMock.calls()[1]; expect(eventCall[0].split('/')[6]).to.equal('events'); - const batch = JSON.parse(fetchMock.calls()[1][1].body as string); + const batch = JSON.parse( + fetchMock.calls()[1][1].body as string, + ); expect(batch).to.be.ok; expect(batch).to.have.property('application_info'); expect(batch.application_info).to.have.property( 'sideloaded_kits_count', - 2 + 2, ); }); it('should NOT add a flag in batches for reporting if sideloaded kits are not used', async () => { mParticle.init(apiKey, window.mParticle.config); - await waitForCondition(() => window.mParticle.getInstance()?._Store?.identityCallInFlight === false); + await waitForCondition( + () => + window.mParticle.getInstance()?._Store + ?.identityCallInFlight === false, + ); mParticle.logEvent('foo', mParticle.EventType.Navigation); - const batch = JSON.parse(fetchMock.lastCall()[1].body as string); + const batch = JSON.parse( + fetchMock.lastCall()[1].body as string, + ); expect(batch).to.have.property('application_info'); expect(batch.application_info).not.to.have.property( - 'sideloaded_kits_count' + 'sideloaded_kits_count', ); }); - describe('filter dictionary integration tests', function() { + describe('filter dictionary integration tests', function () { let sideloadedKit1; let sideloadedKit2; let mpSideloadedKit1; let mpSideloadedKit2; - beforeEach(function() { + beforeEach(function () { sideloadedKit1 = new MockSideloadedKit('SideloadedKit1', 1); sideloadedKit2 = new MockSideloadedKit('SideloadedKit2', 2); mpSideloadedKit1 = new mParticle.MPSideloadedKit( - sideloadedKit1 + sideloadedKit1, ); mpSideloadedKit2 = new mParticle.MPSideloadedKit( - sideloadedKit2 + sideloadedKit2, ); mParticle._resetForTests(MPConfig); delete mParticle._instances['default_instance']; }); - afterEach(function() { + afterEach(function () { delete window.MockForwarder1; fetchMock.restore(); }); @@ -3182,11 +3382,11 @@ describe('forwarders', function() { it('should filter event names out properly when set', async () => { mpSideloadedKit1.addEventNameFilter( mParticle.EventType.Unknown, - 'Test Event' + 'Test Event', ); mpSideloadedKit2.addEventNameFilter( mParticle.EventType.Unknown, - 'Test Event2' + 'Test Event2', ); const sideloadedKits = [mpSideloadedKit1, mpSideloadedKit2]; @@ -3194,7 +3394,11 @@ describe('forwarders', function() { window.mParticle.config.sideloadedKits = sideloadedKits; mParticle.init(apiKey, window.mParticle.config); - await waitForCondition(() => window.mParticle.getInstance()?._Store?.identityCallInFlight === false); + await waitForCondition( + () => + window.mParticle.getInstance()?._Store + ?.identityCallInFlight === false, + ); mParticle.logEvent('Test Event'); @@ -3202,29 +3406,29 @@ describe('forwarders', function() { // SideloadedKit11 has received the session start event, but not the Test Event // SideloadedKit22 will receive the Test Event window.SideloadedKit11.instance.receivedEvent.EventName.should.not.equal( - 'Test Event' + 'Test Event', ); window.SideloadedKit22.instance.receivedEvent.EventName.should.equal( - 'Test Event' + 'Test Event', ); mParticle.logEvent('Test Event2'); // SideloadedKit11 receives Test Event2, but SideloadedKit22 does not window.SideloadedKit11.instance.receivedEvent.EventName.should.equal( - 'Test Event2' + 'Test Event2', ); window.SideloadedKit22.instance.receivedEvent.EventName.should.not.equal( - 'Test Event2' + 'Test Event2', ); }); it('should filter event types out properly when set', async () => { mpSideloadedKit1.addEventTypeFilter( - mParticle.EventType.Unknown + mParticle.EventType.Unknown, ); mpSideloadedKit2.addEventTypeFilter( - mParticle.EventType.Navigation + mParticle.EventType.Navigation, ); const sideloadedKits = [mpSideloadedKit1, mpSideloadedKit2]; @@ -3232,47 +3436,51 @@ describe('forwarders', function() { window.mParticle.config.sideloadedKits = sideloadedKits; mParticle.init(apiKey, window.mParticle.config); - await waitForCondition(() => window.mParticle.getInstance()?._Store?.identityCallInFlight === false); + await waitForCondition( + () => + window.mParticle.getInstance()?._Store + ?.identityCallInFlight === false, + ); mParticle.logEvent( 'Test Event', - mParticle.EventType.Unknown + mParticle.EventType.Unknown, ); // The received event gets replaced by the last event sent to the forwarder // SideloadedKit11 has received the session start event, but not the Test Event of EventType.Unknown // SideloadedKit22 will receive the Test Event of EventType.Unknown window.SideloadedKit11.instance.receivedEvent.EventName.should.not.equal( - 'Test Event' + 'Test Event', ); window.SideloadedKit22.instance.receivedEvent.EventName.should.equal( - 'Test Event' + 'Test Event', ); mParticle.logEvent( 'Test Event2', - mParticle.EventType.Navigation + mParticle.EventType.Navigation, ); // SideloadedKit11 receives the Navigation Event, SideloadedKit22 does not window.SideloadedKit11.instance.receivedEvent.EventName.should.equal( - 'Test Event2' + 'Test Event2', ); window.SideloadedKit22.instance.receivedEvent.EventName.should.not.equal( - 'Test Event2' + 'Test Event2', ); }); - it('should filter event attributes out properly when set', async function() { + it('should filter event attributes out properly when set', async function () { mpSideloadedKit1.addEventAttributeFilter( mParticle.EventType.Navigation, 'Test Event', - 'testAttr1' + 'testAttr1', ); mpSideloadedKit2.addEventAttributeFilter( mParticle.EventType.Navigation, 'Test Event', - 'testAttr2' + 'testAttr2', ); const sideloadedKits = [mpSideloadedKit1, mpSideloadedKit2]; @@ -3280,7 +3488,11 @@ describe('forwarders', function() { window.mParticle.config.sideloadedKits = sideloadedKits; mParticle.init(apiKey, window.mParticle.config); - await waitForCondition(() => window.mParticle.getInstance()?._Store?.identityCallInFlight === false); + await waitForCondition( + () => + window.mParticle.getInstance()?._Store + ?.identityCallInFlight === false, + ); const attrs = { testAttr1: 'foo', @@ -3290,27 +3502,27 @@ describe('forwarders', function() { mParticle.logEvent( 'Test Event', mParticle.EventType.Navigation, - attrs + attrs, ); window.SideloadedKit11.instance.receivedEvent.EventAttributes.should.have.property( 'testAttr2', - 'bar' + 'bar', ); window.SideloadedKit11.instance.receivedEvent.EventAttributes.should.not.property( - 'testAttr1' + 'testAttr1', ); window.SideloadedKit22.instance.receivedEvent.EventAttributes.should.have.property( 'testAttr1', - 'foo' + 'foo', ); window.SideloadedKit22.instance.receivedEvent.EventAttributes.should.not.property( - 'testAttr2' + 'testAttr2', ); }); - it('should filter screen names out properly when set', async function() { + it('should filter screen names out properly when set', async function () { mpSideloadedKit1.addScreenNameFilter('Test Screen Name 1'); mpSideloadedKit2.addScreenNameFilter('Test Screen Name 2'); @@ -3319,7 +3531,11 @@ describe('forwarders', function() { window.mParticle.config.sideloadedKits = sideloadedKits; mParticle.init(apiKey, window.mParticle.config); - await waitForCondition(() => window.mParticle.getInstance()?._Store?.identityCallInFlight === false); + await waitForCondition( + () => + window.mParticle.getInstance()?._Store + ?.identityCallInFlight === false, + ); mParticle.logPageView('Test Screen Name 1'); @@ -3327,31 +3543,31 @@ describe('forwarders', function() { // SideloadedKit11 has received the session start event, but not the Test Screen Name 1 event // SideloadedKit22 does receive it window.SideloadedKit11.instance.receivedEvent.EventName.should.not.equal( - 'Test Screen Name 1' + 'Test Screen Name 1', ); window.SideloadedKit22.instance.receivedEvent.EventName.should.equal( - 'Test Screen Name 1' + 'Test Screen Name 1', ); mParticle.logPageView('Test Screen Name 2'); // SideloadedKit11 will receive Test Screen Name 2, but SideloadedKit22 does not window.SideloadedKit11.instance.receivedEvent.EventName.should.equal( - 'Test Screen Name 2' + 'Test Screen Name 2', ); window.SideloadedKit22.instance.receivedEvent.EventName.should.not.equal( - 'Test Screen Name 2' + 'Test Screen Name 2', ); }); - it('should filter screen name attribute out properly when set', async function() { + it('should filter screen name attribute out properly when set', async function () { mpSideloadedKit1.addScreenAttributeFilter( 'Test Screen Name 1', - 'testAttr1' + 'testAttr1', ); mpSideloadedKit2.addScreenAttributeFilter( 'Test Screen Name 1', - 'testAttr2' + 'testAttr2', ); const sideloadedKits = [mpSideloadedKit1, mpSideloadedKit2]; @@ -3359,7 +3575,11 @@ describe('forwarders', function() { window.mParticle.config.sideloadedKits = sideloadedKits; mParticle.init(apiKey, window.mParticle.config); - await waitForCondition(() => window.mParticle.getInstance()?._Store?.identityCallInFlight === false); + await waitForCondition( + () => + window.mParticle.getInstance()?._Store + ?.identityCallInFlight === false, + ); const attrs = { testAttr1: 'foo', @@ -3370,26 +3590,26 @@ describe('forwarders', function() { window.SideloadedKit11.instance.receivedEvent.EventAttributes.should.have.property( 'testAttr2', - 'bar' + 'bar', ); window.SideloadedKit11.instance.receivedEvent.EventAttributes.should.not.property( - 'testAttr1' + 'testAttr1', ); window.SideloadedKit22.instance.receivedEvent.EventAttributes.should.have.property( 'testAttr1', - 'foo' + 'foo', ); window.SideloadedKit22.instance.receivedEvent.EventAttributes.should.not.property( - 'testAttr2' + 'testAttr2', ); }); it('should filter user identities out properly when set', async () => { mpSideloadedKit1.addUserIdentityFilter( - mParticle.IdentityType.Email + mParticle.IdentityType.Email, ); mpSideloadedKit2.addUserIdentityFilter( - mParticle.IdentityType.Other + mParticle.IdentityType.Other, ); const sideloadedKits = [mpSideloadedKit1, mpSideloadedKit2]; @@ -3397,7 +3617,11 @@ describe('forwarders', function() { window.mParticle.config.sideloadedKits = sideloadedKits; mParticle.init(apiKey, window.mParticle.config); - await waitForCondition(() => window.mParticle.getInstance()?._Store?.identityCallInFlight === false); + await waitForCondition( + () => + window.mParticle.getInstance()?._Store + ?.identityCallInFlight === false, + ); mParticle.Identity.login({ userIdentities: { @@ -3408,31 +3632,35 @@ describe('forwarders', function() { mParticle.logPageView('Test Screen Name 1'); - await waitForCondition(() => window.mParticle.getInstance()?._Store?.identityCallInFlight === false); + await waitForCondition( + () => + window.mParticle.getInstance()?._Store + ?.identityCallInFlight === false, + ); // SideloadedKit11 will receive an event with only an Other identity type window.SideloadedKit11.instance.receivedEvent.UserIdentities.length.should.equal( - 1 + 1, ); window.SideloadedKit11.instance.receivedEvent.UserIdentities[0].Type.should.equal( - mParticle.IdentityType.Other + mParticle.IdentityType.Other, ); window.SideloadedKit11.instance.receivedEvent.UserIdentities[0].Identity.should.equal( - 'test' + 'test', ); // SideloadedKit22 will receive an event with only an Email identity type window.SideloadedKit22.instance.receivedEvent.UserIdentities.length.should.equal( - 1 + 1, ); window.SideloadedKit22.instance.receivedEvent.UserIdentities[0].Type.should.equal( - mParticle.IdentityType.Email + mParticle.IdentityType.Email, ); window.SideloadedKit22.instance.receivedEvent.UserIdentities[0].Identity.should.equal( - 'test@gmail.com' + 'test@gmail.com', ); }); - it('should filter user attributes out properly when set', async function() { + it('should filter user attributes out properly when set', async function () { mpSideloadedKit1.addUserAttributeFilter('testAttr1'); mpSideloadedKit2.addUserAttributeFilter('testAttr2'); @@ -3441,71 +3669,79 @@ describe('forwarders', function() { window.mParticle.config.sideloadedKits = sideloadedKits; mParticle.init(apiKey, window.mParticle.config); - await waitForCondition(() => window.mParticle.getInstance()?._Store?.identityCallInFlight === false); + await waitForCondition( + () => + window.mParticle.getInstance()?._Store + ?.identityCallInFlight === false, + ); mParticle.Identity.getCurrentUser().setUserAttribute( 'testAttr1', - 'foo' + 'foo', ); mParticle.Identity.getCurrentUser().setUserAttribute( 'testAttr2', - 'bar' + 'bar', ); mParticle.logPageView('Test Screen Name 1'); window.SideloadedKit11.instance.receivedEvent.UserAttributes.should.have.property( 'testAttr2', - 'bar' + 'bar', ); window.SideloadedKit11.instance.receivedEvent.UserAttributes.should.not.have.property( - 'testAttr1' + 'testAttr1', ); window.SideloadedKit22.instance.receivedEvent.UserAttributes.should.have.property( 'testAttr1', - 'foo' + 'foo', ); window.SideloadedKit22.instance.receivedEvent.UserAttributes.should.not.have.property( - 'testAttr2' + 'testAttr2', ); }); }); }); - describe('forwarding', function() { - beforeEach(function() { + describe('forwarding', function () { + beforeEach(function () { mParticle._resetForTests(MPConfig); delete mParticle._instances['default_instance']; }); - afterEach(function() { + afterEach(function () { delete window.MockForwarder1; fetchMock.restore(); }); - it('should send event to sideloaded kits', async function() { + it('should send event to sideloaded kits', async function () { const sideloadedKit1 = new MockSideloadedKit( 'SideloadedKit1', - 1 + 1, ); const sideloadedKit2 = new MockSideloadedKit( 'SideloadedKit2', - 2 + 2, ); const mpSideloadedKit1 = new mParticle.MPSideloadedKit( - sideloadedKit1 + sideloadedKit1, ); const mpSideloadedKit2 = new mParticle.MPSideloadedKit( - sideloadedKit2 + sideloadedKit2, ); const sideloadedKits = [mpSideloadedKit1, mpSideloadedKit2]; window.mParticle.config.sideloadedKits = sideloadedKits; mParticle.init(apiKey, window.mParticle.config); - await waitForCondition(() => window.mParticle.getInstance()?._Store?.identityCallInFlight === false); + await waitForCondition( + () => + window.mParticle.getInstance()?._Store + ?.identityCallInFlight === false, + ); mParticle.logEvent('foo', mParticle.EventType.Navigation); const sideloadedKit1Event = @@ -3517,21 +3753,21 @@ describe('forwarders', function() { sideloadedKit2Event.should.have.property('EventName', 'foo'); }); - it('should invoke sideloaded identify call', async function() { + it('should invoke sideloaded identify call', async function () { const sideloadedKit1 = new MockSideloadedKit( 'SideloadedKit1', - 1 + 1, ); const sideloadedKit2 = new MockSideloadedKit( 'SideloadedKit2', - 2 + 2, ); const mpSideloadedKit1 = new mParticle.MPSideloadedKit( - sideloadedKit1 + sideloadedKit1, ); const mpSideloadedKit2 = new mParticle.MPSideloadedKit( - sideloadedKit2 + sideloadedKit2, ); const sideloadedKits = [mpSideloadedKit1, mpSideloadedKit2]; @@ -3545,42 +3781,46 @@ describe('forwarders', function() { window.mParticle.config.sideloadedKits = sideloadedKits; mParticle.init(apiKey, window.mParticle.config); - await waitForCondition(() => window.mParticle.getInstance()?._Store?.identityCallInFlight === false); + await waitForCondition( + () => + window.mParticle.getInstance()?._Store + ?.identityCallInFlight === false, + ); window.SideloadedKit11.instance.should.have.property( 'setUserIdentityCalled', - true + true, ); window.SideloadedKit22.instance.should.have.property( 'setUserIdentityCalled', - true + true, ); window.SideloadedKit11.instance.should.have.property( 'onUserIdentifiedCalled', - true + true, ); window.SideloadedKit22.instance.should.have.property( 'onUserIdentifiedCalled', - true + true, ); }); - it('should invoke sideloaded set/removeUserAttribute call', async function() { + it('should invoke sideloaded set/removeUserAttribute call', async function () { const sideloadedKit1 = new MockSideloadedKit( 'SideloadedKit1', - 1 + 1, ); const sideloadedKit2 = new MockSideloadedKit( 'SideloadedKit2', - 2 + 2, ); const mpSideloadedKit1 = new mParticle.MPSideloadedKit( - sideloadedKit1 + sideloadedKit1, ); const mpSideloadedKit2 = new mParticle.MPSideloadedKit( - sideloadedKit2 + sideloadedKit2, ); const sideloadedKits = [mpSideloadedKit1, mpSideloadedKit2]; @@ -3588,50 +3828,54 @@ describe('forwarders', function() { window.mParticle.config.sideloadedKits = sideloadedKits; mParticle.init(apiKey, window.mParticle.config); - await waitForCondition(() => window.mParticle.getInstance()?._Store?.identityCallInFlight === false); + await waitForCondition( + () => + window.mParticle.getInstance()?._Store + ?.identityCallInFlight === false, + ); mParticle.Identity.getCurrentUser().setUserAttribute( 'gender', - 'male' + 'male', ); mParticle.Identity.getCurrentUser().removeUserAttribute( - 'gender' + 'gender', ); window.SideloadedKit11.instance.should.have.property( 'setUserAttributeCalled', - true + true, ); window.SideloadedKit22.instance.should.have.property( 'setUserAttributeCalled', - true + true, ); window.SideloadedKit11.instance.should.have.property( 'removeUserAttributeCalled', - true + true, ); window.SideloadedKit22.instance.should.have.property( 'removeUserAttributeCalled', - true + true, ); }); - it('should invoke sideloaded logout call', async function() { + it('should invoke sideloaded logout call', async function () { const sideloadedKit1 = new MockSideloadedKit( 'SideloadedKit1', - 1 + 1, ); const sideloadedKit2 = new MockSideloadedKit( 'SideloadedKit2', - 2 + 2, ); const mpSideloadedKit1 = new mParticle.MPSideloadedKit( - sideloadedKit1 + sideloadedKit1, ); const mpSideloadedKit2 = new mParticle.MPSideloadedKit( - sideloadedKit2 + sideloadedKit2, ); const sideloadedKits = [mpSideloadedKit1, mpSideloadedKit2]; @@ -3639,37 +3883,45 @@ describe('forwarders', function() { window.mParticle.config.sideloadedKits = sideloadedKits; mParticle.init(apiKey, window.mParticle.config); - await waitForCondition(() => window.mParticle.getInstance()?._Store?.identityCallInFlight === false); + await waitForCondition( + () => + window.mParticle.getInstance()?._Store + ?.identityCallInFlight === false, + ); mParticle.Identity.logout(); - await waitForCondition(() => window.mParticle.getInstance()?._Store?.identityCallInFlight === false); + await waitForCondition( + () => + window.mParticle.getInstance()?._Store + ?.identityCallInFlight === false, + ); window.SideloadedKit11.instance.should.have.property( 'onLogoutCompleteCalled', - true + true, ); window.SideloadedKit22.instance.should.have.property( 'onLogoutCompleteCalled', - true + true, ); }); - it('should invoke sideloaded login call', async function() { + it('should invoke sideloaded login call', async function () { const sideloadedKit1 = new MockSideloadedKit( 'SideloadedKit1', - 1 + 1, ); const sideloadedKit2 = new MockSideloadedKit( 'SideloadedKit2', - 2 + 2, ); const mpSideloadedKit1 = new mParticle.MPSideloadedKit( - sideloadedKit1 + sideloadedKit1, ); const mpSideloadedKit2 = new mParticle.MPSideloadedKit( - sideloadedKit2 + sideloadedKit2, ); const sideloadedKits = [mpSideloadedKit1, mpSideloadedKit2]; @@ -3677,38 +3929,46 @@ describe('forwarders', function() { window.mParticle.config.sideloadedKits = sideloadedKits; mParticle.init(apiKey, window.mParticle.config); - await waitForCondition(() => window.mParticle.getInstance()?._Store?.identityCallInFlight === false); + await waitForCondition( + () => + window.mParticle.getInstance()?._Store + ?.identityCallInFlight === false, + ); mParticle.Identity.login({ userIdentities: { customerid: 'abc' }, }); - await waitForCondition(() => window.mParticle.getInstance()?._Store?.identityCallInFlight === false); + await waitForCondition( + () => + window.mParticle.getInstance()?._Store + ?.identityCallInFlight === false, + ); window.SideloadedKit11.instance.should.have.property( 'onLoginCompleteCalled', - true + true, ); window.SideloadedKit22.instance.should.have.property( 'onLoginCompleteCalled', - true + true, ); }); - it('should invoke sideloaded modify call', async function() { + it('should invoke sideloaded modify call', async function () { const sideloadedKit1 = new MockSideloadedKit( 'SideloadedKit1', - 1 + 1, ); const sideloadedKit2 = new MockSideloadedKit( 'SideloadedKit2', - 2 + 2, ); const mpSideloadedKit1 = new mParticle.MPSideloadedKit( - sideloadedKit1 + sideloadedKit1, ); const mpSideloadedKit2 = new mParticle.MPSideloadedKit( - sideloadedKit2 + sideloadedKit2, ); const sideloadedKits = [mpSideloadedKit1, mpSideloadedKit2]; @@ -3716,38 +3976,46 @@ describe('forwarders', function() { window.mParticle.config.sideloadedKits = sideloadedKits; mParticle.init(apiKey, window.mParticle.config); - await waitForCondition(() => window.mParticle.getInstance()?._Store?.identityCallInFlight === false); + await waitForCondition( + () => + window.mParticle.getInstance()?._Store + ?.identityCallInFlight === false, + ); mParticle.Identity.modify({ userIdentities: { customerid: 'abc' }, }); - await waitForCondition(() => window.mParticle.getInstance()?._Store?.identityCallInFlight === false); + await waitForCondition( + () => + window.mParticle.getInstance()?._Store + ?.identityCallInFlight === false, + ); window.SideloadedKit11.instance.should.have.property( 'onModifyCompleteCalled', - true + true, ); window.SideloadedKit22.instance.should.have.property( 'onModifyCompleteCalled', - true + true, ); }); - it('should invoke sideloaded modify call', async function() { + it('should invoke sideloaded modify call', async function () { const sideloadedKit1 = new MockSideloadedKit( 'SideloadedKit1', - 1 + 1, ); const sideloadedKit2 = new MockSideloadedKit( 'SideloadedKit2', - 2 + 2, ); const mpSideloadedKit1 = new mParticle.MPSideloadedKit( - sideloadedKit1 + sideloadedKit1, ); const mpSideloadedKit2 = new mParticle.MPSideloadedKit( - sideloadedKit2 + sideloadedKit2, ); const sideloadedKits = [mpSideloadedKit1, mpSideloadedKit2]; @@ -3755,19 +4023,23 @@ describe('forwarders', function() { window.mParticle.config.sideloadedKits = sideloadedKits; mParticle.init(apiKey, window.mParticle.config); - await waitForCondition(() => window.mParticle.getInstance()?._Store?.identityCallInFlight === false); + await waitForCondition( + () => + window.mParticle.getInstance()?._Store + ?.identityCallInFlight === false, + ); mParticle.setOptOut(true); window.SideloadedKit11.instance.should.have.property( 'setOptOutCalled', - true + true, ); window.SideloadedKit22.instance.should.have.property( 'setOptOutCalled', - true + true, ); }); }); }); -}); \ No newline at end of file +}); diff --git a/test/src/tests-helpers.js b/test/src/tests-helpers.js index 968cc8c12..65875bd82 100644 --- a/test/src/tests-helpers.js +++ b/test/src/tests-helpers.js @@ -1,16 +1,12 @@ -import { - urls, - apiKey, - testMPID, - mParticle, -} from './config/constants'; +import { urls, apiKey, testMPID, mParticle } from './config/constants'; import sinon from 'sinon'; import Utils from './config/utils'; -const { waitForCondition, fetchMockSuccess, hasIdentityCallInflightReturned} = Utils; +const { waitForCondition, fetchMockSuccess, hasIdentityCallInflightReturned } = + Utils; -describe('helpers', function() { - beforeEach(function() { +describe('helpers', function () { + beforeEach(function () { fetchMockSuccess(urls.events); fetchMockSuccess(urls.identify, { context: null, @@ -23,10 +19,9 @@ describe('helpers', function() { }); mParticle.init(apiKey, window.mParticle.config); - }); - it('should correctly validate an attribute value', function(done) { + it('should correctly validate an attribute value', function (done) { const validatedString = mParticle .getInstance() ._Helpers.Validators.isValidAttributeValue('testValue1'); @@ -59,17 +54,19 @@ describe('helpers', function() { it('should return event name in warning when sanitizing invalid attributes', async () => { await waitForCondition(hasIdentityCallInflightReturned); const bond = sinon.spy(mParticle.getInstance().Logger, 'warning'); - mParticle.logEvent('eventName', mParticle.EventType.Location, {invalidValue: {}}); + mParticle.logEvent('eventName', mParticle.EventType.Location, { + invalidValue: {}, + }); bond.called.should.eql(true); bond.callCount.should.equal(1); bond.getCalls()[0].args[0].should.eql( - "For 'eventName', the corresponding attribute value of 'invalidValue' must be a string, number, boolean, or null." + "For 'eventName', the corresponding attribute value of 'invalidValue' must be a string, number, boolean, or null.", ); }); - it('should return product name in warning when sanitizing invalid attributes', function(done) { + it('should return product name in warning when sanitizing invalid attributes', function (done) { const bond = sinon.spy(mParticle.getInstance().Logger, 'warning'); mParticle.eCommerce.createProduct( 'productName', @@ -77,17 +74,17 @@ describe('helpers', function() { 1, 1, 'variant', - 'category', - 'brand', - 'position', - 'couponCode', - {invalidValue: {}} - ) + 'category', + 'brand', + 'position', + 'couponCode', + { invalidValue: {} }, + ); bond.called.should.eql(true); bond.callCount.should.equal(1); bond.getCalls()[0].args[0].should.eql( - "For 'productName', the corresponding attribute value of 'invalidValue' must be a string, number, boolean, or null." + "For 'productName', the corresponding attribute value of 'invalidValue' must be a string, number, boolean, or null.", ); done(); @@ -98,21 +95,33 @@ describe('helpers', function() { const bond = sinon.spy(mParticle.getInstance().Logger, 'warning'); - const product1 = mParticle.eCommerce.createProduct('prod1', 'prod1sku', 999); - const product2 = mParticle.eCommerce.createProduct('prod2', 'prod2sku', 799); + const product1 = mParticle.eCommerce.createProduct( + 'prod1', + 'prod1sku', + 999, + ); + const product2 = mParticle.eCommerce.createProduct( + 'prod2', + 'prod2sku', + 799, + ); - const customAttributes = {invalidValue: {}}; - mParticle.eCommerce.logProductAction(mParticle.ProductActionType.AddToCart, [product1, product2], customAttributes); + const customAttributes = { invalidValue: {} }; + mParticle.eCommerce.logProductAction( + mParticle.ProductActionType.AddToCart, + [product1, product2], + customAttributes, + ); bond.called.should.eql(true); bond.callCount.should.equal(1); - + bond.getCalls()[0].args[0].should.eql( - "For 'eCommerce - AddToCart', the corresponding attribute value of 'invalidValue' must be a string, number, boolean, or null." + "For 'eCommerce - AddToCart', the corresponding attribute value of 'invalidValue' must be a string, number, boolean, or null.", ); }); - it('should correctly validate an identity request with copyUserAttribute as a key using any identify method', function(done) { + it('should correctly validate an identity request with copyUserAttribute as a key using any identify method', function (done) { const identityApiData = { userIdentities: { customerid: '123', @@ -121,7 +130,10 @@ describe('helpers', function() { }; const identifyResult = mParticle .getInstance() - ._Helpers.Validators.validateIdentities(identityApiData, 'identify'); + ._Helpers.Validators.validateIdentities( + identityApiData, + 'identify', + ); const logoutResult = mParticle .getInstance() ._Helpers.Validators.validateIdentities(identityApiData, 'logout'); @@ -140,7 +152,7 @@ describe('helpers', function() { done(); }); - it('should correctly parse string or number', function(done) { + it('should correctly parse string or number', function (done) { const string = 'abc'; const number = 123; const object = {}; @@ -171,7 +183,7 @@ describe('helpers', function() { done(); }); - it('should filterUserIdentities and include customerId as first in the array', function(done) { + it('should filterUserIdentities and include customerId as first in the array', function (done) { const filterList = [2, 4, 6, 8]; const userIdentitiesObject = { email: 'test@gmail.com', @@ -190,7 +202,7 @@ describe('helpers', function() { filteredIdentities[0].should.have.property('Type', 1); filteredIdentities[1].should.have.property( 'Identity', - 'test@gmail.com' + 'test@gmail.com', ); filteredIdentities[1].should.have.property('Type', 7); filteredIdentities[2].should.have.property('Identity', 'abc'); @@ -199,7 +211,7 @@ describe('helpers', function() { done(); }); - it('should return the appropriate boolean for if events should be delayed by an integration', function(done) { + it('should return the appropriate boolean for if events should be delayed by an integration', function (done) { const integrationDelays1 = { 128: false, 20: false, @@ -239,7 +251,7 @@ describe('helpers', function() { done(); }); - it('should return false if integration delay object is empty', function(done) { + it('should return false if integration delay object is empty', function (done) { const emptyIntegrationDelays = {}; const result1 = mParticle .getInstance() @@ -250,19 +262,16 @@ describe('helpers', function() { done(); }); - it('should return 0 when hashing undefined or null', function(done) { - mParticle.generateHash(undefined) - .should.equal(0); - mParticle.generateHash(null) - .should.equal(0); + it('should return 0 when hashing undefined or null', function (done) { + mParticle.generateHash(undefined).should.equal(0); + mParticle.generateHash(null).should.equal(0); (typeof mParticle.generateHash(false)).should.equal('number'); - mParticle.generateHash(false) - .should.not.equal(0); + mParticle.generateHash(false).should.not.equal(0); done(); }); - it('should generate random value', function(done) { + it('should generate random value', function (done) { let randomValue = mParticle.getInstance()._Helpers.generateUniqueId(); randomValue.should.be.ok(); window.crypto.getRandomValues = undefined; @@ -270,7 +279,7 @@ describe('helpers', function() { randomValue.should.be.ok(); //old browsers may return undefined despite //defining the getRandomValues API. - window.crypto.getRandomValues = function(a) { + window.crypto.getRandomValues = function (a) { a = undefined; return a; }; @@ -280,7 +289,7 @@ describe('helpers', function() { done(); }); - it('should create a storage name based on default mParticle storage version + apiKey if apiKey is passed in', function(done) { + it('should create a storage name based on default mParticle storage version + apiKey if apiKey is passed in', function (done) { const cookieName = mParticle .getInstance() ._Helpers.createMainStorageName(apiKey); @@ -289,7 +298,7 @@ describe('helpers', function() { done(); }); - it('should create a storage name based on default mParticle storage version if no apiKey is passed in', function(done) { + it('should create a storage name based on default mParticle storage version if no apiKey is passed in', function (done) { const cookieName = mParticle .getInstance() ._Helpers.createMainStorageName(); @@ -298,7 +307,7 @@ describe('helpers', function() { done(); }); - it('should create a product storage name based on default mParticle storage version + apiKey if apiKey is passed in', function(done) { + it('should create a product storage name based on default mParticle storage version + apiKey if apiKey is passed in', function (done) { const cookieName = mParticle .getInstance() ._Helpers.createProductStorageName(apiKey); @@ -306,7 +315,7 @@ describe('helpers', function() { done(); }); - it('should create a product storage name based on default mParticle storage version if no apiKey is passed in', function(done) { + it('should create a product storage name based on default mParticle storage version if no apiKey is passed in', function (done) { const cookieName = mParticle .getInstance() ._Helpers.createProductStorageName(); @@ -314,4 +323,4 @@ describe('helpers', function() { done(); }); -}); \ No newline at end of file +}); diff --git a/test/src/tests-identities-attributes.ts b/test/src/tests-identities-attributes.ts index 1c9fdd222..bf46218f5 100644 --- a/test/src/tests-identities-attributes.ts +++ b/test/src/tests-identities-attributes.ts @@ -1,26 +1,28 @@ import { expect } from 'chai'; import fetchMock from 'fetch-mock/esm/client'; -import { - urls, - apiKey, - testMPID, - MPConfig, -} from './config/constants'; +import { urls, apiKey, testMPID, MPConfig } from './config/constants'; import Utils from './config/utils'; import { AllUserAttributes, UserAttributesValue } from '@mparticle/web-sdk'; import { UserAttributes } from '../../src/identity-user-interfaces'; -import { Batch, CustomEvent, UserAttributeChangeEvent } from '@mparticle/event-models'; -import { IMParticleInstanceManager, SDKProduct } from '../../src/sdkRuntimeModels'; +import { + Batch, + CustomEvent, + UserAttributeChangeEvent, +} from '@mparticle/event-models'; +import { + IMParticleInstanceManager, + SDKProduct, +} from '../../src/sdkRuntimeModels'; const { waitForCondition, fetchMockSuccess, - hasIdentifyReturned, + hasIdentifyReturned, hasIdentityCallInflightReturned, findEventFromRequest, findBatch, getLocalStorage, MockForwarder, - getIdentityEvent + getIdentityEvent, } = Utils; declare global { @@ -31,40 +33,41 @@ declare global { const mParticle = window.mParticle as IMParticleInstanceManager; -const BAD_SESSION_ATTRIBUTE_KEY_AS_OBJECT = ({ +const BAD_SESSION_ATTRIBUTE_KEY_AS_OBJECT = { key: 'value', -} as unknown) as string; +} as unknown as string; -const BAD_SESSION_ATTRIBUTE_KEY_AS_ARRAY = (['key'] as unknown) as string; +const BAD_SESSION_ATTRIBUTE_KEY_AS_ARRAY = ['key'] as unknown as string; -const BAD_SESSION_ATTRIBUTE_VALUE_AS_OBJECT = ({ +const BAD_SESSION_ATTRIBUTE_VALUE_AS_OBJECT = { bad: 'bad', -} as unknown) as string; +} as unknown as string; -const BAD_USER_ATTRIBUTE_KEY_AS_OBJECT = ({ +const BAD_USER_ATTRIBUTE_KEY_AS_OBJECT = { bad: 'bad', -} as unknown) as string; +} as unknown as string; -const BAD_USER_ATTRIBUTE_KEY_AS_ARRAY = ([ +const BAD_USER_ATTRIBUTE_KEY_AS_ARRAY = [ 'bad', 'bad', 'bad', -] as unknown) as string; +] as unknown as string; -const BAD_USER_ATTRIBUTE_LIST_VALUE = (1234 as unknown) as UserAttributesValue[]; +const BAD_USER_ATTRIBUTE_LIST_VALUE = 1234 as unknown as UserAttributesValue[]; -describe('identities and attributes', function() { +describe('identities and attributes', function () { let beforeEachCallbackCalled = false; let hasBeforeEachCallbackReturned; - beforeEach(function() { + beforeEach(function () { fetchMockSuccess(urls.identify, { - mpid: testMPID, is_logged_in: false + mpid: testMPID, + is_logged_in: false, }); fetchMock.post(urls.events, 200); - mParticle.config.identityCallback = function() { + mParticle.config.identityCallback = function () { // There are some tests that need to verify that the initial init // call within the beforeEach method has completed before they // can introduce a new identityCallback for their specific assertions. @@ -76,970 +79,968 @@ describe('identities and attributes', function() { hasBeforeEachCallbackReturned = () => beforeEachCallbackCalled; }); - afterEach(function() { + afterEach(function () { beforeEachCallbackCalled = false; fetchMock.restore(); }); - it('should set user attribute', function(done) { + it('should set user attribute', function (done) { mParticle._resetForTests(MPConfig); const mockForwarder = new MockForwarder(); mockForwarder.register(window.mParticle.config); mParticle.init(apiKey, window.mParticle.config); - waitForCondition(hasIdentifyReturned) - .then(() => { - mParticle.Identity.getCurrentUser().setUserAttribute('gender', 'male'); + waitForCondition(hasIdentifyReturned).then(() => { + mParticle.Identity.getCurrentUser().setUserAttribute( + 'gender', + 'male', + ); - mParticle.logEvent('test user attributes'); + mParticle.logEvent('test user attributes'); - const event = findBatch(fetchMock.calls(), 'test user attributes'); + const event = findBatch(fetchMock.calls(), 'test user attributes'); - expect(event).to.have.property('user_attributes'); - expect(event.user_attributes).to.have.property('gender', 'male'); + expect(event).to.have.property('user_attributes'); + expect(event.user_attributes).to.have.property('gender', 'male'); - const cookies = getLocalStorage(); - expect(cookies[testMPID].ua).to.have.property('gender', 'male'); + const cookies = getLocalStorage(); + expect(cookies[testMPID].ua).to.have.property('gender', 'male'); - done(); + done(); }); }); - it('should set user attribute be case insensitive', function(done) { + it('should set user attribute be case insensitive', function (done) { mParticle._resetForTests(MPConfig); const mockForwarder = new MockForwarder(); mockForwarder.register(window.mParticle.config); mParticle.init(apiKey, window.mParticle.config); - waitForCondition(hasIdentifyReturned) - .then(() => { - mParticle.Identity.getCurrentUser().setUserAttribute('Gender', 'male'); - mParticle.Identity.getCurrentUser().setUserAttribute( - 'gender', - 'female' - ); + waitForCondition(hasIdentifyReturned).then(() => { + mParticle.Identity.getCurrentUser().setUserAttribute( + 'Gender', + 'male', + ); + mParticle.Identity.getCurrentUser().setUserAttribute( + 'gender', + 'female', + ); - mParticle.logEvent('test user attributes'); + mParticle.logEvent('test user attributes'); - const event = findBatch(fetchMock.calls(), 'test user attributes'); + const event = findBatch(fetchMock.calls(), 'test user attributes'); - let cookies = getLocalStorage(); - expect(cookies[testMPID].ua).to.have.property('gender', 'female'); + let cookies = getLocalStorage(); + expect(cookies[testMPID].ua).to.have.property('gender', 'female'); - expect(event).to.have.property('user_attributes'); - expect(event.user_attributes).to.have.property('gender', 'female'); - expect(event.user_attributes).to.not.have.property('Gender'); + expect(event).to.have.property('user_attributes'); + expect(event.user_attributes).to.have.property('gender', 'female'); + expect(event.user_attributes).to.not.have.property('Gender'); - mParticle.Identity.getCurrentUser().setUserAttribute('Gender', 'male'); + mParticle.Identity.getCurrentUser().setUserAttribute( + 'Gender', + 'male', + ); - mParticle.logEvent('test user attributes2'); - const event2 = findBatch(fetchMock.calls(), 'test user attributes2'); - expect(event2.user_attributes).to.have.property('Gender', 'male'); - expect(event2.user_attributes).to.not.have.property('gender'); + mParticle.logEvent('test user attributes2'); + const event2 = findBatch( + fetchMock.calls(), + 'test user attributes2', + ); + expect(event2.user_attributes).to.have.property('Gender', 'male'); + expect(event2.user_attributes).to.not.have.property('gender'); - cookies = getLocalStorage(); - expect(cookies[testMPID].ua).to.have.property('Gender', 'male'); + cookies = getLocalStorage(); + expect(cookies[testMPID].ua).to.have.property('Gender', 'male'); - done(); - }) + done(); + }); }); - it('should set multiple user attributes with setUserAttributes', function(done) { + it('should set multiple user attributes with setUserAttributes', function (done) { mParticle._resetForTests(MPConfig); const mockForwarder = new MockForwarder(); mockForwarder.register(window.mParticle.config); mParticle.init(apiKey, window.mParticle.config); - waitForCondition(hasIdentifyReturned) - .then(() => { - mParticle.Identity.getCurrentUser().setUserAttributes({ - gender: 'male', - age: 21, - }); + waitForCondition(hasIdentifyReturned).then(() => { + mParticle.Identity.getCurrentUser().setUserAttributes({ + gender: 'male', + age: 21, + }); - mParticle.logEvent('test user attributes'); + mParticle.logEvent('test user attributes'); - const event = findBatch(fetchMock.calls(), 'test user attributes'); + const event = findBatch(fetchMock.calls(), 'test user attributes'); - const cookies = getLocalStorage(); - expect(cookies[testMPID].ua).to.have.property('gender', 'male'); - expect(cookies[testMPID].ua).to.have.property('age', 21); + const cookies = getLocalStorage(); + expect(cookies[testMPID].ua).to.have.property('gender', 'male'); + expect(cookies[testMPID].ua).to.have.property('age', 21); - expect(event).to.have.property('user_attributes'); - expect(event.user_attributes).to.have.property('gender', 'male'); - expect(event.user_attributes).to.have.property('age', 21); + expect(event).to.have.property('user_attributes'); + expect(event.user_attributes).to.have.property('gender', 'male'); + expect(event.user_attributes).to.have.property('age', 21); - done(); - }) + done(); + }); }); - it('should remove user attribute', function(done) { + it('should remove user attribute', function (done) { mParticle._resetForTests(MPConfig); const mockForwarder = new MockForwarder(); mockForwarder.register(window.mParticle.config); mParticle.init(apiKey, window.mParticle.config); - waitForCondition(hasIdentifyReturned) - .then(() => { - mParticle.Identity.getCurrentUser().setUserAttribute('gender', 'male'); - mParticle.Identity.getCurrentUser().removeUserAttribute('gender'); + waitForCondition(hasIdentifyReturned).then(() => { + mParticle.Identity.getCurrentUser().setUserAttribute( + 'gender', + 'male', + ); + mParticle.Identity.getCurrentUser().removeUserAttribute('gender'); - mParticle.logEvent('test user attributes'); - const event = findBatch(fetchMock.calls(), 'test user attributes'); - expect(event.user_attributes).to.not.have.property('gender'); + mParticle.logEvent('test user attributes'); + const event = findBatch(fetchMock.calls(), 'test user attributes'); + expect(event.user_attributes).to.not.have.property('gender'); - const cookies = getLocalStorage(); - expect(cookies[testMPID].ua).to.not.be.ok; + const cookies = getLocalStorage(); + expect(cookies[testMPID].ua).to.not.be.ok; - done(); + done(); }); }); - it('should remove user attribute case insensitive', function(done) { + it('should remove user attribute case insensitive', function (done) { mParticle._resetForTests(MPConfig); const mockForwarder = new MockForwarder(); mockForwarder.register(window.mParticle.config); mParticle.init(apiKey, window.mParticle.config); - waitForCondition(hasIdentifyReturned) - .then(() => { - mParticle.Identity.getCurrentUser().setUserAttribute('Gender', 'male'); - mParticle.Identity.getCurrentUser().removeUserAttribute('gender'); + waitForCondition(hasIdentifyReturned).then(() => { + mParticle.Identity.getCurrentUser().setUserAttribute( + 'Gender', + 'male', + ); + mParticle.Identity.getCurrentUser().removeUserAttribute('gender'); - mParticle.logEvent('test user attributes'); + mParticle.logEvent('test user attributes'); - const event = findBatch(fetchMock.calls(), 'test user attributes'); - expect(event.user_attributes).to.not.have.property('Gender'); + const event = findBatch(fetchMock.calls(), 'test user attributes'); + expect(event.user_attributes).to.not.have.property('Gender'); - const cookies = getLocalStorage(); - expect(cookies[testMPID].ua).to.not.be.ok; + const cookies = getLocalStorage(); + expect(cookies[testMPID].ua).to.not.be.ok; - done(); + done(); }); - }); - it('should set session attribute', function(done) { - waitForCondition(hasIdentifyReturned) - .then(() => { - mParticle.setSessionAttribute('name', 'test'); + it('should set session attribute', function (done) { + waitForCondition(hasIdentifyReturned).then(() => { + mParticle.setSessionAttribute('name', 'test'); - mParticle.logEvent('test event'); + mParticle.logEvent('test event'); - const event = findEventFromRequest(fetchMock.calls(), 'test event'); + const event = findEventFromRequest(fetchMock.calls(), 'test event'); - expect(event.data.custom_attributes).to.equal(null); + expect(event.data.custom_attributes).to.equal(null); - mParticle.endSession(); - const sessionEndEvent = findEventFromRequest( - fetchMock.calls(), - 'session_end' - ); + mParticle.endSession(); + const sessionEndEvent = findEventFromRequest( + fetchMock.calls(), + 'session_end', + ); - expect(sessionEndEvent.data.custom_attributes).to.have.property( - 'name', - 'test' - ); + expect(sessionEndEvent.data.custom_attributes).to.have.property( + 'name', + 'test', + ); - done(); + done(); }); }); - it('should set session attribute case insensitive', function(done) { - waitForCondition(hasIdentifyReturned) - .then(() => { - mParticle.setSessionAttribute('name', 'test'); - mParticle.setSessionAttribute('Name', 'test1'); + it('should set session attribute case insensitive', function (done) { + waitForCondition(hasIdentifyReturned).then(() => { + mParticle.setSessionAttribute('name', 'test'); + mParticle.setSessionAttribute('Name', 'test1'); - mParticle.endSession(); + mParticle.endSession(); - const sessionEndEvent = findEventFromRequest( - fetchMock.calls(), - 'session_end' - ); + const sessionEndEvent = findEventFromRequest( + fetchMock.calls(), + 'session_end', + ); - expect(sessionEndEvent.data.custom_attributes).to.have.property( - 'name', - 'test1' - ); - expect(sessionEndEvent.data.custom_attributes).to.not.have.property( - 'Name' - ); + expect(sessionEndEvent.data.custom_attributes).to.have.property( + 'name', + 'test1', + ); + expect(sessionEndEvent.data.custom_attributes).to.not.have.property( + 'Name', + ); - done(); - }) + done(); + }); }); - it("should not set a session attribute's key as an object or array)", function(done) { - waitForCondition(hasIdentifyReturned) - .then(() => { - mParticle.setSessionAttribute( - BAD_SESSION_ATTRIBUTE_KEY_AS_OBJECT, - 'test' - ); - mParticle.endSession(); - const sessionEndEvent1 = findEventFromRequest( - fetchMock.calls(), - 'session_end' - ); + it("should not set a session attribute's key as an object or array)", function (done) { + waitForCondition(hasIdentifyReturned).then(() => { + mParticle.setSessionAttribute( + BAD_SESSION_ATTRIBUTE_KEY_AS_OBJECT, + 'test', + ); + mParticle.endSession(); + const sessionEndEvent1 = findEventFromRequest( + fetchMock.calls(), + 'session_end', + ); - mParticle.startNewSession(); - fetchMock.resetHistory(); - mParticle.setSessionAttribute( - BAD_SESSION_ATTRIBUTE_KEY_AS_ARRAY, - 'test' - ); - mParticle.endSession(); - const sessionEndEvent2 = findEventFromRequest( - fetchMock.calls(), - 'session_end' - ); + mParticle.startNewSession(); + fetchMock.resetHistory(); + mParticle.setSessionAttribute( + BAD_SESSION_ATTRIBUTE_KEY_AS_ARRAY, + 'test', + ); + mParticle.endSession(); + const sessionEndEvent2 = findEventFromRequest( + fetchMock.calls(), + 'session_end', + ); - expect( - Object.keys(sessionEndEvent1.data.custom_attributes).length - ).to.equal(0); - expect( - Object.keys(sessionEndEvent2.data.custom_attributes).length - ).to.equal(0); + expect( + Object.keys(sessionEndEvent1.data.custom_attributes).length, + ).to.equal(0); + expect( + Object.keys(sessionEndEvent2.data.custom_attributes).length, + ).to.equal(0); - done(); - }) + done(); + }); }); - it('should remove session attributes when session ends', function(done) { - waitForCondition(hasIdentifyReturned) - .then(() => { - mParticle.startNewSession(); - mParticle.setSessionAttribute('name', 'test'); - mParticle.endSession(); + it('should remove session attributes when session ends', function (done) { + waitForCondition(hasIdentifyReturned).then(() => { + mParticle.startNewSession(); + mParticle.setSessionAttribute('name', 'test'); + mParticle.endSession(); - fetchMock.resetHistory(); - mParticle.startNewSession(); - mParticle.endSession(); + fetchMock.resetHistory(); + mParticle.startNewSession(); + mParticle.endSession(); - const sessionEndEvent = findEventFromRequest( - fetchMock.calls(), - 'session_end' - ); + const sessionEndEvent = findEventFromRequest( + fetchMock.calls(), + 'session_end', + ); - expect(sessionEndEvent.data.custom_attributes).to.not.have.property( - 'name' - ); + expect(sessionEndEvent.data.custom_attributes).to.not.have.property( + 'name', + ); - done(); - }) + done(); + }); }); - it('should set and log position', function(done) { - waitForCondition(hasIdentifyReturned) - .then(() => { - mParticle.setPosition(34.134103, -118.321694); - mParticle.logEvent('Test Event'); + it('should set and log position', function (done) { + waitForCondition(hasIdentifyReturned).then(() => { + mParticle.setPosition(34.134103, -118.321694); + mParticle.logEvent('Test Event'); - const event = findEventFromRequest(fetchMock.calls(), 'Test Event'); + const event = findEventFromRequest(fetchMock.calls(), 'Test Event'); - expect(event.data).to.have.property('location'); - expect(event.data.location).to.have.property('latitude', 34.134103); - expect(event.data.location).to.have.property('longitude', -118.321694); + expect(event.data).to.have.property('location'); + expect(event.data.location).to.have.property('latitude', 34.134103); + expect(event.data.location).to.have.property( + 'longitude', + -118.321694, + ); - done(); - }) + done(); + }); }); - it('should set user tag', function(done) { - waitForCondition(hasIdentifyReturned) - .then(() => { - mParticle.Identity.getCurrentUser().setUserTag('test'); + it('should set user tag', function (done) { + waitForCondition(hasIdentifyReturned).then(() => { + mParticle.Identity.getCurrentUser().setUserTag('test'); - mParticle.logEvent('Test Event'); + mParticle.logEvent('Test Event'); - const event = findBatch(fetchMock.calls(), 'Test Event'); + const event = findBatch(fetchMock.calls(), 'Test Event'); - expect(event).to.have.property('user_attributes'); - expect(event.user_attributes).to.have.property('test', null); + expect(event).to.have.property('user_attributes'); + expect(event.user_attributes).to.have.property('test', null); - const cookies = getLocalStorage(); - expect(cookies[testMPID].ua).to.have.property('test'); + const cookies = getLocalStorage(); + expect(cookies[testMPID].ua).to.have.property('test'); - done(); - }) + done(); + }); }); - it('should set user tag case insensitive', function(done) { - waitForCondition(hasIdentifyReturned) - .then(() => { - mParticle.Identity.getCurrentUser().setUserTag('Test'); - mParticle.Identity.getCurrentUser().setUserTag('test'); + it('should set user tag case insensitive', function (done) { + waitForCondition(hasIdentifyReturned).then(() => { + mParticle.Identity.getCurrentUser().setUserTag('Test'); + mParticle.Identity.getCurrentUser().setUserTag('test'); - mParticle.logEvent('Test Event'); + mParticle.logEvent('Test Event'); - const event = findBatch(fetchMock.calls(), 'Test Event'); + const event = findBatch(fetchMock.calls(), 'Test Event'); - expect(event).to.have.property('user_attributes'); - expect(event.user_attributes).to.not.have.property('Test'); - expect(event.user_attributes).to.have.property('test'); + expect(event).to.have.property('user_attributes'); + expect(event.user_attributes).to.not.have.property('Test'); + expect(event.user_attributes).to.have.property('test'); - const cookies = getLocalStorage(); - expect(cookies[testMPID].ua).to.have.property('test'); + const cookies = getLocalStorage(); + expect(cookies[testMPID].ua).to.have.property('test'); - done(); - }) + done(); + }); }); - it('should remove user tag', function(done) { - waitForCondition(hasIdentifyReturned) - .then(() => { - mParticle.Identity.getCurrentUser().setUserTag('test'); - mParticle.Identity.getCurrentUser().removeUserTag('test'); + it('should remove user tag', function (done) { + waitForCondition(hasIdentifyReturned).then(() => { + mParticle.Identity.getCurrentUser().setUserTag('test'); + mParticle.Identity.getCurrentUser().removeUserTag('test'); - mParticle.logEvent('test event'); + mParticle.logEvent('test event'); - const event = findBatch(fetchMock.calls(), 'test event'); + const event = findBatch(fetchMock.calls(), 'test event'); - expect(event).to.have.property('user_attributes'); - expect(event.user_attributes).to.not.have.property('test'); + expect(event).to.have.property('user_attributes'); + expect(event.user_attributes).to.not.have.property('test'); - const cookies = getLocalStorage(); - expect(cookies[testMPID].ua).to.not.be.ok; + const cookies = getLocalStorage(); + expect(cookies[testMPID].ua).to.not.be.ok; - done(); + done(); }); }); - it('should remove user tag case insensitive', function(done) { - waitForCondition(hasIdentifyReturned) - .then(() => { - mParticle.Identity.getCurrentUser().setUserTag('Test'); - mParticle.Identity.getCurrentUser().removeUserTag('test'); + it('should remove user tag case insensitive', function (done) { + waitForCondition(hasIdentifyReturned).then(() => { + mParticle.Identity.getCurrentUser().setUserTag('Test'); + mParticle.Identity.getCurrentUser().removeUserTag('test'); - mParticle.logEvent('test event'); + mParticle.logEvent('test event'); - const event = findBatch(fetchMock.calls(), 'test event'); + const event = findBatch(fetchMock.calls(), 'test event'); - expect(event).to.have.property('user_attributes'); - expect(event.user_attributes).to.not.have.property('Test'); + expect(event).to.have.property('user_attributes'); + expect(event.user_attributes).to.not.have.property('Test'); - const cookies = getLocalStorage(); - expect(cookies[testMPID].ua).to.not.be.ok; + const cookies = getLocalStorage(); + expect(cookies[testMPID].ua).to.not.be.ok; - done(); + done(); }); }); - it('should set user attribute list', function(done) { + it('should set user attribute list', function (done) { mParticle._resetForTests(MPConfig); mParticle.init(apiKey, window.mParticle.config); - waitForCondition(hasIdentifyReturned) - .then(() => { - mParticle.Identity.getCurrentUser().setUserAttributeList('numbers', [ - 1, - 2, - 3, - 4, - 5, - ]); + waitForCondition(hasIdentifyReturned).then(() => { + mParticle.Identity.getCurrentUser().setUserAttributeList( + 'numbers', + [1, 2, 3, 4, 5], + ); - mParticle.logEvent('test user attributes'); + mParticle.logEvent('test user attributes'); - const event = findBatch(fetchMock.calls(), 'test user attributes'); + const event = findBatch(fetchMock.calls(), 'test user attributes'); - expect(event).to.have.property('user_attributes'); - expect(event.user_attributes) - .to.have.property('numbers') - .to.deep.equal([1, 2, 3, 4, 5]); + expect(event).to.have.property('user_attributes'); + expect(event.user_attributes) + .to.have.property('numbers') + .to.deep.equal([1, 2, 3, 4, 5]); - const cookies = getLocalStorage(); - expect(cookies[testMPID].ua.numbers.length).to.equal(5); + const cookies = getLocalStorage(); + expect(cookies[testMPID].ua.numbers.length).to.equal(5); - done(); - }) + done(); + }); }); - it('should set user attribute list case insensitive', function(done) { + it('should set user attribute list case insensitive', function (done) { mParticle._resetForTests(MPConfig); - + mParticle.init(apiKey, window.mParticle.config); - waitForCondition(hasIdentifyReturned) - .then(() => { - mParticle.Identity.getCurrentUser().setUserAttributeList('numbers', [ - 1, - 2, - 3, - 4, - 5, - ]); - mParticle.Identity.getCurrentUser().setUserAttributeList('Numbers', [ - 1, - 2, - 3, - 4, - 5, - 6, - ]); - - mParticle.logEvent('test user attributes'); - - const event = findBatch(fetchMock.calls(), 'test user attributes'); - const cookies = getLocalStorage(); - - expect(event).to.have.property('user_attributes'); - expect(event.user_attributes) - .to.have.property('Numbers') - .to.deep.equal([1, 2, 3, 4, 5, 6]); - expect(event.user_attributes).to.not.have.property('numbers'); - expect(cookies[testMPID].ua.Numbers.length).to.equal(6); - - mParticle.Identity.getCurrentUser().setUserAttributeList('numbers', [ - 1, - 2, - 3, - 4, - 5, - ]); - - mParticle.logEvent('test user attributes2'); - const event2 = findBatch(fetchMock.calls(), 'test user attributes2'); - const cookies3 = getLocalStorage(); - - expect(event2.user_attributes) - .to.have.property('numbers') - .to.deep.equal([1, 2, 3, 4, 5]); - expect(event2.user_attributes).to.not.have.property('Numbers'); - expect(cookies3[testMPID].ua.numbers.length).to.equal(5); - - done(); - }) + waitForCondition(hasIdentifyReturned).then(() => { + mParticle.Identity.getCurrentUser().setUserAttributeList( + 'numbers', + [1, 2, 3, 4, 5], + ); + mParticle.Identity.getCurrentUser().setUserAttributeList( + 'Numbers', + [1, 2, 3, 4, 5, 6], + ); + + mParticle.logEvent('test user attributes'); + + const event = findBatch(fetchMock.calls(), 'test user attributes'); + const cookies = getLocalStorage(); + + expect(event).to.have.property('user_attributes'); + expect(event.user_attributes) + .to.have.property('Numbers') + .to.deep.equal([1, 2, 3, 4, 5, 6]); + expect(event.user_attributes).to.not.have.property('numbers'); + expect(cookies[testMPID].ua.Numbers.length).to.equal(6); + + mParticle.Identity.getCurrentUser().setUserAttributeList( + 'numbers', + [1, 2, 3, 4, 5], + ); + + mParticle.logEvent('test user attributes2'); + const event2 = findBatch( + fetchMock.calls(), + 'test user attributes2', + ); + const cookies3 = getLocalStorage(); + + expect(event2.user_attributes) + .to.have.property('numbers') + .to.deep.equal([1, 2, 3, 4, 5]); + expect(event2.user_attributes).to.not.have.property('Numbers'); + expect(cookies3[testMPID].ua.numbers.length).to.equal(5); + + done(); + }); }); - it('should make a copy of user attribute list', function(done) { + it('should make a copy of user attribute list', function (done) { const list = [1, 2, 3, 4, 5]; mParticle._resetForTests(MPConfig); mParticle.init(apiKey, window.mParticle.config); - waitForCondition(hasIdentifyReturned) - .then(() => { - mParticle.Identity.getCurrentUser().setUserAttributeList( - 'numbers', - list - ); + waitForCondition(hasIdentifyReturned).then(() => { + mParticle.Identity.getCurrentUser().setUserAttributeList( + 'numbers', + list, + ); - list.push(6); + list.push(6); - mParticle.logEvent('test user attributes'); + mParticle.logEvent('test user attributes'); - const event = findBatch(fetchMock.calls(), 'test user attributes'); + const event = findBatch(fetchMock.calls(), 'test user attributes'); - const cookies = getLocalStorage(); - expect(cookies[testMPID].ua.numbers.length).to.equal(5); + const cookies = getLocalStorage(); + expect(cookies[testMPID].ua.numbers.length).to.equal(5); - expect(event).to.have.property('user_attributes'); - expect(event.user_attributes) - .to.have.property('numbers') - .with.lengthOf(5); + expect(event).to.have.property('user_attributes'); + expect(event.user_attributes) + .to.have.property('numbers') + .with.lengthOf(5); - done(); - }) + done(); + }); }); - it('should remove all user attributes', function(done) { + it('should remove all user attributes', function (done) { mParticle._resetForTests(MPConfig); mParticle.init(apiKey, window.mParticle.config); - waitForCondition(hasIdentifyReturned) - .then(() => { - mParticle.Identity.getCurrentUser().setUserAttributeList('numbers', [ - 1, - 2, - 3, - 4, - 5, - ]); - mParticle.Identity.getCurrentUser().removeAllUserAttributes(); + waitForCondition(hasIdentifyReturned).then(() => { + mParticle.Identity.getCurrentUser().setUserAttributeList( + 'numbers', + [1, 2, 3, 4, 5], + ); + mParticle.Identity.getCurrentUser().removeAllUserAttributes(); - mParticle.logEvent('test user attributes'); + mParticle.logEvent('test user attributes'); - const event = findBatch(fetchMock.calls(), 'test user attributes'); - const cookies = getLocalStorage(); + const event = findBatch(fetchMock.calls(), 'test user attributes'); + const cookies = getLocalStorage(); - expect(event).to.have.property('user_attributes'); - expect(event.user_attributes).to.deep.equal({}); - expect(cookies[testMPID].ua).to.not.be.ok; + expect(event).to.have.property('user_attributes'); + expect(event.user_attributes).to.deep.equal({}); + expect(cookies[testMPID].ua).to.not.be.ok; - done(); - }) + done(); + }); }); - it('should get user attribute lists', function(done) { + it('should get user attribute lists', function (done) { mParticle._resetForTests(MPConfig); mParticle.init(apiKey, window.mParticle.config); - waitForCondition(hasIdentifyReturned) - .then(() => { - - mParticle.Identity.getCurrentUser().setUserAttribute('gender', 'male'); - mParticle.Identity.getCurrentUser().setUserAttributeList('numbers', [ - 1, - 2, - 3, - 4, - 5, - ]); + waitForCondition(hasIdentifyReturned).then(() => { + mParticle.Identity.getCurrentUser().setUserAttribute( + 'gender', + 'male', + ); + mParticle.Identity.getCurrentUser().setUserAttributeList( + 'numbers', + [1, 2, 3, 4, 5], + ); - const userAttributes = mParticle.Identity.getCurrentUser().getUserAttributesLists(); + const userAttributes = + mParticle.Identity.getCurrentUser().getUserAttributesLists(); - expect(userAttributes).to.have.property('numbers'); - expect(userAttributes).to.not.have.property('gender'); + expect(userAttributes).to.have.property('numbers'); + expect(userAttributes).to.not.have.property('gender'); - done(); - }) + done(); + }); }); - it('should copy when calling get user attribute lists', function(done) { + it('should copy when calling get user attribute lists', function (done) { mParticle._resetForTests(MPConfig); mParticle.init(apiKey, window.mParticle.config); - waitForCondition(hasIdentifyReturned) - .then(() => { - mParticle.Identity.getCurrentUser().setUserAttribute('gender', 'male'); - mParticle.Identity.getCurrentUser().setUserAttributeList('numbers', [ - 1, - 2, - 3, - 4, - 5, - ]); + waitForCondition(hasIdentifyReturned).then(() => { + mParticle.Identity.getCurrentUser().setUserAttribute( + 'gender', + 'male', + ); + mParticle.Identity.getCurrentUser().setUserAttributeList( + 'numbers', + [1, 2, 3, 4, 5], + ); - const userAttributes = mParticle.Identity.getCurrentUser().getUserAttributesLists(); + const userAttributes = + mParticle.Identity.getCurrentUser().getUserAttributesLists(); - userAttributes['numbers'].push(6); + userAttributes['numbers'].push(6); - const userAttributes1 = mParticle.Identity.getCurrentUser().getUserAttributesLists(); - expect(userAttributes1['numbers']).to.have.lengthOf(5); + const userAttributes1 = + mParticle.Identity.getCurrentUser().getUserAttributesLists(); + expect(userAttributes1['numbers']).to.have.lengthOf(5); - done(); - }) + done(); + }); }); - it('should copy when calling get user attributes', function(done) { + it('should copy when calling get user attributes', function (done) { mParticle._resetForTests(MPConfig); mParticle.init(apiKey, window.mParticle.config); - waitForCondition(hasIdentifyReturned) - .then(() => { - mParticle.Identity.getCurrentUser().setUserAttribute('gender', 'male'); - mParticle.Identity.getCurrentUser().setUserAttributeList('numbers', [ - 1, - 2, - 3, - 4, - 5, - ]); + waitForCondition(hasIdentifyReturned).then(() => { + mParticle.Identity.getCurrentUser().setUserAttribute( + 'gender', + 'male', + ); + mParticle.Identity.getCurrentUser().setUserAttributeList( + 'numbers', + [1, 2, 3, 4, 5], + ); - const userAttributes = mParticle.Identity.getCurrentUser().getAllUserAttributes(); + const userAttributes = + mParticle.Identity.getCurrentUser().getAllUserAttributes(); - userAttributes.blah = 'test'; - userAttributes['numbers'].push(6); + userAttributes.blah = 'test'; + userAttributes['numbers'].push(6); - const userAttributes1 = mParticle.Identity.getCurrentUser().getAllUserAttributes(); + const userAttributes1 = + mParticle.Identity.getCurrentUser().getAllUserAttributes(); - expect(userAttributes1['numbers']).to.have.lengthOf(5); - expect(userAttributes1).to.not.have.property('blah'); + expect(userAttributes1['numbers']).to.have.lengthOf(5); + expect(userAttributes1).to.not.have.property('blah'); - done(); - }) + done(); + }); }); - it('should get all user attributes', function(done) { + it('should get all user attributes', function (done) { mParticle._resetForTests(MPConfig); mParticle.init(apiKey, window.mParticle.config); - waitForCondition(hasIdentifyReturned) - .then(() => { - mParticle.Identity.getCurrentUser().setUserAttribute('test', '123'); - mParticle.Identity.getCurrentUser().setUserAttribute( - 'another test', - 'blah' - ); + waitForCondition(hasIdentifyReturned).then(() => { + mParticle.Identity.getCurrentUser().setUserAttribute('test', '123'); + mParticle.Identity.getCurrentUser().setUserAttribute( + 'another test', + 'blah', + ); - const attrs = mParticle.Identity.getCurrentUser().getAllUserAttributes(); + const attrs = + mParticle.Identity.getCurrentUser().getAllUserAttributes(); - expect(attrs).to.have.property('test', '123'); - expect(attrs).to.have.property('another test', 'blah'); + expect(attrs).to.have.property('test', '123'); + expect(attrs).to.have.property('another test', 'blah'); - done(); - }) + done(); + }); }); - it('should not set user attribute list if value is not array', function(done) { + it('should not set user attribute list if value is not array', function (done) { mParticle._resetForTests(MPConfig); mParticle.init(apiKey, window.mParticle.config); - waitForCondition(hasIdentifyReturned) - .then(() => { - mParticle.Identity.getCurrentUser().setUserAttributeList( - 'mykey', - BAD_USER_ATTRIBUTE_LIST_VALUE - ); + waitForCondition(hasIdentifyReturned).then(() => { + mParticle.Identity.getCurrentUser().setUserAttributeList( + 'mykey', + BAD_USER_ATTRIBUTE_LIST_VALUE, + ); - const attrs = mParticle.Identity.getCurrentUser().getAllUserAttributes(); + const attrs = + mParticle.Identity.getCurrentUser().getAllUserAttributes(); - expect(attrs).to.not.have.property('mykey'); + expect(attrs).to.not.have.property('mykey'); - done(); - }) + done(); + }); }); - it('should not set bad session attribute value', function(done) { - waitForCondition(hasIdentifyReturned) - .then(() => { - mParticle.setSessionAttribute( - 'name', - BAD_SESSION_ATTRIBUTE_VALUE_AS_OBJECT - ); + it('should not set bad session attribute value', function (done) { + waitForCondition(hasIdentifyReturned).then(() => { + mParticle.setSessionAttribute( + 'name', + BAD_SESSION_ATTRIBUTE_VALUE_AS_OBJECT, + ); - mParticle.endSession(); + mParticle.endSession(); - const sessionEndEvent = findEventFromRequest( - fetchMock.calls(), - 'session_end' - ); + const sessionEndEvent = findEventFromRequest( + fetchMock.calls(), + 'session_end', + ); - expect(sessionEndEvent.data.custom_attributes).to.not.have.property( - 'name' - ); + expect(sessionEndEvent.data.custom_attributes).to.not.have.property( + 'name', + ); - done(); - }) + done(); + }); }); - it('should not set a bad user attribute key or value', function(done) { - waitForCondition(hasIdentifyReturned) - .then(() => { - mParticle.Identity.getCurrentUser().setUserAttribute('gender', { - bad: 'bad', - }); - mParticle.logEvent('test bad user attributes1'); - const event1 = findBatch( - fetchMock.calls(), - 'test bad user attributes1' - ); + it('should not set a bad user attribute key or value', function (done) { + waitForCondition(hasIdentifyReturned).then(() => { + mParticle.Identity.getCurrentUser().setUserAttribute('gender', { + bad: 'bad', + }); + mParticle.logEvent('test bad user attributes1'); + const event1 = findBatch( + fetchMock.calls(), + 'test bad user attributes1', + ); - mParticle.Identity.getCurrentUser().setUserAttribute('gender', [ - 'bad', - 'bad', - 'bad', - ]); - mParticle.logEvent('test bad user attributes2'); - const event2 = findBatch( - fetchMock.calls(), - 'test bad user attributes2' - ); + mParticle.Identity.getCurrentUser().setUserAttribute('gender', [ + 'bad', + 'bad', + 'bad', + ]); + mParticle.logEvent('test bad user attributes2'); + const event2 = findBatch( + fetchMock.calls(), + 'test bad user attributes2', + ); - mParticle.Identity.getCurrentUser().setUserAttribute( - BAD_USER_ATTRIBUTE_KEY_AS_OBJECT, - 'male' - ); - mParticle.logEvent('test bad user attributes3'); - const event3 = findBatch( - fetchMock.calls(), - 'test bad user attributes3' - ); + mParticle.Identity.getCurrentUser().setUserAttribute( + BAD_USER_ATTRIBUTE_KEY_AS_OBJECT, + 'male', + ); + mParticle.logEvent('test bad user attributes3'); + const event3 = findBatch( + fetchMock.calls(), + 'test bad user attributes3', + ); - mParticle.Identity.getCurrentUser().setUserAttribute( - BAD_USER_ATTRIBUTE_KEY_AS_ARRAY, - 'female' - ); - mParticle.logEvent('test bad user attributes4'); - const event4 = findBatch( - fetchMock.calls(), - 'test bad user attributes4' - ); + mParticle.Identity.getCurrentUser().setUserAttribute( + BAD_USER_ATTRIBUTE_KEY_AS_ARRAY, + 'female', + ); + mParticle.logEvent('test bad user attributes4'); + const event4 = findBatch( + fetchMock.calls(), + 'test bad user attributes4', + ); - mParticle.Identity.getCurrentUser().setUserAttribute(null, 'female'); - mParticle.logEvent('test bad user attributes5'); - const event5 = findBatch( - fetchMock.calls(), - 'test bad user attributes5' - ); + mParticle.Identity.getCurrentUser().setUserAttribute( + null, + 'female', + ); + mParticle.logEvent('test bad user attributes5'); + const event5 = findBatch( + fetchMock.calls(), + 'test bad user attributes5', + ); - mParticle.Identity.getCurrentUser().setUserAttribute( - undefined, - 'female' - ); - mParticle.logEvent('test bad user attributes6'); - const event6 = findBatch( - fetchMock.calls(), - 'test bad user attributes6' - ); + mParticle.Identity.getCurrentUser().setUserAttribute( + undefined, + 'female', + ); + mParticle.logEvent('test bad user attributes6'); + const event6 = findBatch( + fetchMock.calls(), + 'test bad user attributes6', + ); - expect(event1).to.have.property('user_attributes'); - expect(event1.user_attributes).to.not.have.property('gender'); + expect(event1).to.have.property('user_attributes'); + expect(event1.user_attributes).to.not.have.property('gender'); - expect(event2).to.have.property('user_attributes'); - expect(event2.user_attributes).to.not.have.property('gender'); + expect(event2).to.have.property('user_attributes'); + expect(event2.user_attributes).to.not.have.property('gender'); - expect(event3).to.have.property('user_attributes'); - expect(event3.user_attributes).to.not.have.property('gender'); + expect(event3).to.have.property('user_attributes'); + expect(event3.user_attributes).to.not.have.property('gender'); - expect(event4).to.have.property('user_attributes'); - expect(event4.user_attributes).to.not.have.property('gender'); + expect(event4).to.have.property('user_attributes'); + expect(event4.user_attributes).to.not.have.property('gender'); - expect(event5).to.have.property('user_attributes'); - expect(event5.user_attributes).to.not.have.property('gender'); + expect(event5).to.have.property('user_attributes'); + expect(event5.user_attributes).to.not.have.property('gender'); - expect(event6).to.have.property('user_attributes'); - expect(event6.user_attributes).to.not.have.property('gender'); + expect(event6).to.have.property('user_attributes'); + expect(event6.user_attributes).to.not.have.property('gender'); - done(); - }) - }); + done(); + }); + }); - it('should get cart products', function(done) { - const product1: SDKProduct = mParticle.eCommerce.createProduct('iPhone', 'SKU1', 1, 1); - const product2: SDKProduct = mParticle.eCommerce.createProduct('Android', 'SKU2', 1, 1); + it('should get cart products', function (done) { + const product1: SDKProduct = mParticle.eCommerce.createProduct( + 'iPhone', + 'SKU1', + 1, + 1, + ); + const product2: SDKProduct = mParticle.eCommerce.createProduct( + 'Android', + 'SKU2', + 1, + 1, + ); - waitForCondition(hasIdentifyReturned) - .then(() => { - mParticle.eCommerce.Cart.add([product1, product2], null); + waitForCondition(hasIdentifyReturned).then(() => { + mParticle.eCommerce.Cart.add([product1, product2], null); - const cartProducts = mParticle.Identity.getCurrentUser() - .getCart() - .getCartProducts(); + const cartProducts = mParticle.Identity.getCurrentUser() + .getCart() + .getCartProducts(); - expect(cartProducts.length).to.equal(2); - expect(JSON.stringify(cartProducts[0])).to.equal( - JSON.stringify(product1) - ); - expect(JSON.stringify(cartProducts[1])).to.equal( - JSON.stringify(product2) - ); + expect(cartProducts.length).to.equal(2); + expect(JSON.stringify(cartProducts[0])).to.equal( + JSON.stringify(product1), + ); + expect(JSON.stringify(cartProducts[1])).to.equal( + JSON.stringify(product2), + ); - done(); - }) + done(); + }); }); - it('should send user attribute change requests when setting new attributes', function(done) { + it('should send user attribute change requests when setting new attributes', function (done) { mParticle._resetForTests(MPConfig); mParticle.init(apiKey, window.mParticle.config); - waitForCondition(hasIdentifyReturned) - .then(() => { - // set a new attribute, age - fetchMock.resetHistory(); - mParticle.Identity.getCurrentUser().setUserAttribute('age', '25'); - - // `fetchMock.lastOptions().body` is technically an object, but - // our server actually returns this as a string. - // In this case, we are going to parse the string and coerce it - // into an AllUserAttributes object so we can have type safety - // for the remainder of this test and to ensure that the - // exracted event data conforms to a UserAttributeChangeEvent - let body: AllUserAttributes = JSON.parse( - `${fetchMock.lastOptions().body}` - ); - expect(body.user_attributes).to.have.property('age', '25'); - - let event: UserAttributeChangeEvent = body.events[0]; - expect(event).to.be.ok; - expect(event.event_type).to.equal('user_attribute_change'); - expect(event.data.new).to.equal('25'); - expect(event.data.old === null).to.equal(true); - expect(event.data.user_attribute_name).to.equal('age'); - expect(event.data.deleted).to.equal(false); - expect(event.data.is_new_attribute).to.equal(true); - - // change age attribute - fetchMock.resetHistory(); - mParticle.Identity.getCurrentUser().setUserAttribute('age', '30'); - body = JSON.parse(`${fetchMock.lastOptions().body}`); - expect(body.user_attributes).to.have.property('age', '30'); - event = body.events[0]; - expect(event.event_type).to.equal('user_attribute_change'); - expect(event.data.new).to.equal('30'); - expect(event.data.old).to.equal('25'); - expect(event.data.user_attribute_name).to.equal('age'); - expect(event.data.deleted).to.equal(false); - expect(event.data.is_new_attribute).to.equal(false); - - // removes age attribute - fetchMock.resetHistory(); - mParticle.Identity.getCurrentUser().removeUserAttribute('age'); - body = JSON.parse(`${fetchMock.lastOptions().body}`); - expect(body.user_attributes).to.not.have.property('age'); - event = body.events[0]; - expect(event.event_type).to.equal('user_attribute_change'); - expect(event.data.new === null).to.equal(true); - expect(event.data.old).to.equal('30'); - expect(event.data.user_attribute_name).to.equal('age'); - expect(event.data.deleted).to.equal(true); - expect(event.data.is_new_attribute).to.equal(false); - - // set a user attribute list - fetchMock.resetHistory(); - - mParticle.Identity.getCurrentUser().setUserAttributeList('age', [ - 'test1', - 'test2', - ]); - body = JSON.parse(`${fetchMock.lastOptions().body}`); - - expect(body.user_attributes['age'][0]).to.equal('test1'); - expect(body.user_attributes['age'][1]).to.equal('test2'); - event = body.events[0]; - expect(event.event_type).to.equal('user_attribute_change'); - let obj = { - test1: true, - test2: true, - }; - - // In this case, the expectation is that the user attributes are an array of strings - (event.data.new as string[]).forEach(function(userAttr) { - expect(obj[userAttr]).to.equal(true); - }); - expect(event.data.old === null).to.equal(true); - expect(event.data.user_attribute_name).to.equal('age'); - expect(event.data.deleted).to.equal(false); - expect(event.data.is_new_attribute).to.equal(true); - - // changes ordering of above attribute list - fetchMock.resetHistory(); + waitForCondition(hasIdentifyReturned).then(() => { + // set a new attribute, age + fetchMock.resetHistory(); + mParticle.Identity.getCurrentUser().setUserAttribute('age', '25'); + + // `fetchMock.lastOptions().body` is technically an object, but + // our server actually returns this as a string. + // In this case, we are going to parse the string and coerce it + // into an AllUserAttributes object so we can have type safety + // for the remainder of this test and to ensure that the + // exracted event data conforms to a UserAttributeChangeEvent + let body: AllUserAttributes = JSON.parse( + `${fetchMock.lastOptions().body}`, + ); + expect(body.user_attributes).to.have.property('age', '25'); + + let event: UserAttributeChangeEvent = body.events[0]; + expect(event).to.be.ok; + expect(event.event_type).to.equal('user_attribute_change'); + expect(event.data.new).to.equal('25'); + expect(event.data.old === null).to.equal(true); + expect(event.data.user_attribute_name).to.equal('age'); + expect(event.data.deleted).to.equal(false); + expect(event.data.is_new_attribute).to.equal(true); + + // change age attribute + fetchMock.resetHistory(); + mParticle.Identity.getCurrentUser().setUserAttribute('age', '30'); + body = JSON.parse(`${fetchMock.lastOptions().body}`); + expect(body.user_attributes).to.have.property('age', '30'); + event = body.events[0]; + expect(event.event_type).to.equal('user_attribute_change'); + expect(event.data.new).to.equal('30'); + expect(event.data.old).to.equal('25'); + expect(event.data.user_attribute_name).to.equal('age'); + expect(event.data.deleted).to.equal(false); + expect(event.data.is_new_attribute).to.equal(false); + + // removes age attribute + fetchMock.resetHistory(); + mParticle.Identity.getCurrentUser().removeUserAttribute('age'); + body = JSON.parse(`${fetchMock.lastOptions().body}`); + expect(body.user_attributes).to.not.have.property('age'); + event = body.events[0]; + expect(event.event_type).to.equal('user_attribute_change'); + expect(event.data.new === null).to.equal(true); + expect(event.data.old).to.equal('30'); + expect(event.data.user_attribute_name).to.equal('age'); + expect(event.data.deleted).to.equal(true); + expect(event.data.is_new_attribute).to.equal(false); + + // set a user attribute list + fetchMock.resetHistory(); + + mParticle.Identity.getCurrentUser().setUserAttributeList('age', [ + 'test1', + 'test2', + ]); + body = JSON.parse(`${fetchMock.lastOptions().body}`); + + expect(body.user_attributes['age'][0]).to.equal('test1'); + expect(body.user_attributes['age'][1]).to.equal('test2'); + event = body.events[0]; + expect(event.event_type).to.equal('user_attribute_change'); + let obj = { + test1: true, + test2: true, + }; + + // In this case, the expectation is that the user attributes are an array of strings + (event.data.new as string[]).forEach(function (userAttr) { + expect(obj[userAttr]).to.equal(true); + }); + expect(event.data.old === null).to.equal(true); + expect(event.data.user_attribute_name).to.equal('age'); + expect(event.data.deleted).to.equal(false); + expect(event.data.is_new_attribute).to.equal(true); + + // changes ordering of above attribute list + fetchMock.resetHistory(); + + mParticle.Identity.getCurrentUser().setUserAttributeList('age', [ + 'test2', + 'test1', + ]); + body = JSON.parse(`${fetchMock.lastOptions().body}`); + expect(body.user_attributes['age'][0]).to.equal('test2'); + expect(body.user_attributes['age'][1]).to.equal('test1'); + + event = JSON.parse(`${fetchMock.lastOptions().body}`).events[0]; + expect(event.event_type).to.equal('user_attribute_change'); + obj = { + test1: true, + test2: true, + }; + + // In this case, the expectation is that the user attributes are an array of strings + (event.data.new as string[]).forEach(function (userAttr) { + expect(obj[userAttr]).to.equal(true); + }); - mParticle.Identity.getCurrentUser().setUserAttributeList('age', [ - 'test2', - 'test1', - ]); - body = JSON.parse(`${fetchMock.lastOptions().body}`); - expect(body.user_attributes['age'][0]).to.equal('test2'); - expect(body.user_attributes['age'][1]).to.equal('test1'); - - event = JSON.parse(`${fetchMock.lastOptions().body}`).events[0]; - expect(event.event_type).to.equal('user_attribute_change'); - obj = { - test1: true, - test2: true, - }; + expect(event.data.old[0] === 'test1').to.equal(true); + expect(event.data.old[1] === 'test2').to.equal(true); + expect(event.data.user_attribute_name).to.equal('age'); + expect(event.data.deleted).to.equal(false); + expect(event.data.is_new_attribute).to.equal(false); - // In this case, the expectation is that the user attributes are an array of strings - (event.data.new as string[]).forEach(function(userAttr) { - expect(obj[userAttr]).to.equal(true); + delete window.mParticle.config.flags; + done(); }); - - expect(event.data.old[0] === 'test1').to.equal(true); - expect(event.data.old[1] === 'test2').to.equal(true); - expect(event.data.user_attribute_name).to.equal('age'); - expect(event.data.deleted).to.equal(false); - expect(event.data.is_new_attribute).to.equal(false); - - delete window.mParticle.config.flags; - done(); - }) }); - it('should send user attribute change requests for the MPID it is being set on', function(done) { + it('should send user attribute change requests for the MPID it is being set on', function (done) { mParticle._resetForTests(MPConfig); mParticle.init(apiKey, window.mParticle.config); - waitForCondition(hasIdentifyReturned) - .then(() => { + waitForCondition(hasIdentifyReturned).then(() => { + mParticle.Identity.getCurrentUser().setUserAttribute('age', '25'); + const testMPID = mParticle.Identity.getCurrentUser().getMPID(); + let body: UserAttributes = JSON.parse( + `${`${fetchMock.lastOptions().body}`}`, + ); + expect(body.mpid).to.equal(testMPID); + let event: UserAttributeChangeEvent = body.events[0]; + expect(event.event_type).to.equal('user_attribute_change'); + expect(event.data.new).to.equal('25'); + expect(event.data.old).to.equal(null); + expect(event.data.user_attribute_name).to.equal('age'); + expect(event.data.deleted).to.equal(false); + expect(event.data.is_new_attribute).to.equal(true); + + // new user logs in + const loginUser = { + userIdentities: { + customerid: 'customerid1', + }, + }; + + fetchMockSuccess(urls.login, { + mpid: 'anotherMPID', + is_logged_in: true, + }); - mParticle.Identity.getCurrentUser().setUserAttribute('age', '25'); - const testMPID = mParticle.Identity.getCurrentUser().getMPID(); - let body: UserAttributes = JSON.parse( - `${`${fetchMock.lastOptions().body}`}` - ); - expect(body.mpid).to.equal(testMPID); - let event: UserAttributeChangeEvent = body.events[0]; - expect(event.event_type).to.equal('user_attribute_change'); - expect(event.data.new).to.equal('25'); - expect(event.data.old).to.equal(null); - expect(event.data.user_attribute_name).to.equal('age'); - expect(event.data.deleted).to.equal(false); - expect(event.data.is_new_attribute).to.equal(true); - - // new user logs in - const loginUser = { - userIdentities: { - customerid: 'customerid1', - }, - }; + mParticle.Identity.login(loginUser); - fetchMockSuccess(urls.login, { - mpid: 'anotherMPID', is_logged_in: true + waitForCondition(() => { + return ( + mParticle.Identity.getCurrentUser()?.getMPID() === + 'anotherMPID' + ); + }).then(() => { + const users = mParticle.Identity.getUsers(); + expect(users.length).to.equal(2); + + const anotherMPIDUser = users[0]; + const testMPIDUser = users[1]; + + expect(anotherMPIDUser.getMPID()).to.equal('anotherMPID'); + expect(testMPIDUser.getMPID()).to.equal('testMPID'); + + anotherMPIDUser.setUserAttribute('age', '30'); + body = JSON.parse(`${`${fetchMock.lastOptions().body}`}`); + event = body.events[0]; + expect(body.mpid).to.equal(anotherMPIDUser.getMPID()); + expect(event.event_type).to.equal('user_attribute_change'); + expect(event.data.new).to.equal('30'); + expect(event.data.old).to.equal(null); + expect(event.data.user_attribute_name).to.equal('age'); + expect(event.data.deleted).to.equal(false); + expect(event.data.is_new_attribute).to.equal(true); + + testMPIDUser.setUserAttribute('age', '20'); + body = JSON.parse(`${fetchMock.lastOptions().body}`); + expect(body.mpid).to.equal(testMPIDUser.getMPID()); + event = body.events[0]; + expect(event.event_type).to.equal('user_attribute_change'); + expect(event.data.new).to.equal('20'); + expect(event.data.old).to.equal('25'); + expect(event.data.user_attribute_name).to.equal('age'); + expect(event.data.deleted).to.equal(false); + expect(event.data.is_new_attribute).to.equal(false); + + // remove user attribute + anotherMPIDUser.removeUserAttribute('age'); + body = JSON.parse(`${fetchMock.lastOptions().body}`); + expect(body.mpid).to.equal(anotherMPIDUser.getMPID()); + event = body.events[0]; + expect(event.event_type).to.equal('user_attribute_change'); + expect(event.data.new).to.equal(null); + expect(event.data.old).to.equal('30'); + expect(event.data.user_attribute_name).to.equal('age'); + expect(event.data.deleted).to.equal(true); + expect(event.data.is_new_attribute).to.equal(false); + + testMPIDUser.removeUserAttribute('age'); + body = JSON.parse(`${fetchMock.lastOptions().body}`); + expect(body.mpid).to.equal(testMPIDUser.getMPID()); + event = body.events[0]; + expect(event.event_type).to.equal('user_attribute_change'); + expect(event.data.new).to.equal(null); + expect(event.data.old).to.equal('20'); + expect(event.data.user_attribute_name).to.equal('age'); + expect(event.data.deleted).to.equal(true); + expect(event.data.is_new_attribute).to.equal(false); + + delete window.mParticle.config.flags; + done(); + }); }); - - mParticle.Identity.login(loginUser); - - waitForCondition(() => { - return ( - mParticle.Identity.getCurrentUser()?.getMPID() === 'anotherMPID' - ); - }) - .then(() => { - const users = mParticle.Identity.getUsers(); - expect(users.length).to.equal(2); - - const anotherMPIDUser = users[0]; - const testMPIDUser = users[1]; - - expect(anotherMPIDUser.getMPID()).to.equal('anotherMPID'); - expect(testMPIDUser.getMPID()).to.equal('testMPID'); - - anotherMPIDUser.setUserAttribute('age', '30'); - body = JSON.parse(`${`${fetchMock.lastOptions().body}`}`); - event = body.events[0]; - expect(body.mpid).to.equal(anotherMPIDUser.getMPID()); - expect(event.event_type).to.equal('user_attribute_change'); - expect(event.data.new).to.equal('30'); - expect(event.data.old).to.equal(null); - expect(event.data.user_attribute_name).to.equal('age'); - expect(event.data.deleted).to.equal(false); - expect(event.data.is_new_attribute).to.equal(true); - - testMPIDUser.setUserAttribute('age', '20'); - body = JSON.parse(`${fetchMock.lastOptions().body}`); - expect(body.mpid).to.equal(testMPIDUser.getMPID()); - event = body.events[0]; - expect(event.event_type).to.equal('user_attribute_change'); - expect(event.data.new).to.equal('20'); - expect(event.data.old).to.equal('25'); - expect(event.data.user_attribute_name).to.equal('age'); - expect(event.data.deleted).to.equal(false); - expect(event.data.is_new_attribute).to.equal(false); - - // remove user attribute - anotherMPIDUser.removeUserAttribute('age'); - body = JSON.parse(`${fetchMock.lastOptions().body}`); - expect(body.mpid).to.equal(anotherMPIDUser.getMPID()); - event = body.events[0]; - expect(event.event_type).to.equal('user_attribute_change'); - expect(event.data.new).to.equal(null); - expect(event.data.old).to.equal('30'); - expect(event.data.user_attribute_name).to.equal('age'); - expect(event.data.deleted).to.equal(true); - expect(event.data.is_new_attribute).to.equal(false); - - testMPIDUser.removeUserAttribute('age'); - body = JSON.parse(`${fetchMock.lastOptions().body}`); - expect(body.mpid).to.equal(testMPIDUser.getMPID()); - event = body.events[0]; - expect(event.event_type).to.equal('user_attribute_change'); - expect(event.data.new).to.equal(null); - expect(event.data.old).to.equal('20'); - expect(event.data.user_attribute_name).to.equal('age'); - expect(event.data.deleted).to.equal(true); - expect(event.data.is_new_attribute).to.equal(false); - - delete window.mParticle.config.flags; - done(); - }) - }) }); - it('should send user identity change requests when setting new identities on new users', function(done) { + it('should send user identity change requests when setting new identities on new users', function (done) { mParticle._resetForTests(MPConfig); fetchMock.resetHistory(); @@ -1049,193 +1050,252 @@ describe('identities and attributes', function() { email: 'initial@gmail.com', }, }; - mParticle.config.flags.eventBatchingIntervalMillis = 5000 + mParticle.config.flags.eventBatchingIntervalMillis = 5000; mParticle.init(apiKey, window.mParticle.config); - waitForCondition(hasIdentifyReturned) - .then(() => { - mParticle.upload(); - expect( - JSON.parse(`${fetchMock.lastOptions().body}`).user_identities - ).to.have.property('email', 'initial@gmail.com'); - - mParticle.logEvent('testAfterInit'); - mParticle.upload(); - - expect( - JSON.parse(`${fetchMock.lastOptions().body}`).user_identities - ).to.have.property('email', 'initial@gmail.com'); - - fetchMockSuccess(urls.login, { - mpid: 'anotherMPID', is_logged_in: false - }); - - fetchMock.resetHistory(); - - // anonymous user is in storage, new user logs in - const loginUser = { - userIdentities: { - customerid: 'customerid1', - }, - }; - mParticle.Identity.login(loginUser); - waitForCondition(() => { - return ( - mParticle.Identity.getCurrentUser()?.getMPID() === 'anotherMPID' - ); - }) - .then(() => { - let body = JSON.parse(`${fetchMock.lastOptions().body}`); - - // should be the new MPID - expect(body.mpid).to.equal('anotherMPID'); - expect(body.user_identities).to.have.property( - 'customer_id', - 'customerid1' - ); - expect(body.user_identities).to.not.have.property('email'); - - const event = body.events[0]; - expect(event).to.be.ok; - expect(event.event_type).to.equal('user_identity_change'); - expect(event.data.new.identity_type).to.equal('customer_id'); - expect(event.data.new.identity).to.equal('customerid1'); - expect(typeof event.data.new.timestamp_unixtime_ms).to.equal('number'); - expect(event.data.new.created_this_batch).to.equal(true); - expect(event.data.old.identity_type).to.equal('customer_id'); - expect(event.data.old.identity === null).to.equal(true); - expect(typeof event.data.old.timestamp_unixtime_ms).to.equal('number'); - expect(event.data.old.created_this_batch).to.equal(false); - - mParticle.logEvent('testAfterLogin'); - mParticle.upload(); - body = JSON.parse(`${fetchMock.lastOptions().body}`); - - expect(body.user_identities).to.have.property( - 'customer_id', - 'customerid1' - ); - expect(body.user_identities).to.not.have.property('email'); - - // change customerid creates an identity change event - const modifyUser = { - userIdentities: { - customerid: 'customerid2', - }, - }; - - fetchMockSuccess('https://identity.mparticle.com/v1/anotherMPID/modify', { - mpid: 'anotherMPID', is_logged_in: true + waitForCondition(hasIdentifyReturned).then(() => { + mParticle.upload(); + expect( + JSON.parse(`${fetchMock.lastOptions().body}`).user_identities, + ).to.have.property('email', 'initial@gmail.com'); + + mParticle.logEvent('testAfterInit'); + mParticle.upload(); + + expect( + JSON.parse(`${fetchMock.lastOptions().body}`).user_identities, + ).to.have.property('email', 'initial@gmail.com'); + + fetchMockSuccess(urls.login, { + mpid: 'anotherMPID', + is_logged_in: false, }); - - mParticle.Identity.modify(modifyUser); + + fetchMock.resetHistory(); + + // anonymous user is in storage, new user logs in + const loginUser = { + userIdentities: { + customerid: 'customerid1', + }, + }; + mParticle.Identity.login(loginUser); waitForCondition(() => { return ( - mParticle.getInstance()._Store.identityCallInFlight === false + mParticle.Identity.getCurrentUser()?.getMPID() === + 'anotherMPID' + ); + }).then(() => { + let body = JSON.parse(`${fetchMock.lastOptions().body}`); + + // should be the new MPID + expect(body.mpid).to.equal('anotherMPID'); + expect(body.user_identities).to.have.property( + 'customer_id', + 'customerid1', + ); + expect(body.user_identities).to.not.have.property('email'); + + const event = body.events[0]; + expect(event).to.be.ok; + expect(event.event_type).to.equal('user_identity_change'); + expect(event.data.new.identity_type).to.equal('customer_id'); + expect(event.data.new.identity).to.equal('customerid1'); + expect(typeof event.data.new.timestamp_unixtime_ms).to.equal( + 'number', + ); + expect(event.data.new.created_this_batch).to.equal(true); + expect(event.data.old.identity_type).to.equal('customer_id'); + expect(event.data.old.identity === null).to.equal(true); + expect(typeof event.data.old.timestamp_unixtime_ms).to.equal( + 'number', + ); + expect(event.data.old.created_this_batch).to.equal(false); + + mParticle.logEvent('testAfterLogin'); + mParticle.upload(); + body = JSON.parse(`${fetchMock.lastOptions().body}`); + + expect(body.user_identities).to.have.property( + 'customer_id', + 'customerid1', + ); + expect(body.user_identities).to.not.have.property('email'); + + // change customerid creates an identity change event + const modifyUser = { + userIdentities: { + customerid: 'customerid2', + }, + }; + + fetchMockSuccess( + 'https://identity.mparticle.com/v1/anotherMPID/modify', + { + mpid: 'anotherMPID', + is_logged_in: true, + }, + ); + + mParticle.Identity.modify(modifyUser); + waitForCondition(() => { + return ( + mParticle.getInstance()._Store.identityCallInFlight === + false ); - }) - .then(() => { - const body2 = JSON.parse(`${fetchMock.lastOptions().body}`); - expect(body2.mpid).to.equal('anotherMPID'); - expect(body2.user_identities).to.have.property( - 'customer_id', - 'customerid2' - ); - expect(body2.user_identities).to.not.have.property('email'); - - const event2 = body2.events[0]; - expect(event2).to.be.ok; - expect(event2.event_type).to.equal('user_identity_change'); - expect(event2.data.new.identity_type).to.equal('customer_id'); - expect(event2.data.new.identity).to.equal('customerid2'); - expect(typeof event2.data.new.timestamp_unixtime_ms).to.equal('number'); - expect(event2.data.new.created_this_batch).to.equal(false); - expect(event2.data.old.identity_type).to.equal('customer_id'); - expect(event2.data.old.identity).to.equal('customerid1'); - expect(typeof event2.data.old.timestamp_unixtime_ms).to.equal('number'); - expect(event2.data.old.created_this_batch).to.equal(false); - - // Adding a new identity to the current user will create an identity change event - const modifyUser2 = { - userIdentities: { - customerid: 'customerid2', - email: 'test@test.com', - }, - }; - - fetchMock.resetHistory(); - - mParticle.Identity.modify(modifyUser2); - waitForCondition(() => { - return ( - mParticle.getInstance()._Store.identityCallInFlight === false - ); - }) - .then(() => { - const body3 = JSON.parse(`${fetchMock.lastOptions().body}`); - expect(body3.mpid).to.equal('anotherMPID'); - - const event3 = body3.events[0]; - expect(event3).to.be.ok; - expect(event3.event_type).to.equal('user_identity_change'); - expect(event3.data.new.identity_type).to.equal('email'); - expect(event3.data.new.identity).to.equal('test@test.com'); - expect(typeof event3.data.new.timestamp_unixtime_ms).to.equal('number'); - expect(event3.data.new.created_this_batch).to.equal(true); - - expect(event3.data.old.identity_type).to.equal('email'); - expect(event3.data.old.identity === null).to.equal(true); - expect(typeof event3.data.old.timestamp_unixtime_ms).to.equal('number'); - expect(event3.data.old.created_this_batch).to.equal(false); - - // logout with an other will create only a change event for the other - const logoutUser = { - userIdentities: { - other: 'other1', - }, - }; - fetchMock.resetHistory(); + }).then(() => { + const body2 = JSON.parse(`${fetchMock.lastOptions().body}`); + expect(body2.mpid).to.equal('anotherMPID'); + expect(body2.user_identities).to.have.property( + 'customer_id', + 'customerid2', + ); + expect(body2.user_identities).to.not.have.property('email'); - fetchMockSuccess(urls.logout, { - mpid: 'mpid2', is_logged_in: false + const event2 = body2.events[0]; + expect(event2).to.be.ok; + expect(event2.event_type).to.equal('user_identity_change'); + expect(event2.data.new.identity_type).to.equal( + 'customer_id', + ); + expect(event2.data.new.identity).to.equal('customerid2'); + expect( + typeof event2.data.new.timestamp_unixtime_ms, + ).to.equal('number'); + expect(event2.data.new.created_this_batch).to.equal(false); + expect(event2.data.old.identity_type).to.equal( + 'customer_id', + ); + expect(event2.data.old.identity).to.equal('customerid1'); + expect( + typeof event2.data.old.timestamp_unixtime_ms, + ).to.equal('number'); + expect(event2.data.old.created_this_batch).to.equal(false); + + // Adding a new identity to the current user will create an identity change event + const modifyUser2 = { + userIdentities: { + customerid: 'customerid2', + email: 'test@test.com', + }, + }; + + fetchMock.resetHistory(); + + mParticle.Identity.modify(modifyUser2); + waitForCondition(() => { + return ( + mParticle.getInstance()._Store + .identityCallInFlight === false + ); + }).then(() => { + const body3 = JSON.parse( + `${fetchMock.lastOptions().body}`, + ); + expect(body3.mpid).to.equal('anotherMPID'); + + const event3 = body3.events[0]; + expect(event3).to.be.ok; + expect(event3.event_type).to.equal( + 'user_identity_change', + ); + expect(event3.data.new.identity_type).to.equal('email'); + expect(event3.data.new.identity).to.equal( + 'test@test.com', + ); + expect( + typeof event3.data.new.timestamp_unixtime_ms, + ).to.equal('number'); + expect(event3.data.new.created_this_batch).to.equal( + true, + ); + + expect(event3.data.old.identity_type).to.equal('email'); + expect(event3.data.old.identity === null).to.equal( + true, + ); + expect( + typeof event3.data.old.timestamp_unixtime_ms, + ).to.equal('number'); + expect(event3.data.old.created_this_batch).to.equal( + false, + ); + + // logout with an other will create only a change event for the other + const logoutUser = { + userIdentities: { + other: 'other1', + }, + }; + fetchMock.resetHistory(); + + fetchMockSuccess(urls.logout, { + mpid: 'mpid2', + is_logged_in: false, + }); + + mParticle.Identity.logout(logoutUser); + waitForCondition(() => { + return ( + mParticle.Identity.getCurrentUser()?.getMPID() === + 'mpid2' + ); + }).then(() => { + // Calls are for logout and UIC + expect(fetchMock.calls().length).to.equal(2); + const body4 = JSON.parse( + `${fetchMock.lastOptions().body}`, + ); + expect(body4.mpid).to.equal('mpid2'); + + const event4 = body4.events[0]; + expect(event4).to.be.ok; + expect(event4.event_type).to.equal( + 'user_identity_change', + ); + expect(event4.data.new.identity_type).to.equal( + 'other', + ); + expect(event4.data.new.identity).to.equal('other1'); + expect( + typeof event4.data.new.timestamp_unixtime_ms, + ).to.equal('number'); + expect(event4.data.new.created_this_batch).to.equal( + true, + ); + + expect(event4.data.old.identity_type).to.equal( + 'other', + ); + expect(event4.data.old.identity === null).to.equal( + true, + ); + expect( + typeof event4.data.old.timestamp_unixtime_ms, + ).to.equal('number'); + expect(event4.data.old.created_this_batch).to.equal( + false, + ); + + mParticle.logEvent('testAfterLogout'); + + const body5 = JSON.parse( + `${fetchMock.lastOptions().body}`, + ); + expect(body5.mpid).to.equal('mpid2'); + expect( + Object.keys(body5.user_identities).length, + ).to.equal(1); + expect(body5.user_identities).to.have.property( + 'other', + 'other1', + ); + + done(); + }); + }); + }); + }); }); - - mParticle.Identity.logout(logoutUser); - waitForCondition(() => { - return ( - mParticle.Identity.getCurrentUser()?.getMPID() === 'mpid2' - ); - }).then(() => { - // Calls are for logout and UIC - expect(fetchMock.calls().length).to.equal(2); - const body4 = JSON.parse(`${fetchMock.lastOptions().body}`); - expect(body4.mpid).to.equal('mpid2'); - - const event4 = body4.events[0]; - expect(event4).to.be.ok; - expect(event4.event_type).to.equal('user_identity_change'); - expect(event4.data.new.identity_type).to.equal('other'); - expect(event4.data.new.identity).to.equal('other1'); - expect(typeof event4.data.new.timestamp_unixtime_ms).to.equal('number'); - expect(event4.data.new.created_this_batch).to.equal(true); - - expect(event4.data.old.identity_type).to.equal('other'); - expect(event4.data.old.identity === null).to.equal(true); - expect(typeof event4.data.old.timestamp_unixtime_ms).to.equal('number'); - expect(event4.data.old.created_this_batch).to.equal(false); - - mParticle.logEvent('testAfterLogout'); - - const body5 = JSON.parse(`${fetchMock.lastOptions().body}`); - expect(body5.mpid).to.equal('mpid2'); - expect(Object.keys(body5.user_identities).length).to.equal(1); - expect(body5.user_identities).to.have.property('other', 'other1'); - - done(); - }) - }) - }); - }) - }) }); it('should order user identity change events before logging any events', async () => { @@ -1266,43 +1326,81 @@ describe('identities and attributes', function() { const secondCall = fetchMock.calls()[1]; expect(secondCall[0].split('/')[6]).to.equal('events'); - const secondCallBody = JSON.parse(secondCall[1].body as unknown as string) as Batch; - expect(secondCallBody.events[0].event_type).to.equal('session_start', 'Second Call'); + const secondCallBody = JSON.parse( + secondCall[1].body as unknown as string, + ) as Batch; + expect(secondCallBody.events[0].event_type).to.equal( + 'session_start', + 'Second Call', + ); const thirdCall = fetchMock.calls()[2]; expect(thirdCall[0].split('/')[6]).to.equal('events'); - const thirdCallBody = JSON.parse(thirdCall[1].body as unknown as string) as Batch; - expect(thirdCallBody.events[0].event_type).to.equal('application_state_transition', 'Third Call'); + const thirdCallBody = JSON.parse( + thirdCall[1].body as unknown as string, + ) as Batch; + expect(thirdCallBody.events[0].event_type).to.equal( + 'application_state_transition', + 'Third Call', + ); const fourthCall = fetchMock.calls()[3]; expect(fourthCall[0].split('/')[6]).to.equal('events'); - const fourthCallBody = JSON.parse(fourthCall[1].body as unknown as string) as Batch; - expect(fourthCallBody.events[0].event_type).to.equal('user_identity_change', 'Fourth Call'); + const fourthCallBody = JSON.parse( + fourthCall[1].body as unknown as string, + ) as Batch; + expect(fourthCallBody.events[0].event_type).to.equal( + 'user_identity_change', + 'Fourth Call', + ); const fifthCall = fetchMock.calls()[4]; expect(fifthCall[0].split('/')[6]).to.equal('events'); - const fifthCallBody = JSON.parse(fifthCall[1].body as unknown as string) as Batch; + const fifthCallBody = JSON.parse( + fifthCall[1].body as unknown as string, + ) as Batch; const fifthCallEvent = fifthCallBody.events[0] as CustomEvent; - expect(fifthCallEvent.event_type).to.equal('custom_event', 'Fifth Call'); - expect(fifthCallEvent.data.event_name).to.equal('Test Event 1', 'Fifth Call'); + expect(fifthCallEvent.event_type).to.equal( + 'custom_event', + 'Fifth Call', + ); + expect(fifthCallEvent.data.event_name).to.equal( + 'Test Event 1', + 'Fifth Call', + ); const sixthCall = fetchMock.calls()[5]; expect(sixthCall[0].split('/')[6]).to.equal('events'); - const sixthCallBody = JSON.parse(sixthCall[1].body as unknown as string) as Batch; + const sixthCallBody = JSON.parse( + sixthCall[1].body as unknown as string, + ) as Batch; const sixthCallEvent = sixthCallBody.events[0] as CustomEvent; - expect(sixthCallBody.events[0].event_type).to.equal('custom_event', 'Sixth Call'); - expect(sixthCallEvent.data.event_name).to.equal('Test Event 2', 'Sixth Call'); + expect(sixthCallBody.events[0].event_type).to.equal( + 'custom_event', + 'Sixth Call', + ); + expect(sixthCallEvent.data.event_name).to.equal( + 'Test Event 2', + 'Sixth Call', + ); const seventhEvent = fetchMock.calls()[6]; expect(seventhEvent[0].split('/')[6]).to.equal('events'); - const seventhEventBody = JSON.parse(seventhEvent[1].body as unknown as string) as Batch; + const seventhEventBody = JSON.parse( + seventhEvent[1].body as unknown as string, + ) as Batch; const seventhEventEvent = seventhEventBody.events[0] as CustomEvent; - expect(seventhEventBody.events[0].event_type).to.equal('custom_event', 'Seventh Call'); - expect(seventhEventEvent.data.event_name).to.equal('Test Event 3', 'Seventh Call'); + expect(seventhEventBody.events[0].event_type).to.equal( + 'custom_event', + 'Seventh Call', + ); + expect(seventhEventEvent.data.event_name).to.equal( + 'Test Event 3', + 'Seventh Call', + ); }); it('should order user identity change events before logging any events that are in the ready queue', async () => { - mParticle._resetForTests(MPConfig); fetchMock.resetHistory(); @@ -1332,42 +1430,81 @@ describe('identities and attributes', function() { const secondCall = fetchMock.calls()[1]; expect(secondCall[0].split('/')[6]).to.equal('events'); - const secondCallBody = JSON.parse(secondCall[1].body as unknown as string) as Batch; - expect(secondCallBody.events[0].event_type).to.equal('session_start', 'Second Call'); + const secondCallBody = JSON.parse( + secondCall[1].body as unknown as string, + ) as Batch; + expect(secondCallBody.events[0].event_type).to.equal( + 'session_start', + 'Second Call', + ); const thirdCall = fetchMock.calls()[2]; expect(thirdCall[0].split('/')[6]).to.equal('events'); - const thirdCallBody = JSON.parse(thirdCall[1].body as unknown as string) as Batch; - expect(thirdCallBody.events[0].event_type).to.equal('application_state_transition', 'Third Call'); + const thirdCallBody = JSON.parse( + thirdCall[1].body as unknown as string, + ) as Batch; + expect(thirdCallBody.events[0].event_type).to.equal( + 'application_state_transition', + 'Third Call', + ); const fourthCall = fetchMock.calls()[3]; expect(fourthCall[0].split('/')[6]).to.equal('events'); - const fourthCallBody = JSON.parse(fourthCall[1].body as unknown as string) as Batch; - expect(fourthCallBody.events[0].event_type).to.equal('user_identity_change', 'Fourth Call'); + const fourthCallBody = JSON.parse( + fourthCall[1].body as unknown as string, + ) as Batch; + expect(fourthCallBody.events[0].event_type).to.equal( + 'user_identity_change', + 'Fourth Call', + ); const fifthCall = fetchMock.calls()[4]; expect(fifthCall[0].split('/')[6]).to.equal('events'); - const fifthCallBody = JSON.parse(fifthCall[1].body as unknown as string) as Batch; + const fifthCallBody = JSON.parse( + fifthCall[1].body as unknown as string, + ) as Batch; const fifthCallEvent = fifthCallBody.events[0] as CustomEvent; - expect(fifthCallEvent.event_type).to.equal('custom_event', 'Fifth Call'); - expect(fifthCallEvent.data.event_name).to.equal('Test Event 1', 'Fifth Call'); + expect(fifthCallEvent.event_type).to.equal( + 'custom_event', + 'Fifth Call', + ); + expect(fifthCallEvent.data.event_name).to.equal( + 'Test Event 1', + 'Fifth Call', + ); const sixthCall = fetchMock.calls()[5]; expect(sixthCall[0].split('/')[6]).to.equal('events'); - const sixthCallBody = JSON.parse(sixthCall[1].body as unknown as string) as Batch; + const sixthCallBody = JSON.parse( + sixthCall[1].body as unknown as string, + ) as Batch; const sixthCallEvent = sixthCallBody.events[0] as CustomEvent; - expect(sixthCallBody.events[0].event_type).to.equal('custom_event', 'Sixth Call'); - expect(sixthCallEvent.data.event_name).to.equal('Test Event 2', 'Sixth Call'); + expect(sixthCallBody.events[0].event_type).to.equal( + 'custom_event', + 'Sixth Call', + ); + expect(sixthCallEvent.data.event_name).to.equal( + 'Test Event 2', + 'Sixth Call', + ); const seventhEvent = fetchMock.calls()[6]; expect(seventhEvent[0].split('/')[6]).to.equal('events'); - const seventhEventBody = JSON.parse(seventhEvent[1].body as unknown as string) as Batch; + const seventhEventBody = JSON.parse( + seventhEvent[1].body as unknown as string, + ) as Batch; const seventhEventEvent = seventhEventBody.events[0] as CustomEvent; - expect(seventhEventBody.events[0].event_type).to.equal('custom_event', 'Seventh Call'); - expect(seventhEventEvent.data.event_name).to.equal('Test Event 3', 'Seventh Call'); + expect(seventhEventBody.events[0].event_type).to.equal( + 'custom_event', + 'Seventh Call', + ); + expect(seventhEventEvent.data.event_name).to.equal( + 'Test Event 3', + 'Seventh Call', + ); }); - it('should send historical UIs on batches when MPID changes', function(done) { + it('should send historical UIs on batches when MPID changes', function (done) { mParticle._resetForTests(MPConfig); window.mParticle.config.identifyRequest = { @@ -1376,109 +1513,118 @@ describe('identities and attributes', function() { }, }; - window.mParticle.config.flags = { EventBatchingIntervalMillis: 0, - } - - mParticle.init(apiKey, window.mParticle.config); - - waitForCondition(hasIdentifyReturned) - .then(() => { - fetchMockSuccess(urls.login, { - mpid: 'testMPID', is_logged_in: true - }); - // on identity strategy where MPID remains the same from anonymous to login - const loginUser = { - userIdentities: { - customerid: 'customerid1', - }, - }; - - mParticle.Identity.login(loginUser); - - waitForCondition(() => { - return ( - mParticle.getInstance()._Store.identityCallInFlight === false - ); - }) - .then(() => { - let batch = JSON.parse(`${fetchMock.lastOptions().body}`); - expect(batch.mpid).to.equal(testMPID); - expect(batch.user_identities).to.have.property( - 'email', - 'initial@gmail.com' - ); - expect(batch.user_identities).to.have.property( - 'customer_id', - 'customerid1' - ); - - const logoutUser = { - userIdentities: { - other: 'other1', - }, }; - fetchMockSuccess(urls.logout, { - mpid: 'mpid2', is_logged_in: false - }); + mParticle.init(apiKey, window.mParticle.config); - mParticle.Identity.logout(logoutUser); + waitForCondition(hasIdentifyReturned).then(() => { + fetchMockSuccess(urls.login, { + mpid: 'testMPID', + is_logged_in: true, + }); + // on identity strategy where MPID remains the same from anonymous to login + const loginUser = { + userIdentities: { + customerid: 'customerid1', + }, + }; - waitForCondition(() => { - return ( - mParticle.Identity.getCurrentUser()?.getMPID() === 'mpid2' - ); - }) - .then(() => { - batch = JSON.parse(`${fetchMock.lastOptions().body}`); - expect(batch.mpid).to.equal('mpid2'); - expect(batch.user_identities).to.have.property('other', 'other1'); - expect(batch.user_identities).to.not.have.property('email'); - expect(batch.user_identities).to.not.have.property('customer_id'); + mParticle.Identity.login(loginUser); - fetchMock.resetHistory(); - // log back in with previous MPID, but with only a single UI, all UIs should be on batch + waitForCondition(() => { + return ( + mParticle.getInstance()._Store.identityCallInFlight === + false + ); + }).then(() => { + let batch = JSON.parse(`${fetchMock.lastOptions().body}`); + expect(batch.mpid).to.equal(testMPID); + expect(batch.user_identities).to.have.property( + 'email', + 'initial@gmail.com', + ); + expect(batch.user_identities).to.have.property( + 'customer_id', + 'customerid1', + ); + + const logoutUser = { + userIdentities: { + other: 'other1', + }, + }; + + fetchMockSuccess(urls.logout, { + mpid: 'mpid2', + is_logged_in: false, + }); + + mParticle.Identity.logout(logoutUser); + + waitForCondition(() => { + return ( + mParticle.Identity.getCurrentUser()?.getMPID() === + 'mpid2' + ); + }).then(() => { + batch = JSON.parse(`${fetchMock.lastOptions().body}`); + expect(batch.mpid).to.equal('mpid2'); + expect(batch.user_identities).to.have.property( + 'other', + 'other1', + ); + expect(batch.user_identities).to.not.have.property('email'); + expect(batch.user_identities).to.not.have.property( + 'customer_id', + ); - fetchMockSuccess(urls.login, { - mpid: 'testMPID', is_logged_in: true + fetchMock.resetHistory(); + // log back in with previous MPID, but with only a single UI, all UIs should be on batch + + fetchMockSuccess(urls.login, { + mpid: 'testMPID', + is_logged_in: true, + }); + + mParticle.Identity.login(loginUser); + + waitForCondition(() => { + return ( + mParticle.getInstance()._Store + .identityCallInFlight === false + ); + }).then(() => { + // switching back to logged in user should not result in any UIC events + expect(fetchMock.calls().length).to.equal(1); + + const data = getIdentityEvent( + fetchMock.calls(), + 'login', + ); + + expect(data).to.be.ok; + + mParticle.logEvent('event after logging back in'); + batch = JSON.parse(`${fetchMock.lastOptions().body}`); + expect(batch.mpid).to.equal(testMPID); + expect(batch.user_identities).to.have.property( + 'email', + 'initial@gmail.com', + ); + expect(batch.user_identities).to.have.property( + 'customer_id', + 'customerid1', + ); + done(); + }); + }); + }); }); - - mParticle.Identity.login(loginUser); - - waitForCondition(() => { - return ( - mParticle.getInstance()._Store.identityCallInFlight === false - ); - }) - .then(() => { - // switching back to logged in user should not result in any UIC events - expect(fetchMock.calls().length).to.equal(1); - - const data = getIdentityEvent(fetchMock.calls(), 'login'); - - expect(data).to.be.ok; - - mParticle.logEvent('event after logging back in'); - batch = JSON.parse(`${fetchMock.lastOptions().body}`); - expect(batch.mpid).to.equal(testMPID); - expect(batch.user_identities).to.have.property( - 'email', - 'initial@gmail.com' - ); - expect(batch.user_identities).to.have.property( - 'customer_id', - 'customerid1' - ); - done(); - }) - }) - }) - }) }); - it('should not send user attribute change requests when user attribute already set with same value with false values', function(done) { + it('should not send user attribute change requests when user attribute already set with same value with false values', function (done) { mParticle._resetForTests(MPConfig); window.mParticle.config.flags = { @@ -1487,99 +1633,102 @@ describe('identities and attributes', function() { mParticle.init(apiKey, window.mParticle.config); - waitForCondition(hasIdentifyReturned) - .then(() => { - // set a new attribute, age - fetchMock.resetHistory(); - mParticle.Identity.getCurrentUser().setUserAttribute('age', '25'); - const body1 = JSON.parse(`${fetchMock.lastOptions().body}`); - expect(body1.user_attributes).to.have.property('age', '25'); - const event1 = body1.events[0]; - expect(event1).to.be.ok; - expect(event1.event_type).to.equal('user_attribute_change'); - expect(event1.data.new).to.equal('25'); - expect(event1.data.old).to.equal(null); - expect(event1.data.user_attribute_name).to.equal('age'); - expect(event1.data.deleted).to.equal(false); - expect(event1.data.is_new_attribute).to.equal(true); - - // test setting attributes with 'false' values (i.e false, 0 and '') - - // check for UAC event for testFalse: fasle when set for first time - fetchMock.resetHistory(); - mParticle.Identity.getCurrentUser().setUserAttribute( - 'testFalse', - false - ); - const body2 = JSON.parse(`${fetchMock.lastOptions().body}`); - expect(body2.user_attributes).to.have.property('testFalse', false); - const event2 = body2.events[0]; - expect(event2).to.be.ok; - expect(event2.event_type).to.equal('user_attribute_change'); - expect(event2.data.new).to.equal(false); - expect(event2.data.old).to.equal(null); - expect(event2.data.user_attribute_name).to.equal('testFalse'); - expect(event2.data.deleted).to.equal(false); - expect(event2.data.is_new_attribute).to.equal(true); - - // check for UAC event for testEmptyString: '' when set for first time - fetchMock.resetHistory(); - mParticle.Identity.getCurrentUser().setUserAttribute( - 'testEmptyString', - '' - ); - const body3 = JSON.parse(`${fetchMock.lastOptions().body}`); - expect(body3.user_attributes).to.have.property('testEmptyString', ''); - const event3 = body3.events[0]; - expect(event3).to.be.ok; - expect(event3.event_type).to.equal('user_attribute_change'); - expect(event3.data.new).to.equal(''); - expect(event3.data.old).to.equal(null); - expect(event3.data.user_attribute_name).to.equal('testEmptyString'); - expect(event3.data.deleted).to.equal(false); - expect(event3.data.is_new_attribute).to.equal(true); - - // check for UAC event for testZero: 0 when set for first time - fetchMock.resetHistory(); - mParticle.Identity.getCurrentUser().setUserAttribute('testZero', 0); - const body4 = JSON.parse(`${fetchMock.lastOptions().body}`); - expect(body4.user_attributes).to.have.property('testZero', 0); - const event4 = body4.events[0]; - expect(event4).to.be.ok; - expect(event4.event_type).to.equal('user_attribute_change'); - expect(event4.data.new).to.equal(0); - expect(event4.data.old).to.equal(null); - expect(event4.data.user_attribute_name).to.equal('testZero'); - expect(event4.data.deleted).to.equal(false); - expect(event4.data.is_new_attribute).to.equal(true); - - // confirm user attributes previously set already exist for user - const userAttributes = mParticle.Identity.getCurrentUser().getAllUserAttributes(); - expect(userAttributes).to.have.property('age'); - expect(userAttributes).to.have.property('testFalse'); - expect(userAttributes).to.have.property('testEmptyString'); - expect(userAttributes).to.have.property('testZero'); - - // re-set all previous attributes with the same values - fetchMock.resetHistory(); - mParticle.Identity.getCurrentUser().setUserAttribute('age', '25'); - mParticle.Identity.getCurrentUser().setUserAttribute( - 'testFalse', - false - ); - mParticle.Identity.getCurrentUser().setUserAttribute( - 'testEmptyString', - '' - ); - mParticle.Identity.getCurrentUser().setUserAttribute('testZero', 0); - expect(fetchMock.lastOptions()).to.equal(undefined); - expect(fetchMock.calls().length).to.equal(0); + waitForCondition(hasIdentifyReturned).then(() => { + // set a new attribute, age + fetchMock.resetHistory(); + mParticle.Identity.getCurrentUser().setUserAttribute('age', '25'); + const body1 = JSON.parse(`${fetchMock.lastOptions().body}`); + expect(body1.user_attributes).to.have.property('age', '25'); + const event1 = body1.events[0]; + expect(event1).to.be.ok; + expect(event1.event_type).to.equal('user_attribute_change'); + expect(event1.data.new).to.equal('25'); + expect(event1.data.old).to.equal(null); + expect(event1.data.user_attribute_name).to.equal('age'); + expect(event1.data.deleted).to.equal(false); + expect(event1.data.is_new_attribute).to.equal(true); + + // test setting attributes with 'false' values (i.e false, 0 and '') + + // check for UAC event for testFalse: fasle when set for first time + fetchMock.resetHistory(); + mParticle.Identity.getCurrentUser().setUserAttribute( + 'testFalse', + false, + ); + const body2 = JSON.parse(`${fetchMock.lastOptions().body}`); + expect(body2.user_attributes).to.have.property('testFalse', false); + const event2 = body2.events[0]; + expect(event2).to.be.ok; + expect(event2.event_type).to.equal('user_attribute_change'); + expect(event2.data.new).to.equal(false); + expect(event2.data.old).to.equal(null); + expect(event2.data.user_attribute_name).to.equal('testFalse'); + expect(event2.data.deleted).to.equal(false); + expect(event2.data.is_new_attribute).to.equal(true); + + // check for UAC event for testEmptyString: '' when set for first time + fetchMock.resetHistory(); + mParticle.Identity.getCurrentUser().setUserAttribute( + 'testEmptyString', + '', + ); + const body3 = JSON.parse(`${fetchMock.lastOptions().body}`); + expect(body3.user_attributes).to.have.property( + 'testEmptyString', + '', + ); + const event3 = body3.events[0]; + expect(event3).to.be.ok; + expect(event3.event_type).to.equal('user_attribute_change'); + expect(event3.data.new).to.equal(''); + expect(event3.data.old).to.equal(null); + expect(event3.data.user_attribute_name).to.equal('testEmptyString'); + expect(event3.data.deleted).to.equal(false); + expect(event3.data.is_new_attribute).to.equal(true); + + // check for UAC event for testZero: 0 when set for first time + fetchMock.resetHistory(); + mParticle.Identity.getCurrentUser().setUserAttribute('testZero', 0); + const body4 = JSON.parse(`${fetchMock.lastOptions().body}`); + expect(body4.user_attributes).to.have.property('testZero', 0); + const event4 = body4.events[0]; + expect(event4).to.be.ok; + expect(event4.event_type).to.equal('user_attribute_change'); + expect(event4.data.new).to.equal(0); + expect(event4.data.old).to.equal(null); + expect(event4.data.user_attribute_name).to.equal('testZero'); + expect(event4.data.deleted).to.equal(false); + expect(event4.data.is_new_attribute).to.equal(true); + + // confirm user attributes previously set already exist for user + const userAttributes = + mParticle.Identity.getCurrentUser().getAllUserAttributes(); + expect(userAttributes).to.have.property('age'); + expect(userAttributes).to.have.property('testFalse'); + expect(userAttributes).to.have.property('testEmptyString'); + expect(userAttributes).to.have.property('testZero'); + + // re-set all previous attributes with the same values + fetchMock.resetHistory(); + mParticle.Identity.getCurrentUser().setUserAttribute('age', '25'); + mParticle.Identity.getCurrentUser().setUserAttribute( + 'testFalse', + false, + ); + mParticle.Identity.getCurrentUser().setUserAttribute( + 'testEmptyString', + '', + ); + mParticle.Identity.getCurrentUser().setUserAttribute('testZero', 0); + expect(fetchMock.lastOptions()).to.equal(undefined); + expect(fetchMock.calls().length).to.equal(0); - done(); - }) + done(); + }); }); - it('should send user attribute change event when setting different falsey values', function(done) { + it('should send user attribute change event when setting different falsey values', function (done) { mParticle._resetForTests(MPConfig); window.mParticle.config.flags = { @@ -1588,68 +1737,76 @@ describe('identities and attributes', function() { mParticle.init(apiKey, window.mParticle.config); - waitForCondition(hasIdentifyReturned) - .then(() => { - // set initial test attribute with 'falsey' value to 0 - fetchMock.resetHistory(); - mParticle.Identity.getCurrentUser().setUserAttribute('testFalsey', 0); - const body1 = JSON.parse(`${fetchMock.lastOptions().body}`); - expect(body1.user_attributes).to.have.property('testFalsey', 0); - const event1 = body1.events[0]; - expect(event1).to.be.ok; - expect(event1.event_type).to.equal('user_attribute_change'); - expect(event1.data.new).to.equal(0); - expect(event1.data.old).to.equal(null); - expect(event1.data.user_attribute_name).to.equal('testFalsey'); - expect(event1.data.deleted).to.equal(false); - expect(event1.data.is_new_attribute).to.equal(true); - - // re-set same test attribute with 'falsey' value to '' - fetchMock.resetHistory(); - mParticle.Identity.getCurrentUser().setUserAttribute('testFalsey', ''); - const body2 = JSON.parse(`${fetchMock.lastOptions().body}`); - expect(body2.user_attributes).to.have.property('testFalsey', ''); - const event2 = body2.events[0]; - expect(event2).to.be.ok; - expect(event2.event_type).to.equal('user_attribute_change'); - expect(event2.data.new).to.equal(''); - expect(event2.data.old).to.equal(0); - expect(event2.data.user_attribute_name).to.equal('testFalsey'); - expect(event2.data.deleted).to.equal(false); - expect(event2.data.is_new_attribute).to.equal(false); - - // re-set same test attribute with 'falsey' value to false - fetchMock.resetHistory(); - mParticle.Identity.getCurrentUser().setUserAttribute( - 'testFalsey', - false - ); - const body3 = JSON.parse(`${fetchMock.lastOptions().body}`); - expect(body3.user_attributes).to.have.property('testFalsey', false); - const event3 = body3.events[0]; - expect(event3).to.be.ok; - expect(event3.event_type).to.equal('user_attribute_change'); - expect(event3.data.new).to.equal(false); - expect(event3.data.old).to.equal(''); - expect(event3.data.user_attribute_name).to.equal('testFalsey'); - expect(event3.data.deleted).to.equal(false); - expect(event3.data.is_new_attribute).to.equal(false); - - // re-set same test attribute with 'falsey' value to original value 0 - fetchMock.resetHistory(); - mParticle.Identity.getCurrentUser().setUserAttribute('testFalsey', 0); - const body4 = JSON.parse(`${fetchMock.lastOptions().body}`); - expect(body4.user_attributes).to.have.property('testFalsey', 0); - const event4 = body4.events[0]; - expect(event4).to.be.ok; - expect(event4.event_type).to.equal('user_attribute_change'); - expect(event4.data.new).to.equal(0); - expect(event4.data.old).to.equal(false); - expect(event4.data.user_attribute_name).to.equal('testFalsey'); - expect(event4.data.deleted).to.equal(false); - expect(event4.data.is_new_attribute).to.equal(false); - - done(); - }) + waitForCondition(hasIdentifyReturned).then(() => { + // set initial test attribute with 'falsey' value to 0 + fetchMock.resetHistory(); + mParticle.Identity.getCurrentUser().setUserAttribute( + 'testFalsey', + 0, + ); + const body1 = JSON.parse(`${fetchMock.lastOptions().body}`); + expect(body1.user_attributes).to.have.property('testFalsey', 0); + const event1 = body1.events[0]; + expect(event1).to.be.ok; + expect(event1.event_type).to.equal('user_attribute_change'); + expect(event1.data.new).to.equal(0); + expect(event1.data.old).to.equal(null); + expect(event1.data.user_attribute_name).to.equal('testFalsey'); + expect(event1.data.deleted).to.equal(false); + expect(event1.data.is_new_attribute).to.equal(true); + + // re-set same test attribute with 'falsey' value to '' + fetchMock.resetHistory(); + mParticle.Identity.getCurrentUser().setUserAttribute( + 'testFalsey', + '', + ); + const body2 = JSON.parse(`${fetchMock.lastOptions().body}`); + expect(body2.user_attributes).to.have.property('testFalsey', ''); + const event2 = body2.events[0]; + expect(event2).to.be.ok; + expect(event2.event_type).to.equal('user_attribute_change'); + expect(event2.data.new).to.equal(''); + expect(event2.data.old).to.equal(0); + expect(event2.data.user_attribute_name).to.equal('testFalsey'); + expect(event2.data.deleted).to.equal(false); + expect(event2.data.is_new_attribute).to.equal(false); + + // re-set same test attribute with 'falsey' value to false + fetchMock.resetHistory(); + mParticle.Identity.getCurrentUser().setUserAttribute( + 'testFalsey', + false, + ); + const body3 = JSON.parse(`${fetchMock.lastOptions().body}`); + expect(body3.user_attributes).to.have.property('testFalsey', false); + const event3 = body3.events[0]; + expect(event3).to.be.ok; + expect(event3.event_type).to.equal('user_attribute_change'); + expect(event3.data.new).to.equal(false); + expect(event3.data.old).to.equal(''); + expect(event3.data.user_attribute_name).to.equal('testFalsey'); + expect(event3.data.deleted).to.equal(false); + expect(event3.data.is_new_attribute).to.equal(false); + + // re-set same test attribute with 'falsey' value to original value 0 + fetchMock.resetHistory(); + mParticle.Identity.getCurrentUser().setUserAttribute( + 'testFalsey', + 0, + ); + const body4 = JSON.parse(`${fetchMock.lastOptions().body}`); + expect(body4.user_attributes).to.have.property('testFalsey', 0); + const event4 = body4.events[0]; + expect(event4).to.be.ok; + expect(event4.event_type).to.equal('user_attribute_change'); + expect(event4.data.new).to.equal(0); + expect(event4.data.old).to.equal(false); + expect(event4.data.user_attribute_name).to.equal('testFalsey'); + expect(event4.data.deleted).to.equal(false); + expect(event4.data.is_new_attribute).to.equal(false); + + done(); + }); }); -}); \ No newline at end of file +}); diff --git a/test/src/tests-identity-utils.ts b/test/src/tests-identity-utils.ts index 9d914a42e..39be02715 100644 --- a/test/src/tests-identity-utils.ts +++ b/test/src/tests-identity-utils.ts @@ -8,32 +8,38 @@ import { tryCacheIdentity, IKnownIdentities, ICachedIdentityCall, -} from "../../src/identity-utils"; -import { LocalStorageVault } from "../../src/vault"; -import { Dictionary, generateHash } from "../../src/utils"; +} from '../../src/identity-utils'; +import { LocalStorageVault } from '../../src/vault'; +import { Dictionary, generateHash } from '../../src/utils'; import { expect } from 'chai'; -import { - apiKey, MPConfig, +import { + apiKey, + MPConfig, MILLISECONDS_IN_ONE_DAY, MILLISECONDS_IN_ONE_DAY_PLUS_ONE_SECOND, testMPID, - localStorageIDKey + localStorageIDKey, } from './config/constants'; import { IdentityApiData } from '@mparticle/web-sdk'; -import Identity from "../../src/identity"; +import Identity from '../../src/identity'; import Constants from '../../src/constants'; const { Identify, Login, Logout } = Constants.IdentityMethods; import sinon from 'sinon'; // https://go.mparticle.com/work/SQDSDKS-6671 -import { IdentityResultBody, IIdentityResponse } from "../../src/identity-user-interfaces"; +import { + IdentityResultBody, + IIdentityResponse, +} from '../../src/identity-user-interfaces'; -const DEVICE_ID = 'test-device-id' +const DEVICE_ID = 'test-device-id'; -const knownIdentities: IKnownIdentities = createKnownIdentities({ - userIdentities: {customerid: 'id1'}}, - DEVICE_ID +const knownIdentities: IKnownIdentities = createKnownIdentities( + { + userIdentities: { customerid: 'id1' }, + }, + DEVICE_ID, ); const cacheVault = new LocalStorageVault(localStorageIDKey); @@ -41,11 +47,11 @@ const cacheVault = new LocalStorageVault(localStorageIDKey); const identifyResponse: IdentityResultBody = { context: null, matched_identities: { - device_application_stamp: "test-das" + device_application_stamp: 'test-das', }, is_ephemeral: false, mpid: testMPID, - is_logged_in: false + is_logged_in: false, }; const loginResponse: IdentityResultBody = { @@ -57,15 +63,15 @@ const identityResponse: IIdentityResponse = { status: 200, responseText: identifyResponse, cacheMaxAge: 86400, -} +}; describe('identity-utils', () => { - beforeEach(()=> { + beforeEach(() => { window.localStorage.clear(); }); describe('#cacheOrClearIdCache', () => { - afterEach(()=>{ + afterEach(() => { sinon.restore(); }); @@ -79,7 +85,7 @@ describe('identity-utils', () => { knownIdentities, cacheVault, identityResponse, - false + false, ); expect(retrieveSpy.called).to.eq(true); @@ -97,7 +103,7 @@ describe('identity-utils', () => { knownIdentities, cacheVault, identityResponse, - false + false, ); expect(retrieveSpy.called).to.eq(true); @@ -109,15 +115,15 @@ describe('identity-utils', () => { const retrieveSpy = sinon.spy(cacheVault, 'retrieve'); const storeSpy = sinon.spy(cacheVault, 'store'); const purgeSpy = sinon.spy(cacheVault, 'purge'); - + cacheOrClearIdCache( Logout, knownIdentities, cacheVault, identityResponse, - false + false, ); - + expect(retrieveSpy.called).to.eq(false); expect(storeSpy.called).to.eq(false); expect(purgeSpy.called).to.eq(true); @@ -133,7 +139,7 @@ describe('identity-utils', () => { knownIdentities, cacheVault, identityResponse, - true + true, ); expect(retrieveSpy.called).to.eq(false); @@ -154,18 +160,20 @@ describe('identity-utils', () => { knownIdentities, currentTime, cacheVault, - identityResponse + identityResponse, ); const updatedMpIdCache = cacheVault.retrieve(); expect(Object.keys(updatedMpIdCache!).length).to.equal(1); - const cachedKey = - generateHash('identify:device_application_stamp=test-device-id;customerid=id1;'); + const cachedKey = generateHash( + 'identify:device_application_stamp=test-device-id;customerid=id1;', + ); expect(updatedMpIdCache!.hasOwnProperty(cachedKey)).to.equal(true); - const cachedIdentityCall: ICachedIdentityCall = updatedMpIdCache![cachedKey]; + const cachedIdentityCall: ICachedIdentityCall = + updatedMpIdCache![cachedKey]; expect(cachedIdentityCall).hasOwnProperty('responseText'); expect(cachedIdentityCall).hasOwnProperty('status'); @@ -174,16 +182,21 @@ describe('identity-utils', () => { expect(cachedIdentityCall.status).to.equal(200); expect(cachedIdentityCall.expireTimestamp).to.equal(currentTime); - const cachedResponseText = JSON.parse(cachedIdentityCall.responseText); - - const expectedResponseText = {mpid: testMPID, is_logged_in: false}; + const cachedResponseText = JSON.parse( + cachedIdentityCall.responseText, + ); + + const expectedResponseText = { + mpid: testMPID, + is_logged_in: false, + }; expect(cachedResponseText).to.deep.equal(expectedResponseText); }); it('should save a login request to local storage', () => { const mpIdCache = window.localStorage.getItem(localStorageIDKey); expect(mpIdCache).to.equal(null); - + const currentTime = new Date().getTime(); cacheIdentityRequest( @@ -191,18 +204,19 @@ describe('identity-utils', () => { knownIdentities, currentTime, cacheVault, - { ...identityResponse, responseText: loginResponse } + { ...identityResponse, responseText: loginResponse }, ); const updatedMpIdCache = cacheVault.retrieve(); expect(Object.keys(updatedMpIdCache!).length).to.equal(1); - const cachedKey = generateHash('login:device_application_stamp=test-device-id;customerid=id1;'); + const cachedKey = generateHash( + 'login:device_application_stamp=test-device-id;customerid=id1;', + ); expect(updatedMpIdCache!.hasOwnProperty(cachedKey)).to.equal(true); - const cachedLoginCall: ICachedIdentityCall = updatedMpIdCache![ - cachedKey - ]; + const cachedLoginCall: ICachedIdentityCall = + updatedMpIdCache![cachedKey]; expect(cachedLoginCall).hasOwnProperty('responseText'); expect(cachedLoginCall).hasOwnProperty('status'); @@ -212,7 +226,7 @@ describe('identity-utils', () => { expect(cachedLoginCall.expireTimestamp).to.equal(currentTime); const cachedResponseBody = JSON.parse(cachedLoginCall.responseText); - const expectedResponseBody = {mpid: testMPID, is_logged_in: true}; + const expectedResponseBody = { mpid: testMPID, is_logged_in: true }; expect(cachedResponseBody).to.deep.equal(expectedResponseBody); }); }); @@ -244,8 +258,12 @@ describe('identity-utils', () => { yahoo: '06', }; - const key: string = concatenateIdentities('identify', userIdentities); - const expectedResult: string = 'identify:device_application_stamp=first;other=00;customerid=01;facebook=02;twitter=03;google=04;microsoft=05;yahoo=06;email=07;facebookcustomaudienceid=09;other2=10;other3=11;other4=12;other5=13;other6=14;other7=15;other8=16;other9=17;other10=18;mobile_number=19;phone_number_2=20;phone_number_3=21;'; + const key: string = concatenateIdentities( + 'identify', + userIdentities, + ); + const expectedResult = + 'identify:device_application_stamp=first;other=00;customerid=01;facebook=02;twitter=03;google=04;microsoft=05;yahoo=06;email=07;facebookcustomaudienceid=09;other2=10;other3=11;other4=12;other5=13;other6=14;other7=15;other8=16;other9=17;other10=18;mobile_number=19;phone_number_2=20;phone_number_3=21;'; expect(key).to.equal(expectedResult); }); @@ -290,10 +308,16 @@ describe('identity-utils', () => { it('should return false if idCache is empty', () => { const mpIdCache = window.localStorage.getItem(localStorageIDKey); expect(mpIdCache).to.equal(null); - - const cacheVault = new LocalStorageVault(localStorageIDKey); - const result = hasValidCachedIdentity('identify', userIdentities, cacheVault); + const cacheVault = new LocalStorageVault( + localStorageIDKey, + ); + + const result = hasValidCachedIdentity( + 'identify', + userIdentities, + cacheVault, + ); expect(result).to.equal(false); }); @@ -301,10 +325,16 @@ describe('identity-utils', () => { const mpIdCache = window.localStorage.getItem(localStorageIDKey); expect(mpIdCache).to.equal(null); - const cacheVault = new LocalStorageVault(localStorageIDKey); + const cacheVault = new LocalStorageVault( + localStorageIDKey, + ); // check to ensure there is nothing on the cache first - const result1 = hasValidCachedIdentity('identify', userIdentities, cacheVault); + const result1 = hasValidCachedIdentity( + 'identify', + userIdentities, + cacheVault, + ); expect(result1).to.equal(false); const oneDayInMS = 86400 * 60 * 60 * 24; @@ -316,12 +346,16 @@ describe('identity-utils', () => { userIdentities, expireTime, cacheVault, - identityResponse + identityResponse, ); // tick forward less than oneDayInMS clock.tick(5000); - const result2 = hasValidCachedIdentity('identify', userIdentities, cacheVault); + const result2 = hasValidCachedIdentity( + 'identify', + userIdentities, + cacheVault, + ); expect(result2).to.equal(true); }); @@ -338,11 +372,15 @@ describe('identity-utils', () => { userIdentities, expireTime, cacheVault, - identityResponse + identityResponse, ); - clock.tick(oneDayInMS +1); - const result3 = hasValidCachedIdentity('identify', userIdentities, cacheVault); + clock.tick(oneDayInMS + 1); + const result3 = hasValidCachedIdentity( + 'identify', + userIdentities, + cacheVault, + ); expect(result3).to.equal(false); }); }); @@ -372,18 +410,19 @@ describe('identity-utils', () => { mobile_number: 'mobile_number', phone_number_2: 'phone_number_2', phone_number_3: 'phone_number_3', - }}; - + }, + }; + const knownIdentities: IKnownIdentities = createKnownIdentities( identities, - DEVICE_ID + DEVICE_ID, ); - + const expectedResult: IKnownIdentities = { ...identities.userIdentities, device_application_stamp: DEVICE_ID, }; - + expect(knownIdentities).to.deep.equal(expectedResult); }); }); @@ -393,14 +432,20 @@ describe('identity-utils', () => { // set up clock in order to force some time stamps to expire later in the test const clock = sinon.useFakeTimers(); - const cacheVault = new LocalStorageVault(localStorageIDKey); - const knownIdentities1: IKnownIdentities = createKnownIdentities({ - userIdentities: {customerid: 'id1'}}, - DEVICE_ID + const cacheVault = new LocalStorageVault( + localStorageIDKey, + ); + const knownIdentities1: IKnownIdentities = createKnownIdentities( + { + userIdentities: { customerid: 'id1' }, + }, + DEVICE_ID, ); - const knownIdentities2: IKnownIdentities = createKnownIdentities({ - userIdentities: {customerid: 'id2'}}, - DEVICE_ID + const knownIdentities2: IKnownIdentities = createKnownIdentities( + { + userIdentities: { customerid: 'id2' }, + }, + DEVICE_ID, ); // Cache 1st identity response to expire in 1 day @@ -409,7 +454,7 @@ describe('identity-utils', () => { knownIdentities1, MILLISECONDS_IN_ONE_DAY, cacheVault, - identityResponse + identityResponse, ); // Cache 2nd identity response to expire in 1 day + 100ms @@ -418,27 +463,36 @@ describe('identity-utils', () => { knownIdentities2, MILLISECONDS_IN_ONE_DAY + 100, cacheVault, - identityResponse + identityResponse, ); const updatedMpIdCache = cacheVault.retrieve(); - const knownIdentities1CachedKey = - generateHash('identify:device_application_stamp=test-device-id;customerid=id1;'); - const knownIdentities2CachedKey = - generateHash('identify:device_application_stamp=test-device-id;customerid=id2;'); - + const knownIdentities1CachedKey = generateHash( + 'identify:device_application_stamp=test-device-id;customerid=id1;', + ); + const knownIdentities2CachedKey = generateHash( + '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); + 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); + 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); @@ -446,8 +500,12 @@ describe('identity-utils', () => { removeExpiredIdentityCacheDates(cacheVault); const updatedMpIdCache3 = cacheVault.retrieve(); - expect(updatedMpIdCache3!.hasOwnProperty(knownIdentities1CachedKey)).to.equal(false); - expect(updatedMpIdCache3!.hasOwnProperty(knownIdentities2CachedKey)).to.equal(true); + expect( + updatedMpIdCache3!.hasOwnProperty(knownIdentities1CachedKey), + ).to.equal(false); + expect( + updatedMpIdCache3!.hasOwnProperty(knownIdentities2CachedKey), + ).to.equal(true); clock.restore(); }); @@ -458,17 +516,21 @@ describe('identity-utils', () => { window.mParticle._resetForTests(MPConfig); const clock = sinon.useFakeTimers(); - window.mParticle.config.flags = {cacheIdentity: 'True'}; + window.mParticle.config.flags = { cacheIdentity: 'True' }; window.mParticle.init(apiKey, window.mParticle.config); const mpInstance = window.mParticle.getInstance(); - const cacheVault = new LocalStorageVault(localStorageIDKey); + const cacheVault = new LocalStorageVault( + localStorageIDKey, + ); - const customerId = {customerid: 'id1'} - const knownIdentities1: IKnownIdentities = createKnownIdentities({ - userIdentities: customerId}, - DEVICE_ID + const customerId = { customerid: 'id1' }; + const knownIdentities1: IKnownIdentities = createKnownIdentities( + { + userIdentities: customerId, + }, + DEVICE_ID, ); // Cache 1st identity response to expire in 1 day @@ -477,13 +539,13 @@ describe('identity-utils', () => { knownIdentities, MILLISECONDS_IN_ONE_DAY, cacheVault, - identityResponse + identityResponse, ); const identityInstance = new Identity(mpInstance); const identityApiData: IdentityApiData = { - userIdentities: customerId + userIdentities: customerId, }; const callback = sinon.spy(); @@ -494,7 +556,7 @@ describe('identity-utils', () => { testMPID, callback, identityApiData, - 'identify' + 'identify', ); expect(successfullyCachedIdentity).to.equal(true); @@ -506,23 +568,27 @@ describe('identity-utils', () => { window.mParticle._resetForTests(MPConfig); const clock = sinon.useFakeTimers(); - window.mParticle.config.flags = {cacheIdentity: 'True'}; + window.mParticle.config.flags = { cacheIdentity: 'True' }; window.mParticle.init(apiKey, window.mParticle.config); const mpInstance = window.mParticle.getInstance(); - const cacheVault = new LocalStorageVault(localStorageIDKey); + const cacheVault = new LocalStorageVault( + localStorageIDKey, + ); - const customerId = {customerid: 'id1'} - const knownIdentities1: IKnownIdentities = createKnownIdentities({ - userIdentities: customerId}, - DEVICE_ID + const customerId = { customerid: 'id1' }; + const knownIdentities1: IKnownIdentities = createKnownIdentities( + { + userIdentities: customerId, + }, + DEVICE_ID, ); const identityInstance = new Identity(mpInstance); const identityApiData: IdentityApiData = { - userIdentities: customerId + userIdentities: customerId, }; const callback = sinon.spy(); @@ -533,7 +599,7 @@ describe('identity-utils', () => { testMPID, callback, identityApiData, - 'login' + 'login', ); expect(successfullyCachedIdentity).to.equal(false); @@ -542,4 +608,4 @@ describe('identity-utils', () => { clock.restore(); }); }); -}); \ No newline at end of file +}); diff --git a/test/src/tests-identity.ts b/test/src/tests-identity.ts index 5a27e6d58..73ec45856 100644 --- a/test/src/tests-identity.ts +++ b/test/src/tests-identity.ts @@ -2,7 +2,10 @@ import sinon from 'sinon'; import fetchMock from 'fetch-mock/esm/client'; import { expect } from 'chai'; import Utils from './config/utils'; -import Constants, { HTTP_ACCEPTED, HTTP_BAD_REQUEST } from '../../src/constants'; +import Constants, { + HTTP_ACCEPTED, + HTTP_BAD_REQUEST, +} from '../../src/constants'; import { urls, apiKey, @@ -10,11 +13,7 @@ import { MPConfig, workspaceCookieName, } from './config/constants'; -import { - Callback, - IdentityApiData, - UserIdentities, -} from '@mparticle/web-sdk'; +import { Callback, IdentityApiData, UserIdentities } from '@mparticle/web-sdk'; import { IdentityCache } from '../../src/identity-utils'; import { IAliasRequest, @@ -26,7 +25,10 @@ import { IdentityResult, IdentityResultBody, } from '../../src/identity-user-interfaces'; -import { IMParticleInstanceManager, SDKProduct } from '../../src/sdkRuntimeModels'; +import { + IMParticleInstanceManager, + SDKProduct, +} from '../../src/sdkRuntimeModels'; import { IRoktKit } from '../../src/roktManager'; import { IKitConfigs } from '../../src/configAPIClient'; @@ -54,29 +56,29 @@ declare global { const mParticle = window.mParticle as IMParticleInstanceManager; -const BAD_USER_IDENTITIES_AS_STRING = ({ +const BAD_USER_IDENTITIES_AS_STRING = { userIdentities: 'badUserIdentitiesString', -} as unknown) as IdentityApiData; +} as unknown as IdentityApiData; -const BAD_USER_IDENTITIES_AS_ARRAY = ({ +const BAD_USER_IDENTITIES_AS_ARRAY = { userIdentities: ['bad', 'user', 'identities', 'array'], -} as unknown) as IdentityApiData; +} as unknown as IdentityApiData; -const BAD_USER_IDENTITIES_AS_NULL = ({ +const BAD_USER_IDENTITIES_AS_NULL = { userIdentities: null, -} as unknown) as IdentityApiData; +} as unknown as IdentityApiData; -const BAD_USER_IDENTITIES_AS_UNDEFINED = ({ +const BAD_USER_IDENTITIES_AS_UNDEFINED = { userIdentities: undefined, -} as unknown) as IdentityApiData; +} as unknown as IdentityApiData; -const BAD_USER_IDENTITIES_AS_BOOLEAN = ({ +const BAD_USER_IDENTITIES_AS_BOOLEAN = { userIdentities: true, -} as unknown) as IdentityApiData; +} as unknown as IdentityApiData; -const BadCallbackAsString = ('badCallbackString' as unknown) as Callback; +const BadCallbackAsString = 'badCallbackString' as unknown as Callback; -const EmptyUserIdentities = ({} as unknown) as IdentityApiData; +const EmptyUserIdentities = {} as unknown as IdentityApiData; const fetchMockSuccess = (url: string, body: any = {}, headers: any = {}) => { fetchMock.post( @@ -86,20 +88,20 @@ const fetchMockSuccess = (url: string, body: any = {}, headers: any = {}) => { body: JSON.stringify(body), headers, }, - { overwriteRoutes: true } + { overwriteRoutes: true }, ); }; -describe('identity', function() { +describe('identity', function () { let clock; let hasIdentifyReturned; let hasIdentifyReturnedWithEmail; let hasLoginReturned; let hasLogOutReturned; let beforeEachCallbackCalled = false; - let hasBeforeEachCallbackReturned + let hasBeforeEachCallbackReturned; - beforeEach(function() { + beforeEach(function () { delete mParticle.config.useCookieStorage; fetchMockSuccess(urls.events); fetchMockSuccess(urls.identify, { @@ -113,7 +115,7 @@ describe('identity', function() { }); localStorage.clear(); - mParticle.config.identityCallback = function() { + mParticle.config.identityCallback = function () { // There are some tests that need to verify that the initial init // call within the beforeEach method has completed before they // can introduce a new identityCallback for their specific assertions. @@ -127,7 +129,10 @@ describe('identity', function() { }; hasIdentifyReturnedWithEmail = (email = 'test@email.com') => { - return mParticle.Identity.getCurrentUser()?.getUserIdentities()?.userIdentities?.email === email; + return ( + mParticle.Identity.getCurrentUser()?.getUserIdentities() + ?.userIdentities?.email === email + ); }; hasLoginReturned = () => { @@ -145,7 +150,6 @@ describe('identity', function() { }; hasBeforeEachCallbackReturned = () => beforeEachCallbackCalled; - }); afterEach(function () { @@ -157,16 +161,16 @@ describe('identity', function() { } }); - describe('requests', function() { + describe('requests', function () { it('should contain identify request', async () => { fetchMockSuccess(urls.logout, { - context: null, - matched_identities: { - device_application_stamp: 'my-das', - }, - is_ephemeral: true, - mpid: testMPID, - is_logged_in: false, + context: null, + matched_identities: { + device_application_stamp: 'my-das', + }, + is_ephemeral: true, + mpid: testMPID, + is_logged_in: false, }); mParticle.Identity.identify({ @@ -175,7 +179,7 @@ describe('identity', function() { }, }); - await waitForCondition(hasIdentifyReturned) + await waitForCondition(hasIdentifyReturned); // Calls should be expected // 1. Identify @@ -186,7 +190,9 @@ describe('identity', function() { const firstCall = fetchMock.calls()[0]; expect(firstCall[0].split('/')[4]).to.equal('identify'); - const data = JSON.parse(firstCall[1].body as unknown as string) as IIdentityAPIRequestData; + const data = JSON.parse( + firstCall[1].body as unknown as string, + ) as IIdentityAPIRequestData; expect(data).to.have.keys( 'client_sdk', @@ -195,17 +201,16 @@ describe('identity', function() { 'previous_mpid', 'request_id', 'request_timestamp_ms', - 'context' + 'context', ); expect(data.previous_mpid).to.equal(null); expect(data.known_identities).to.have.property( - 'device_application_stamp' + 'device_application_stamp', ); }); - it('should contain logout request', async () => { fetchMockSuccess(urls.logout, { context: null, @@ -217,7 +222,7 @@ describe('identity', function() { is_logged_in: false, }); - await waitForCondition(hasIdentifyReturned) + await waitForCondition(hasIdentifyReturned); mParticle.Identity.logout(); @@ -231,7 +236,9 @@ describe('identity', function() { const lastCall = fetchMock.lastCall(); expect(lastCall[0].split('/')[4]).to.equal('logout'); - const data: IIdentityAPIRequestData = JSON.parse(lastCall[1].body as unknown as string); + const data: IIdentityAPIRequestData = JSON.parse( + lastCall[1].body as unknown as string, + ); expect(data).to.have.keys( 'client_sdk', @@ -240,27 +247,27 @@ describe('identity', function() { 'previous_mpid', 'request_id', 'request_timestamp_ms', - 'context' + 'context', ); expect(data.previous_mpid).to.equal(testMPID); expect(data.known_identities).to.have.property( - 'device_application_stamp' + 'device_application_stamp', ); }); it('should contain login request', async () => { - await waitForCondition(hasIdentifyReturned) + await waitForCondition(hasIdentifyReturned); fetchMockSuccess(urls.login, { - mpid: testMPID, - is_logged_in: false, - context: null, - matched_identities: { - email: 'abc@gmail.com', - }, - is_ephemeral: false, + mpid: testMPID, + is_logged_in: false, + context: null, + matched_identities: { + email: 'abc@gmail.com', + }, + is_ephemeral: false, }); mParticle.Identity.login({ @@ -269,20 +276,22 @@ describe('identity', function() { }, }); - await waitForCondition(hasIdentityCallInflightReturned) + await waitForCondition(hasIdentityCallInflightReturned); // Calls that should be expected: // 1. Identify // 2. Session Start // 3. AST - // 4. Login + // 4. Login // 5. UIC expect(fetchMock.calls().length).to.equal(5); const loginCall = fetchMock.calls()[3]; expect(loginCall[0].split('/')[4]).to.equal('login'); - const data: IIdentityAPIRequestData = JSON.parse(loginCall[1].body as unknown as string); + const data: IIdentityAPIRequestData = JSON.parse( + loginCall[1].body as unknown as string, + ); expect(data).to.have.keys( 'client_sdk', @@ -291,33 +300,32 @@ describe('identity', function() { 'previous_mpid', 'request_id', 'request_timestamp_ms', - 'context' + 'context', ); expect(data.previous_mpid).to.equal(testMPID); expect(data.known_identities).to.have.property( 'email', - 'test@email.com' + 'test@email.com', ); expect(data.known_identities).to.have.property( - 'device_application_stamp' + 'device_application_stamp', ); }); - it('should contain modify request', async () => { fetchMockSuccess(urls.modify, { - change_results: [ - { - identity_type: 'email', - modified_mpid: testMPID, - }, - ], + change_results: [ + { + identity_type: 'email', + modified_mpid: testMPID, + }, + ], }); - await waitForCondition(hasIdentifyReturned) + await waitForCondition(hasIdentifyReturned); mParticle.Identity.modify({ userIdentities: { email: 'test@email.com', @@ -334,7 +342,9 @@ describe('identity', function() { const lastCall = fetchMock.lastCall(); expect(lastCall[0].split('/')[5]).to.equal('modify'); - const data: IIdentityAPIModifyRequestData = JSON.parse(lastCall[1].body as unknown as string); + const data: IIdentityAPIModifyRequestData = JSON.parse( + lastCall[1].body as unknown as string, + ); expect(data).to.have.keys( 'client_sdk', @@ -342,7 +352,7 @@ describe('identity', function() { 'identity_changes', 'request_id', 'request_timestamp_ms', - 'context' + 'context', ); expect(data.identity_changes).to.deep.equal([ @@ -367,9 +377,7 @@ describe('identity', function() { is_logged_in: false, }); - let data: IIdentityAPIRequestData; - - await waitForCondition(hasIdentifyReturned) + await waitForCondition(hasIdentifyReturned); mParticle.Identity.identify({ userIdentities: { @@ -377,7 +385,7 @@ describe('identity', function() { }, }); - await waitForCondition(hasIdentifyReturned) + await waitForCondition(hasIdentifyReturned); // 4 Calls should be expected // 1. Identify @@ -389,8 +397,8 @@ describe('identity', function() { const lastCall = fetchMock.lastCall(); expect(lastCall[0].split('/')[4]).to.equal('identify'); - data = JSON.parse( - lastCall[1].body as unknown as string + const data = JSON.parse( + lastCall[1].body as unknown as string, ) as IIdentityAPIRequestData; expect(data).to.have.keys( @@ -400,16 +408,15 @@ describe('identity', function() { 'previous_mpid', 'request_id', 'request_timestamp_ms', - 'context' + 'context', ); expect(data.previous_mpid).to.equal(testMPID); expect(data.known_identities).to.have.property( - 'device_application_stamp' + 'device_application_stamp', ); }); - }); // https://go.mparticle.com/work/SQDSDKS-6849 @@ -426,7 +433,7 @@ describe('identity', function() { values: [ { consentPurpose: mParticle.generateHash( - '1' + 'foo purpose 1' + '1' + 'foo purpose 1', ), hasConsented: true, }, @@ -442,7 +449,7 @@ describe('identity', function() { values: [ { consentPurpose: mParticle.generateHash( - '1' + 'foo purpose 2' + '1' + 'foo purpose 2', ), hasConsented: true, }, @@ -459,7 +466,9 @@ describe('identity', function() { mParticle.init(apiKey, window.mParticle.config); - await waitForCondition( () => mParticle.Identity.getCurrentUser()?.getMPID() === 'MPID1') + await waitForCondition( + () => mParticle.Identity.getCurrentUser()?.getMPID() === 'MPID1', + ); let activeForwarders = mParticle.getInstance()._getActiveForwarders(); expect(activeForwarders.length).to.equal(0); @@ -467,7 +476,7 @@ describe('identity', function() { let consentState = mParticle.Consent.createConsentState(); consentState.addGDPRConsentState( 'foo purpose 1', - mParticle.Consent.createGDPRConsent(true) + mParticle.Consent.createGDPRConsent(true), ); mParticle.Identity.getCurrentUser().setConsentState(consentState); @@ -482,7 +491,7 @@ describe('identity', function() { mParticle.Identity.login(); - await waitForCondition(hasIdentityCallInflightReturned) + await waitForCondition(hasIdentityCallInflightReturned); activeForwarders = mParticle.getInstance()._getActiveForwarders(); expect(activeForwarders.length).to.equal(0); @@ -490,7 +499,7 @@ describe('identity', function() { consentState = mParticle.Consent.createConsentState(); consentState.addGDPRConsentState( 'foo purpose 2', - mParticle.Consent.createGDPRConsent(true) + mParticle.Consent.createGDPRConsent(true), ); mParticle.Identity.getCurrentUser().setConsentState(consentState); @@ -500,607 +509,703 @@ describe('identity', function() { }); describe('cookies', function () { - it('should store all MPIDs associated with a sessionId, then clear MPIDs from currentSessionMPIDs when a new session starts', async () => { - await waitForCondition(hasIdentifyReturned) + it('should store all MPIDs associated with a sessionId, then clear MPIDs from currentSessionMPIDs when a new session starts', async () => { + await waitForCondition(hasIdentifyReturned); - fetchMockSuccess(urls.login, { - mpid: 'logged-in-user', - is_logged_in: true, - }); - - const userIdentities1 = { - userIdentities: { - customerid: 'foo1', - }, - }; - - mParticle.Identity.login(userIdentities1); - await waitForCondition(hasLoginReturned) + fetchMockSuccess(urls.login, { + mpid: 'logged-in-user', + is_logged_in: true, + }); - const localStorageDataBeforeSessionEnd = mParticle - .getInstance() - ._Persistence.getLocalStorage(); + const userIdentities1 = { + userIdentities: { + customerid: 'foo1', + }, + }; - localStorageDataBeforeSessionEnd.gs.csm.length.should.equal(2); + mParticle.Identity.login(userIdentities1); + await waitForCondition(hasLoginReturned); - mParticle.endSession(); - const localStorageDataAfterSessionEnd1 = mParticle - .getInstance() - ._Persistence.getLocalStorage(); - localStorageDataAfterSessionEnd1.gs.should.not.have.property('csm'); + const localStorageDataBeforeSessionEnd = mParticle + .getInstance() + ._Persistence.getLocalStorage(); - mParticle.logEvent('hi'); - mParticle.Identity.login(userIdentities1); + localStorageDataBeforeSessionEnd.gs.csm.length.should.equal(2); - await waitForCondition(hasIdentityCallInflightReturned) + mParticle.endSession(); + const localStorageDataAfterSessionEnd1 = mParticle + .getInstance() + ._Persistence.getLocalStorage(); + localStorageDataAfterSessionEnd1.gs.should.not.have.property('csm'); - const localStorageAfterLoggingEvent = mParticle - .getInstance() - ._Persistence.getLocalStorage(); - localStorageAfterLoggingEvent.gs.csm.length.should.equal(1); - }); + mParticle.logEvent('hi'); + mParticle.Identity.login(userIdentities1); - it('localStorage - should switch user cookies to new mpid details from cookies when a new mpid is provided', async () => { - mParticle._resetForTests(MPConfig); - window.mParticle.config.useCookieStorage = false; + await waitForCondition(hasIdentityCallInflightReturned); - setLocalStorage(); + const localStorageAfterLoggingEvent = mParticle + .getInstance() + ._Persistence.getLocalStorage(); + localStorageAfterLoggingEvent.gs.csm.length.should.equal(1); + }); - mParticle.init(apiKey, window.mParticle.config); + it('localStorage - should switch user cookies to new mpid details from cookies when a new mpid is provided', async () => { + mParticle._resetForTests(MPConfig); + window.mParticle.config.useCookieStorage = false; - const cookies1 = mParticle.getInstance()._Persistence.getLocalStorage(); - cookies1.cu.should.equal(testMPID); - cookies1[testMPID].should.have.property('csd'); + setLocalStorage(); - fetchMockSuccess(urls.login, { - mpid: 'logged-in-user', - is_logged_in: true, - }); + mParticle.init(apiKey, window.mParticle.config); - const userIdentities1 = { - userIdentities: { - customerid: 'foo1', - }, - }; + const cookies1 = mParticle + .getInstance() + ._Persistence.getLocalStorage(); + cookies1.cu.should.equal(testMPID); + cookies1[testMPID].should.have.property('csd'); - mParticle.Identity.login(userIdentities1); - await waitForCondition(hasLoginReturned) - const cookiesAfterMPIDChange = mParticle - .getInstance() - ._Persistence.getLocalStorage(); + fetchMockSuccess(urls.login, { + mpid: 'logged-in-user', + is_logged_in: true, + }); - expect(cookiesAfterMPIDChange).to.have.all.keys([ - 'l', - 'cu', - 'logged-in-user', - testMPID, - 'gs', - ]); - expect(cookiesAfterMPIDChange).to.have.property('cu', 'logged-in-user'); - expect(cookiesAfterMPIDChange[testMPID]).to.have.property('csd'); - - const props = [ - 'ie', - 'sa', - 'ss', - 'dt', - 'les', - 'av', - 'cgid', - 'das', - 'sid', - 'c', - 'mpid', - 'cp', - ]; + const userIdentities1 = { + userIdentities: { + customerid: 'foo1', + }, + }; - props.forEach(function(prop) { - expect(cookiesAfterMPIDChange[testMPID]).to.not.have.property(prop); - expect(cookiesAfterMPIDChange['logged-in-user']).to.not.have.property( - prop + mParticle.Identity.login(userIdentities1); + await waitForCondition(hasLoginReturned); + const cookiesAfterMPIDChange = mParticle + .getInstance() + ._Persistence.getLocalStorage(); + + expect(cookiesAfterMPIDChange).to.have.all.keys([ + 'l', + 'cu', + 'logged-in-user', + testMPID, + 'gs', + ]); + expect(cookiesAfterMPIDChange).to.have.property( + 'cu', + 'logged-in-user', ); + expect(cookiesAfterMPIDChange[testMPID]).to.have.property('csd'); + + const props = [ + 'ie', + 'sa', + 'ss', + 'dt', + 'les', + 'av', + 'cgid', + 'das', + 'sid', + 'c', + 'mpid', + 'cp', + ]; + + props.forEach(function (prop) { + expect(cookiesAfterMPIDChange[testMPID]).to.not.have.property( + prop, + ); + expect( + cookiesAfterMPIDChange['logged-in-user'], + ).to.not.have.property(prop); + }); }); - }); - - it('cookies - should switch user cookies to new mpid details from cookies when a new mpid is provided', async () => { - mParticle._resetForTests(MPConfig); - mParticle.config.useCookieStorage = true; - - setLocalStorage(); - - mParticle.init(apiKey, window.mParticle.config); - await waitForCondition(hasIdentifyReturned) - - const cookiesAfterInit = findCookie(); - cookiesAfterInit.should.have.properties('gs', 'cu', testMPID); + it('cookies - should switch user cookies to new mpid details from cookies when a new mpid is provided', async () => { + mParticle._resetForTests(MPConfig); + mParticle.config.useCookieStorage = true; - const props1 = [ - 'mpid', - 'ui', - 'ua', - 'les', - 'sid', - 'ie', - 'dt', - 'sa', - 'ss', - 'cp', - ]; + setLocalStorage(); - props1.forEach(function(prop) { - cookiesAfterInit.should.not.have.property(prop); - }); + mParticle.init(apiKey, window.mParticle.config); - fetchMockSuccess(urls.login, { - mpid: 'logged-in-user', - is_logged_in: true, - }); + await waitForCondition(hasIdentifyReturned); + + const cookiesAfterInit = findCookie(); + cookiesAfterInit.should.have.properties('gs', 'cu', testMPID); + + const props1 = [ + 'mpid', + 'ui', + 'ua', + 'les', + 'sid', + 'ie', + 'dt', + 'sa', + 'ss', + 'cp', + ]; + + props1.forEach(function (prop) { + cookiesAfterInit.should.not.have.property(prop); + }); - const userIdentities1 = { - userIdentities: { - customerid: 'foo1', - }, - }; + fetchMockSuccess(urls.login, { + mpid: 'logged-in-user', + is_logged_in: true, + }); - mParticle.Identity.login(userIdentities1); + const userIdentities1 = { + userIdentities: { + customerid: 'foo1', + }, + }; - await waitForCondition(hasLoginReturned) + mParticle.Identity.login(userIdentities1); - const cookiesAfterMPIDChange = findCookie(); - cookiesAfterMPIDChange.should.have.properties([ - 'cu', - 'gs', - 'logged-in-user', - testMPID, - ]); - cookiesAfterMPIDChange.should.have.property('cu', 'logged-in-user'); - - const props2 = [ - 'ie', - 'sa', - 'ss', - 'dt', - 'les', - 'av', - 'cgid', - 'das', - 'sid', - 'c', - 'mpid', - 'cp', - ]; + await waitForCondition(hasLoginReturned); - props2.forEach(function(prop) { - cookiesAfterMPIDChange[testMPID].should.not.have.property(prop); - cookiesAfterMPIDChange['logged-in-user'].should.not.have.property(prop); + const cookiesAfterMPIDChange = findCookie(); + cookiesAfterMPIDChange.should.have.properties([ + 'cu', + 'gs', + 'logged-in-user', + testMPID, + ]); + cookiesAfterMPIDChange.should.have.property('cu', 'logged-in-user'); + + const props2 = [ + 'ie', + 'sa', + 'ss', + 'dt', + 'les', + 'av', + 'cgid', + 'das', + 'sid', + 'c', + 'mpid', + 'cp', + ]; + + props2.forEach(function (prop) { + cookiesAfterMPIDChange[testMPID].should.not.have.property(prop); + cookiesAfterMPIDChange[ + 'logged-in-user' + ].should.not.have.property(prop); + }); }); }); -}); - describe('identity request validation', function () { - it('should swap property identityType for identityName', function (done) { - const data: IdentityApiData = { userIdentities: {} }; - data.userIdentities.other = 'id1'; - data.userIdentities.customerid = 'id2'; - data.userIdentities.facebook = 'id3'; - data.userIdentities.twitter = 'id4'; - data.userIdentities.google = 'id5'; - data.userIdentities.microsoft = 'id6'; - data.userIdentities.yahoo = 'id7'; - data.userIdentities.email = 'id8'; - data.userIdentities.facebookcustomaudienceid = 'id9'; - data.userIdentities.other2 = 'id10'; - data.userIdentities.other3 = 'id11'; - data.userIdentities.other4 = 'id12'; - - let count = 0; - for (const key in data.userIdentities) { - // https://go.mparticle.com/work/SQDSDKS-6473 - expect(mParticle.IdentityType.getIdentityType(key)).to.equal(count); - count++; - // 8 is alias, which was removed - if (count === 8) { - count = 9; + it('should swap property identityType for identityName', function (done) { + const data: IdentityApiData = { userIdentities: {} }; + data.userIdentities.other = 'id1'; + data.userIdentities.customerid = 'id2'; + data.userIdentities.facebook = 'id3'; + data.userIdentities.twitter = 'id4'; + data.userIdentities.google = 'id5'; + data.userIdentities.microsoft = 'id6'; + data.userIdentities.yahoo = 'id7'; + data.userIdentities.email = 'id8'; + data.userIdentities.facebookcustomaudienceid = 'id9'; + data.userIdentities.other2 = 'id10'; + data.userIdentities.other3 = 'id11'; + data.userIdentities.other4 = 'id12'; + + let count = 0; + for (const key in data.userIdentities) { + // https://go.mparticle.com/work/SQDSDKS-6473 + expect(mParticle.IdentityType.getIdentityType(key)).to.equal( + count, + ); + count++; + // 8 is alias, which was removed + if (count === 8) { + count = 9; + } } - } - - done(); - }); - - it('should create a proper identity request', async (done) => { - const data: IdentityApiData = { userIdentities: {} }, - platform = 'web', - sdkVendor = 'mparticle', - sdkVersion = '1.0.0', - deviceId = 'abc', - context = null; - - data.userIdentities.other = 'id1'; - data.userIdentities.customerid = 'id2'; - data.userIdentities.facebook = 'id3'; - data.userIdentities.twitter = 'id4'; - data.userIdentities.google = 'id5'; - data.userIdentities.microsoft = 'id6'; - data.userIdentities.yahoo = 'id7'; - data.userIdentities.email = 'id8'; - data.userIdentities.facebookcustomaudienceid = 'id9'; - data.userIdentities.other2 = 'id10'; - data.userIdentities.other3 = 'id11'; - data.userIdentities.other4 = 'id12'; - data.userIdentities.other5 = 'id13'; - data.userIdentities.other6 = 'id14'; - data.userIdentities.other7 = 'id15'; - data.userIdentities.other8 = 'id16'; - data.userIdentities.other9 = 'id17'; - data.userIdentities.other10 = 'id18'; - data.userIdentities.mobile_number = 'id19'; - data.userIdentities.phone_number_2 = 'id20'; - data.userIdentities.phone_number_3 = 'id21'; - const identityRequest = mParticle - .getInstance() - ._Identity.IdentityRequest.createIdentityRequest( - data, - platform, - sdkVendor, - sdkVersion, - deviceId, - context, - testMPID - ); - - expect(identityRequest).to.have.all.keys([ - 'client_sdk', - 'context', - 'environment', - 'known_identities', - 'previous_mpid', - 'request_id', - 'request_timestamp_ms', - ]); + done(); + }); - expect(identityRequest.client_sdk).to.have.all.keys([ - 'platform', - 'sdk_vendor', - 'sdk_version', - ]); + it('should create a proper identity request', async (done) => { + const data: IdentityApiData = { userIdentities: {} }, + platform = 'web', + sdkVendor = 'mparticle', + sdkVersion = '1.0.0', + deviceId = 'abc', + context = null; + + data.userIdentities.other = 'id1'; + data.userIdentities.customerid = 'id2'; + data.userIdentities.facebook = 'id3'; + data.userIdentities.twitter = 'id4'; + data.userIdentities.google = 'id5'; + data.userIdentities.microsoft = 'id6'; + data.userIdentities.yahoo = 'id7'; + data.userIdentities.email = 'id8'; + data.userIdentities.facebookcustomaudienceid = 'id9'; + data.userIdentities.other2 = 'id10'; + data.userIdentities.other3 = 'id11'; + data.userIdentities.other4 = 'id12'; + data.userIdentities.other5 = 'id13'; + data.userIdentities.other6 = 'id14'; + data.userIdentities.other7 = 'id15'; + data.userIdentities.other8 = 'id16'; + data.userIdentities.other9 = 'id17'; + data.userIdentities.other10 = 'id18'; + data.userIdentities.mobile_number = 'id19'; + data.userIdentities.phone_number_2 = 'id20'; + data.userIdentities.phone_number_3 = 'id21'; + + const identityRequest = mParticle + .getInstance() + ._Identity.IdentityRequest.createIdentityRequest( + data, + platform, + sdkVendor, + sdkVersion, + deviceId, + context, + testMPID, + ); - expect(identityRequest.client_sdk.platform).to.equal(platform); - expect(identityRequest.client_sdk.sdk_vendor).to.equal(sdkVendor); - expect(identityRequest.environment).to.equal('production'); - expect(identityRequest.previous_mpid).to.equal(testMPID); + expect(identityRequest).to.have.all.keys([ + 'client_sdk', + 'context', + 'environment', + 'known_identities', + 'previous_mpid', + 'request_id', + 'request_timestamp_ms', + ]); - expect(identityRequest.known_identities).to.have.all.keys([ - 'other', - 'customerid', - 'facebook', - 'twitter', - 'google', - 'microsoft', - 'yahoo', - 'email', - 'facebookcustomaudienceid', - 'other2', - 'other3', - 'other4', - 'other5', - 'other6', - 'other7', - 'other8', - 'other9', - 'other10', - 'phone_number_2', - 'phone_number_3', - 'mobile_number', - 'device_application_stamp', - ]); + expect(identityRequest.client_sdk).to.have.all.keys([ + 'platform', + 'sdk_vendor', + 'sdk_version', + ]); - expect(identityRequest.known_identities.other).to.equal('id1'); - expect(identityRequest.known_identities.customerid).to.equal('id2'); - expect(identityRequest.known_identities.facebook).to.equal('id3'); - expect(identityRequest.known_identities.twitter).to.equal('id4'); - expect(identityRequest.known_identities.google).to.equal('id5'); - expect(identityRequest.known_identities.microsoft).to.equal('id6'); - expect(identityRequest.known_identities.yahoo).to.equal('id7'); - expect(identityRequest.known_identities.email).to.equal('id8'); - expect( - identityRequest.known_identities.facebookcustomaudienceid - ).to.equal('id9'); - expect(identityRequest.known_identities.other2).to.equal('id10'); - expect(identityRequest.known_identities.other3).to.equal('id11'); - expect(identityRequest.known_identities.other4).to.equal('id12'); - expect(identityRequest.known_identities.other5).to.equal('id13'); - expect(identityRequest.known_identities.other6).to.equal('id14'); - expect(identityRequest.known_identities.other7).to.equal('id15'); - expect(identityRequest.known_identities.other8).to.equal('id16'); - expect(identityRequest.known_identities.other9).to.equal('id17'); - expect(identityRequest.known_identities.other10).to.equal('id18'); - expect(identityRequest.known_identities.mobile_number).to.equal('id19'); - expect(identityRequest.known_identities.phone_number_2).to.equal( - 'id20' - ); - expect(identityRequest.known_identities.phone_number_3).to.equal( - 'id21' - ); + expect(identityRequest.client_sdk.platform).to.equal(platform); + expect(identityRequest.client_sdk.sdk_vendor).to.equal(sdkVendor); + expect(identityRequest.environment).to.equal('production'); + expect(identityRequest.previous_mpid).to.equal(testMPID); + + expect(identityRequest.known_identities).to.have.all.keys([ + 'other', + 'customerid', + 'facebook', + 'twitter', + 'google', + 'microsoft', + 'yahoo', + 'email', + 'facebookcustomaudienceid', + 'other2', + 'other3', + 'other4', + 'other5', + 'other6', + 'other7', + 'other8', + 'other9', + 'other10', + 'phone_number_2', + 'phone_number_3', + 'mobile_number', + 'device_application_stamp', + ]); - done(); - }); + expect(identityRequest.known_identities.other).to.equal('id1'); + expect(identityRequest.known_identities.customerid).to.equal('id2'); + expect(identityRequest.known_identities.facebook).to.equal('id3'); + expect(identityRequest.known_identities.twitter).to.equal('id4'); + expect(identityRequest.known_identities.google).to.equal('id5'); + expect(identityRequest.known_identities.microsoft).to.equal('id6'); + expect(identityRequest.known_identities.yahoo).to.equal('id7'); + expect(identityRequest.known_identities.email).to.equal('id8'); + expect( + identityRequest.known_identities.facebookcustomaudienceid, + ).to.equal('id9'); + expect(identityRequest.known_identities.other2).to.equal('id10'); + expect(identityRequest.known_identities.other3).to.equal('id11'); + expect(identityRequest.known_identities.other4).to.equal('id12'); + expect(identityRequest.known_identities.other5).to.equal('id13'); + expect(identityRequest.known_identities.other6).to.equal('id14'); + expect(identityRequest.known_identities.other7).to.equal('id15'); + expect(identityRequest.known_identities.other8).to.equal('id16'); + expect(identityRequest.known_identities.other9).to.equal('id17'); + expect(identityRequest.known_identities.other10).to.equal('id18'); + expect(identityRequest.known_identities.mobile_number).to.equal( + 'id19', + ); + expect(identityRequest.known_identities.phone_number_2).to.equal( + 'id20', + ); + expect(identityRequest.known_identities.phone_number_3).to.equal( + 'id21', + ); - it('should create a proper modify identity request', async (done) => { - const platform = 'web'; - const sdkVendor = 'mparticle'; - const sdkVersion = '1.0.0'; - const context = null; + done(); + }); - const oldIdentities: UserIdentities = {}; - oldIdentities['other'] = 'id1'; - oldIdentities['customerid'] = 'id2'; - oldIdentities['facebook'] = 'id3'; - oldIdentities['twitter'] = 'id4'; - oldIdentities['google'] = 'id5'; - oldIdentities['microsoft'] = 'id6'; - oldIdentities['yahoo'] = 'id7'; - oldIdentities['email'] = 'id8'; - oldIdentities['facebookcustomaudienceid'] = 'id9'; - oldIdentities['other2'] = 'id11'; - oldIdentities['other3'] = 'id12'; - oldIdentities['other4'] = 'id13'; - oldIdentities['other5'] = 'id14'; - oldIdentities['other6'] = 'id15'; - oldIdentities['other7'] = 'id16'; - oldIdentities['other8'] = 'id17'; - oldIdentities['other9'] = 'id18'; - oldIdentities['other10'] = 'id19'; - oldIdentities['mobile_number'] = 'id20'; - oldIdentities['phone_number_2'] = 'id21'; - oldIdentities['phone_number_3'] = 'id22'; + it('should create a proper modify identity request', async (done) => { + const platform = 'web'; + const sdkVendor = 'mparticle'; + const sdkVersion = '1.0.0'; + const context = null; + + const oldIdentities: UserIdentities = {}; + oldIdentities['other'] = 'id1'; + oldIdentities['customerid'] = 'id2'; + oldIdentities['facebook'] = 'id3'; + oldIdentities['twitter'] = 'id4'; + oldIdentities['google'] = 'id5'; + oldIdentities['microsoft'] = 'id6'; + oldIdentities['yahoo'] = 'id7'; + oldIdentities['email'] = 'id8'; + oldIdentities['facebookcustomaudienceid'] = 'id9'; + oldIdentities['other2'] = 'id11'; + oldIdentities['other3'] = 'id12'; + oldIdentities['other4'] = 'id13'; + oldIdentities['other5'] = 'id14'; + oldIdentities['other6'] = 'id15'; + oldIdentities['other7'] = 'id16'; + oldIdentities['other8'] = 'id17'; + oldIdentities['other9'] = 'id18'; + oldIdentities['other10'] = 'id19'; + oldIdentities['mobile_number'] = 'id20'; + oldIdentities['phone_number_2'] = 'id21'; + oldIdentities['phone_number_3'] = 'id22'; + + const newIdentities: UserIdentities = {}; + newIdentities.other = 'id14'; + newIdentities.customerid = 'id15'; + newIdentities.facebook = 'id16'; + newIdentities.twitter = 'id17'; + newIdentities.google = 'id18'; + newIdentities.microsoft = 'id19'; + newIdentities.yahoo = 'id20'; + newIdentities.email = 'id21'; + newIdentities.facebookcustomaudienceid = 'id22'; + newIdentities.other2 = 'id23'; + newIdentities.other3 = 'id24'; + newIdentities.other4 = 'id25'; + newIdentities.other5 = 'id26'; + newIdentities.other6 = 'id27'; + newIdentities.other7 = 'id28'; + newIdentities.other8 = 'id29'; + newIdentities.other9 = 'id30'; + newIdentities.other10 = 'id31'; + newIdentities.mobile_number = 'id32'; + newIdentities.phone_number_2 = 'id33'; + newIdentities.phone_number_3 = 'id34'; + + const identityRequest = mParticle + .getInstance() + ._Identity.IdentityRequest.createModifyIdentityRequest( + oldIdentities, + newIdentities, + platform, + sdkVendor, + sdkVersion, + context, + ); - const newIdentities: UserIdentities = {}; - newIdentities.other = 'id14'; - newIdentities.customerid = 'id15'; - newIdentities.facebook = 'id16'; - newIdentities.twitter = 'id17'; - newIdentities.google = 'id18'; - newIdentities.microsoft = 'id19'; - newIdentities.yahoo = 'id20'; - newIdentities.email = 'id21'; - newIdentities.facebookcustomaudienceid = 'id22'; - newIdentities.other2 = 'id23'; - newIdentities.other3 = 'id24'; - newIdentities.other4 = 'id25'; - newIdentities.other5 = 'id26'; - newIdentities.other6 = 'id27'; - newIdentities.other7 = 'id28'; - newIdentities.other8 = 'id29'; - newIdentities.other9 = 'id30'; - newIdentities.other10 = 'id31'; - newIdentities.mobile_number = 'id32'; - newIdentities.phone_number_2 = 'id33'; - newIdentities.phone_number_3 = 'id34'; + expect(identityRequest).to.have.all.keys([ + 'client_sdk', + 'context', + 'environment', + 'identity_changes', + 'request_id', + 'request_timestamp_ms', + ]); + expect(identityRequest.client_sdk).to.have.all.keys([ + 'platform', + 'sdk_vendor', + 'sdk_version', + ]); + expect(identityRequest.client_sdk.platform).to.equal('web'); + expect(identityRequest.client_sdk.sdk_vendor).to.equal('mparticle'); + expect(identityRequest.environment).to.equal('production'); + expect(identityRequest.identity_changes.length).to.equal(21); - const identityRequest = mParticle - .getInstance() - ._Identity.IdentityRequest.createModifyIdentityRequest( - oldIdentities, - newIdentities, - platform, - sdkVendor, - sdkVersion, - context + expect(identityRequest.identity_changes[0]).to.have.all.keys([ + 'identity_type', + 'new_value', + 'old_value', + ]); + expect(identityRequest.identity_changes[0].old_value).to.equal( + 'id1', + ); + expect(identityRequest.identity_changes[0].identity_type).to.equal( + 'other', + ); + expect(identityRequest.identity_changes[0].new_value).to.equal( + 'id14', ); - expect(identityRequest).to.have.all.keys([ - 'client_sdk', - 'context', - 'environment', - 'identity_changes', - 'request_id', - 'request_timestamp_ms', - ]); - expect(identityRequest.client_sdk).to.have.all.keys([ - 'platform', - 'sdk_vendor', - 'sdk_version', - ]); - expect(identityRequest.client_sdk.platform).to.equal('web'); - expect(identityRequest.client_sdk.sdk_vendor).to.equal('mparticle'); - expect(identityRequest.environment).to.equal('production'); - expect(identityRequest.identity_changes.length).to.equal(21); - - expect(identityRequest.identity_changes[0]).to.have.all.keys([ - 'identity_type', - 'new_value', - 'old_value', - ]); - expect(identityRequest.identity_changes[0].old_value).to.equal('id1'); - expect(identityRequest.identity_changes[0].identity_type).to.equal( - 'other' - ); - expect(identityRequest.identity_changes[0].new_value).to.equal('id14'); - - expect(identityRequest.identity_changes[1]).to.have.all.keys([ - 'identity_type', - 'new_value', - 'old_value', - ]); - expect(identityRequest.identity_changes[1].old_value).to.equal('id2'); - expect(identityRequest.identity_changes[1].identity_type).to.equal( - 'customerid' - ); - expect(identityRequest.identity_changes[1].new_value).to.equal('id15'); + expect(identityRequest.identity_changes[1]).to.have.all.keys([ + 'identity_type', + 'new_value', + 'old_value', + ]); + expect(identityRequest.identity_changes[1].old_value).to.equal( + 'id2', + ); + expect(identityRequest.identity_changes[1].identity_type).to.equal( + 'customerid', + ); + expect(identityRequest.identity_changes[1].new_value).to.equal( + 'id15', + ); - expect(identityRequest.identity_changes[2]).to.have.all.keys([ - 'identity_type', - 'new_value', - 'old_value', - ]); - expect(identityRequest.identity_changes[2].old_value).to.equal('id3'); - expect(identityRequest.identity_changes[2].identity_type).to.equal( - 'facebook' - ); - expect(identityRequest.identity_changes[2].new_value).to.equal('id16'); + expect(identityRequest.identity_changes[2]).to.have.all.keys([ + 'identity_type', + 'new_value', + 'old_value', + ]); + expect(identityRequest.identity_changes[2].old_value).to.equal( + 'id3', + ); + expect(identityRequest.identity_changes[2].identity_type).to.equal( + 'facebook', + ); + expect(identityRequest.identity_changes[2].new_value).to.equal( + 'id16', + ); - expect(identityRequest.identity_changes[3]).to.have.all.keys([ - 'identity_type', - 'new_value', - 'old_value', - ]); - expect(identityRequest.identity_changes[3].old_value).to.equal('id4'); - expect(identityRequest.identity_changes[3].identity_type).to.equal( - 'twitter' - ); - expect(identityRequest.identity_changes[3].new_value).to.equal('id17'); + expect(identityRequest.identity_changes[3]).to.have.all.keys([ + 'identity_type', + 'new_value', + 'old_value', + ]); + expect(identityRequest.identity_changes[3].old_value).to.equal( + 'id4', + ); + expect(identityRequest.identity_changes[3].identity_type).to.equal( + 'twitter', + ); + expect(identityRequest.identity_changes[3].new_value).to.equal( + 'id17', + ); - expect(identityRequest.identity_changes[4]).to.have.all.keys([ - 'identity_type', - 'new_value', - 'old_value', - ]); - expect(identityRequest.identity_changes[4].old_value).to.equal('id5'); - expect(identityRequest.identity_changes[4].identity_type).to.equal( - 'google' - ); - expect(identityRequest.identity_changes[4].new_value).to.equal('id18'); + expect(identityRequest.identity_changes[4]).to.have.all.keys([ + 'identity_type', + 'new_value', + 'old_value', + ]); + expect(identityRequest.identity_changes[4].old_value).to.equal( + 'id5', + ); + expect(identityRequest.identity_changes[4].identity_type).to.equal( + 'google', + ); + expect(identityRequest.identity_changes[4].new_value).to.equal( + 'id18', + ); - expect(identityRequest.identity_changes[5]).to.have.all.keys([ - 'identity_type', - 'new_value', - 'old_value', - ]); - expect(identityRequest.identity_changes[5].old_value).to.equal('id6'); - expect(identityRequest.identity_changes[5].identity_type).to.equal( - 'microsoft' - ); - expect(identityRequest.identity_changes[5].new_value).to.equal('id19'); + expect(identityRequest.identity_changes[5]).to.have.all.keys([ + 'identity_type', + 'new_value', + 'old_value', + ]); + expect(identityRequest.identity_changes[5].old_value).to.equal( + 'id6', + ); + expect(identityRequest.identity_changes[5].identity_type).to.equal( + 'microsoft', + ); + expect(identityRequest.identity_changes[5].new_value).to.equal( + 'id19', + ); - expect(identityRequest.identity_changes[6]).to.have.all.keys([ - 'identity_type', - 'new_value', - 'old_value', - ]); - expect(identityRequest.identity_changes[6].old_value).to.equal('id7'); - expect(identityRequest.identity_changes[6].identity_type).to.equal( - 'yahoo' - ); - expect(identityRequest.identity_changes[6].new_value).to.equal('id20'); + expect(identityRequest.identity_changes[6]).to.have.all.keys([ + 'identity_type', + 'new_value', + 'old_value', + ]); + expect(identityRequest.identity_changes[6].old_value).to.equal( + 'id7', + ); + expect(identityRequest.identity_changes[6].identity_type).to.equal( + 'yahoo', + ); + expect(identityRequest.identity_changes[6].new_value).to.equal( + 'id20', + ); - expect(identityRequest.identity_changes[7]).to.have.all.keys([ - 'identity_type', - 'new_value', - 'old_value', - ]); - expect(identityRequest.identity_changes[7].old_value).to.equal('id8'); - expect(identityRequest.identity_changes[7].identity_type).to.equal( - 'email' - ); - expect(identityRequest.identity_changes[7].new_value).to.equal('id21'); + expect(identityRequest.identity_changes[7]).to.have.all.keys([ + 'identity_type', + 'new_value', + 'old_value', + ]); + expect(identityRequest.identity_changes[7].old_value).to.equal( + 'id8', + ); + expect(identityRequest.identity_changes[7].identity_type).to.equal( + 'email', + ); + expect(identityRequest.identity_changes[7].new_value).to.equal( + 'id21', + ); - expect(identityRequest.identity_changes[8]).to.have.all.keys([ - 'identity_type', - 'new_value', - 'old_value', - ]); - expect(identityRequest.identity_changes[8].old_value).to.equal('id9'); - expect(identityRequest.identity_changes[8].identity_type).to.equal( - 'facebookcustomaudienceid' - ); - expect(identityRequest.identity_changes[8].new_value).to.equal('id22'); + expect(identityRequest.identity_changes[8]).to.have.all.keys([ + 'identity_type', + 'new_value', + 'old_value', + ]); + expect(identityRequest.identity_changes[8].old_value).to.equal( + 'id9', + ); + expect(identityRequest.identity_changes[8].identity_type).to.equal( + 'facebookcustomaudienceid', + ); + expect(identityRequest.identity_changes[8].new_value).to.equal( + 'id22', + ); - expect(identityRequest.identity_changes[9]).to.have.all.keys([ - 'identity_type', - 'new_value', - 'old_value', - ]); - expect(identityRequest.identity_changes[9].old_value).to.equal('id11'); - expect(identityRequest.identity_changes[9].identity_type).to.equal( - 'other2' - ); - expect(identityRequest.identity_changes[9].new_value).to.equal('id23'); + expect(identityRequest.identity_changes[9]).to.have.all.keys([ + 'identity_type', + 'new_value', + 'old_value', + ]); + expect(identityRequest.identity_changes[9].old_value).to.equal( + 'id11', + ); + expect(identityRequest.identity_changes[9].identity_type).to.equal( + 'other2', + ); + expect(identityRequest.identity_changes[9].new_value).to.equal( + 'id23', + ); - expect(identityRequest.identity_changes[10]).to.have.all.keys([ - 'identity_type', - 'new_value', - 'old_value', - ]); - expect(identityRequest.identity_changes[10].old_value).to.equal('id12'); - expect(identityRequest.identity_changes[10].identity_type).to.equal( - 'other3' - ); - expect(identityRequest.identity_changes[10].new_value).to.equal('id24'); + expect(identityRequest.identity_changes[10]).to.have.all.keys([ + 'identity_type', + 'new_value', + 'old_value', + ]); + expect(identityRequest.identity_changes[10].old_value).to.equal( + 'id12', + ); + expect(identityRequest.identity_changes[10].identity_type).to.equal( + 'other3', + ); + expect(identityRequest.identity_changes[10].new_value).to.equal( + 'id24', + ); - expect(identityRequest.identity_changes[11]).to.have.all.keys([ - 'identity_type', - 'new_value', - 'old_value', - ]); - expect(identityRequest.identity_changes[11].old_value).to.equal('id13'); - expect(identityRequest.identity_changes[11].identity_type).to.equal( - 'other4' - ); - expect(identityRequest.identity_changes[11].new_value).to.equal('id25'); + expect(identityRequest.identity_changes[11]).to.have.all.keys([ + 'identity_type', + 'new_value', + 'old_value', + ]); + expect(identityRequest.identity_changes[11].old_value).to.equal( + 'id13', + ); + expect(identityRequest.identity_changes[11].identity_type).to.equal( + 'other4', + ); + expect(identityRequest.identity_changes[11].new_value).to.equal( + 'id25', + ); - expect(identityRequest.identity_changes[12]).to.have.all.keys([ - 'identity_type', - 'new_value', - 'old_value', - ]); - expect(identityRequest.identity_changes[12].old_value).to.equal('id14'); - expect(identityRequest.identity_changes[12].identity_type).to.equal( - 'other5' - ); - expect(identityRequest.identity_changes[12].new_value).to.equal('id26'); + expect(identityRequest.identity_changes[12]).to.have.all.keys([ + 'identity_type', + 'new_value', + 'old_value', + ]); + expect(identityRequest.identity_changes[12].old_value).to.equal( + 'id14', + ); + expect(identityRequest.identity_changes[12].identity_type).to.equal( + 'other5', + ); + expect(identityRequest.identity_changes[12].new_value).to.equal( + 'id26', + ); - expect(identityRequest.identity_changes[13].old_value).to.equal('id15'); - expect(identityRequest.identity_changes[13].identity_type).to.equal( - 'other6' - ); - expect(identityRequest.identity_changes[13].new_value).to.equal('id27'); + expect(identityRequest.identity_changes[13].old_value).to.equal( + 'id15', + ); + expect(identityRequest.identity_changes[13].identity_type).to.equal( + 'other6', + ); + expect(identityRequest.identity_changes[13].new_value).to.equal( + 'id27', + ); - expect(identityRequest.identity_changes[14].old_value).to.equal('id16'); - expect(identityRequest.identity_changes[14].identity_type).to.equal( - 'other7' - ); - expect(identityRequest.identity_changes[14].new_value).to.equal('id28'); + expect(identityRequest.identity_changes[14].old_value).to.equal( + 'id16', + ); + expect(identityRequest.identity_changes[14].identity_type).to.equal( + 'other7', + ); + expect(identityRequest.identity_changes[14].new_value).to.equal( + 'id28', + ); - expect(identityRequest.identity_changes[15].old_value).to.equal('id17'); - expect(identityRequest.identity_changes[15].identity_type).to.equal( - 'other8' - ); - expect(identityRequest.identity_changes[15].new_value).to.equal('id29'); + expect(identityRequest.identity_changes[15].old_value).to.equal( + 'id17', + ); + expect(identityRequest.identity_changes[15].identity_type).to.equal( + 'other8', + ); + expect(identityRequest.identity_changes[15].new_value).to.equal( + 'id29', + ); - expect(identityRequest.identity_changes[16].old_value).to.equal('id18'); - expect(identityRequest.identity_changes[16].identity_type).to.equal( - 'other9' - ); - expect(identityRequest.identity_changes[16].new_value).to.equal('id30'); + expect(identityRequest.identity_changes[16].old_value).to.equal( + 'id18', + ); + expect(identityRequest.identity_changes[16].identity_type).to.equal( + 'other9', + ); + expect(identityRequest.identity_changes[16].new_value).to.equal( + 'id30', + ); - expect(identityRequest.identity_changes[17].old_value).to.equal('id19'); - expect(identityRequest.identity_changes[17].identity_type).to.equal( - 'other10' - ); - expect(identityRequest.identity_changes[17].new_value).to.equal('id31'); + expect(identityRequest.identity_changes[17].old_value).to.equal( + 'id19', + ); + expect(identityRequest.identity_changes[17].identity_type).to.equal( + 'other10', + ); + expect(identityRequest.identity_changes[17].new_value).to.equal( + 'id31', + ); - expect(identityRequest.identity_changes[18].old_value).to.equal('id20'); - expect(identityRequest.identity_changes[18].identity_type).to.equal( - 'mobile_number' - ); - expect(identityRequest.identity_changes[18].new_value).to.equal('id32'); + expect(identityRequest.identity_changes[18].old_value).to.equal( + 'id20', + ); + expect(identityRequest.identity_changes[18].identity_type).to.equal( + 'mobile_number', + ); + expect(identityRequest.identity_changes[18].new_value).to.equal( + 'id32', + ); - expect(identityRequest.identity_changes[19].old_value).to.equal('id21'); - expect(identityRequest.identity_changes[19].identity_type).to.equal( - 'phone_number_2' - ); - expect(identityRequest.identity_changes[19].new_value).to.equal('id33'); + expect(identityRequest.identity_changes[19].old_value).to.equal( + 'id21', + ); + expect(identityRequest.identity_changes[19].identity_type).to.equal( + 'phone_number_2', + ); + expect(identityRequest.identity_changes[19].new_value).to.equal( + 'id33', + ); - expect(identityRequest.identity_changes[20].old_value).to.equal('id22'); - expect(identityRequest.identity_changes[20].identity_type).to.equal( - 'phone_number_3' - ); - expect(identityRequest.identity_changes[20].new_value).to.equal('id34'); + expect(identityRequest.identity_changes[20].old_value).to.equal( + 'id22', + ); + expect(identityRequest.identity_changes[20].identity_type).to.equal( + 'phone_number_3', + ); + expect(identityRequest.identity_changes[20].new_value).to.equal( + 'id34', + ); - done(); + done(); }); }); @@ -1110,59 +1215,59 @@ describe('identity', function() { fetchMock.restore(); }); - it('should not make a request when an invalid request is sent as a string', async () => { - const identityAPIRequest = BAD_USER_IDENTITIES_AS_STRING; - mParticle.Identity.login(identityAPIRequest); + it('should not make a request when an invalid request is sent as a string', async () => { + const identityAPIRequest = BAD_USER_IDENTITIES_AS_STRING; + mParticle.Identity.login(identityAPIRequest); - await waitForCondition(hasIdentityCallInflightReturned) - expect(fetchMock.calls().length).to.equal(0); - }); + await waitForCondition(hasIdentityCallInflightReturned); + expect(fetchMock.calls().length).to.equal(0); + }); - it('should not make a request when an invalid request is sent as an array', async () => { - const identityAPIRequest = BAD_USER_IDENTITIES_AS_ARRAY; - mParticle.Identity.login(identityAPIRequest); + it('should not make a request when an invalid request is sent as an array', async () => { + const identityAPIRequest = BAD_USER_IDENTITIES_AS_ARRAY; + mParticle.Identity.login(identityAPIRequest); - await waitForCondition(hasIdentityCallInflightReturned) - expect(fetchMock.calls().length).to.equal(0); - }); + await waitForCondition(hasIdentityCallInflightReturned); + expect(fetchMock.calls().length).to.equal(0); + }); - it('should not make a request when an invalid request is sent as a null', async () => { - const identityAPIRequest = BAD_USER_IDENTITIES_AS_NULL; - mParticle.Identity.login(identityAPIRequest); + it('should not make a request when an invalid request is sent as a null', async () => { + const identityAPIRequest = BAD_USER_IDENTITIES_AS_NULL; + mParticle.Identity.login(identityAPIRequest); - await waitForCondition(hasIdentityCallInflightReturned) - expect(fetchMock.calls().length).to.equal(0); - }); + await waitForCondition(hasIdentityCallInflightReturned); + expect(fetchMock.calls().length).to.equal(0); + }); - it('should not make a request when an invalid request is sent as undefined', async () => { - const identityAPIRequest = BAD_USER_IDENTITIES_AS_UNDEFINED; - mParticle.Identity.login(identityAPIRequest); + it('should not make a request when an invalid request is sent as undefined', async () => { + const identityAPIRequest = BAD_USER_IDENTITIES_AS_UNDEFINED; + mParticle.Identity.login(identityAPIRequest); - await waitForCondition(hasIdentityCallInflightReturned) - expect(fetchMock.calls().length).to.equal(0); - }); + await waitForCondition(hasIdentityCallInflightReturned); + expect(fetchMock.calls().length).to.equal(0); + }); - it('should not make a request when an invalid request is sent as a boolean', async () => { - const identityAPIRequest = BAD_USER_IDENTITIES_AS_BOOLEAN; - mParticle.Identity.login(identityAPIRequest); + it('should not make a request when an invalid request is sent as a boolean', async () => { + const identityAPIRequest = BAD_USER_IDENTITIES_AS_BOOLEAN; + mParticle.Identity.login(identityAPIRequest); - await waitForCondition(hasIdentityCallInflightReturned) - expect(fetchMock.calls().length).to.equal(0); - }); + await waitForCondition(hasIdentityCallInflightReturned); + expect(fetchMock.calls().length).to.equal(0); + }); - it('should not make a request when an invalid callback is set', async () => { - const identityRequest: IdentityApiData = { - userIdentities: { - customerid: '123', - }, - }; - const badCallback = BadCallbackAsString; + it('should not make a request when an invalid callback is set', async () => { + const identityRequest: IdentityApiData = { + userIdentities: { + customerid: '123', + }, + }; + const badCallback = BadCallbackAsString; - mParticle.Identity.login(identityRequest, badCallback); + mParticle.Identity.login(identityRequest, badCallback); - await waitForCondition(hasIdentityCallInflightReturned) - expect(fetchMock.calls().length).to.equal(0); - }); + await waitForCondition(hasIdentityCallInflightReturned); + expect(fetchMock.calls().length).to.equal(0); + }); }); describe('#logout', function () { @@ -1171,59 +1276,59 @@ describe('identity', function() { fetchMock.restore(); }); - it('should not make a request when an invalid request is sent as string', async () => { - const identityAPIRequest = BAD_USER_IDENTITIES_AS_STRING; - mParticle.Identity.logout(identityAPIRequest); + it('should not make a request when an invalid request is sent as string', async () => { + const identityAPIRequest = BAD_USER_IDENTITIES_AS_STRING; + mParticle.Identity.logout(identityAPIRequest); - await waitForCondition(hasIdentityCallInflightReturned) - expect(fetchMock.calls().length).to.equal(0); - }); + await waitForCondition(hasIdentityCallInflightReturned); + expect(fetchMock.calls().length).to.equal(0); + }); - it('should not make a request when an invalid request is sent as array', async () => { - const identityAPIRequest = BAD_USER_IDENTITIES_AS_ARRAY; - mParticle.Identity.logout(identityAPIRequest); + it('should not make a request when an invalid request is sent as array', async () => { + const identityAPIRequest = BAD_USER_IDENTITIES_AS_ARRAY; + mParticle.Identity.logout(identityAPIRequest); - await waitForCondition(hasIdentityCallInflightReturned) - expect(fetchMock.calls().length).to.equal(0); - }); + await waitForCondition(hasIdentityCallInflightReturned); + expect(fetchMock.calls().length).to.equal(0); + }); - it('should not make a request when an invalid request is sent as a null', async () => { - const identityAPIRequest = BAD_USER_IDENTITIES_AS_NULL; - mParticle.Identity.logout(identityAPIRequest); + it('should not make a request when an invalid request is sent as a null', async () => { + const identityAPIRequest = BAD_USER_IDENTITIES_AS_NULL; + mParticle.Identity.logout(identityAPIRequest); - await waitForCondition(hasIdentityCallInflightReturned) - expect(fetchMock.calls().length).to.equal(0); - }); + await waitForCondition(hasIdentityCallInflightReturned); + expect(fetchMock.calls().length).to.equal(0); + }); - it('should not make a request when an invalid request is sent as undefined', async () => { - const identityAPIRequest = BAD_USER_IDENTITIES_AS_UNDEFINED; - mParticle.Identity.logout(identityAPIRequest); + it('should not make a request when an invalid request is sent as undefined', async () => { + const identityAPIRequest = BAD_USER_IDENTITIES_AS_UNDEFINED; + mParticle.Identity.logout(identityAPIRequest); - await waitForCondition(hasIdentityCallInflightReturned) - expect(fetchMock.calls().length).to.equal(0); - }); + await waitForCondition(hasIdentityCallInflightReturned); + expect(fetchMock.calls().length).to.equal(0); + }); - it('should not make a request when an invalid request is sent as boolean', async () => { - const identityAPIRequest = BAD_USER_IDENTITIES_AS_BOOLEAN; - mParticle.Identity.logout(identityAPIRequest); + it('should not make a request when an invalid request is sent as boolean', async () => { + const identityAPIRequest = BAD_USER_IDENTITIES_AS_BOOLEAN; + mParticle.Identity.logout(identityAPIRequest); - await waitForCondition(hasIdentityCallInflightReturned) - expect(fetchMock.calls().length).to.equal(0); - }); + await waitForCondition(hasIdentityCallInflightReturned); + expect(fetchMock.calls().length).to.equal(0); + }); - it('should not make a request when an invalid callback is sent', async () => { - const identityRequest: IdentityApiData = { - userIdentities: { - customerid: '123', - }, - }; - const badCallback = BadCallbackAsString; + it('should not make a request when an invalid callback is sent', async () => { + const identityRequest: IdentityApiData = { + userIdentities: { + customerid: '123', + }, + }; + const badCallback = BadCallbackAsString; - mParticle.Identity.logout(identityRequest, badCallback); + mParticle.Identity.logout(identityRequest, badCallback); - await waitForCondition(hasIdentityCallInflightReturned) - expect(fetchMock.calls().length).to.equal(0); - }); + await waitForCondition(hasIdentityCallInflightReturned); + expect(fetchMock.calls().length).to.equal(0); + }); }); describe('#modify', function () { @@ -1232,59 +1337,59 @@ describe('identity', function() { fetchMock.restore(); }); - it('should not make a request when an invalid request is sent as a string', async () => { - const identityAPIRequest = BAD_USER_IDENTITIES_AS_STRING; - mParticle.Identity.modify(identityAPIRequest); + it('should not make a request when an invalid request is sent as a string', async () => { + const identityAPIRequest = BAD_USER_IDENTITIES_AS_STRING; + mParticle.Identity.modify(identityAPIRequest); - await waitForCondition(hasIdentityCallInflightReturned) - expect(fetchMock.calls().length).to.equal(0); - }); + await waitForCondition(hasIdentityCallInflightReturned); + expect(fetchMock.calls().length).to.equal(0); + }); - it('should not make a request when an invalid request is sent as an array', async () => { - const identityAPIRequest = BAD_USER_IDENTITIES_AS_ARRAY; - mParticle.Identity.modify(identityAPIRequest); + it('should not make a request when an invalid request is sent as an array', async () => { + const identityAPIRequest = BAD_USER_IDENTITIES_AS_ARRAY; + mParticle.Identity.modify(identityAPIRequest); - await waitForCondition(hasIdentityCallInflightReturned) - expect(fetchMock.calls().length).to.equal(0); - }); + await waitForCondition(hasIdentityCallInflightReturned); + expect(fetchMock.calls().length).to.equal(0); + }); - it('should not make a request when an invalid request is sent as a null', async () => { - const identityAPIRequest = BAD_USER_IDENTITIES_AS_NULL; - mParticle.Identity.modify(identityAPIRequest); + it('should not make a request when an invalid request is sent as a null', async () => { + const identityAPIRequest = BAD_USER_IDENTITIES_AS_NULL; + mParticle.Identity.modify(identityAPIRequest); - await waitForCondition(hasIdentityCallInflightReturned) - expect(fetchMock.calls().length).to.equal(0); - }); + await waitForCondition(hasIdentityCallInflightReturned); + expect(fetchMock.calls().length).to.equal(0); + }); - it('should not make a request when an invalid request is sent as a undefined', async () => { - const identityAPIRequest = BAD_USER_IDENTITIES_AS_UNDEFINED; - mParticle.Identity.modify(identityAPIRequest); + it('should not make a request when an invalid request is sent as a undefined', async () => { + const identityAPIRequest = BAD_USER_IDENTITIES_AS_UNDEFINED; + mParticle.Identity.modify(identityAPIRequest); - await waitForCondition(hasIdentityCallInflightReturned) - expect(fetchMock.calls().length).to.equal(0); - }); + await waitForCondition(hasIdentityCallInflightReturned); + expect(fetchMock.calls().length).to.equal(0); + }); - it('should not make a request when an invalid request is sent as a boolean', async () => { - const identityAPIRequest = BAD_USER_IDENTITIES_AS_BOOLEAN; - mParticle.Identity.modify(identityAPIRequest); + it('should not make a request when an invalid request is sent as a boolean', async () => { + const identityAPIRequest = BAD_USER_IDENTITIES_AS_BOOLEAN; + mParticle.Identity.modify(identityAPIRequest); - await waitForCondition(hasIdentityCallInflightReturned) - expect(fetchMock.calls().length).to.equal(0); + await waitForCondition(hasIdentityCallInflightReturned); + expect(fetchMock.calls().length).to.equal(0); }); - it('should not make a request when an invalid callback is set', async () => { - const identityRequest: IdentityApiData = { - userIdentities: { - customerid: '123', - }, - }; - const badCallback = BadCallbackAsString; + it('should not make a request when an invalid callback is set', async () => { + const identityRequest: IdentityApiData = { + userIdentities: { + customerid: '123', + }, + }; + const badCallback = BadCallbackAsString; - mParticle.Identity.modify(identityRequest, badCallback); + mParticle.Identity.modify(identityRequest, badCallback); - await waitForCondition(hasIdentityCallInflightReturned) - expect(fetchMock.calls().length).to.equal(0); - }); + await waitForCondition(hasIdentityCallInflightReturned); + expect(fetchMock.calls().length).to.equal(0); + }); }); describe('#identify', function () { @@ -1293,59 +1398,59 @@ describe('identity', function() { fetchMock.restore(); }); - it('should not make a request when an invalid request is sent as a string', async () => { - const identityAPIRequest = BAD_USER_IDENTITIES_AS_STRING; - mParticle.Identity.identify(identityAPIRequest); + it('should not make a request when an invalid request is sent as a string', async () => { + const identityAPIRequest = BAD_USER_IDENTITIES_AS_STRING; + mParticle.Identity.identify(identityAPIRequest); - await waitForCondition(hasIdentityCallInflightReturned) - expect(fetchMock.calls().length).to.equal(0); - }); + await waitForCondition(hasIdentityCallInflightReturned); + expect(fetchMock.calls().length).to.equal(0); + }); - it('should not make a request when an invalid request is sent as an array', async () => { - const identityAPIRequest = BAD_USER_IDENTITIES_AS_ARRAY; - mParticle.Identity.identify(identityAPIRequest); + it('should not make a request when an invalid request is sent as an array', async () => { + const identityAPIRequest = BAD_USER_IDENTITIES_AS_ARRAY; + mParticle.Identity.identify(identityAPIRequest); - await waitForCondition(hasIdentityCallInflightReturned) - expect(fetchMock.calls().length).to.equal(0); - }); + await waitForCondition(hasIdentityCallInflightReturned); + expect(fetchMock.calls().length).to.equal(0); + }); - it('should not make a request when an invalid request is sent as a null', async () => { - const identityAPIRequest = BAD_USER_IDENTITIES_AS_NULL; - mParticle.Identity.identify(identityAPIRequest); + it('should not make a request when an invalid request is sent as a null', async () => { + const identityAPIRequest = BAD_USER_IDENTITIES_AS_NULL; + mParticle.Identity.identify(identityAPIRequest); - await waitForCondition(hasIdentityCallInflightReturned) - expect(fetchMock.calls().length).to.equal(0); - }); + await waitForCondition(hasIdentityCallInflightReturned); + expect(fetchMock.calls().length).to.equal(0); + }); - it('should not make a request when an invalid request is sent as a undefined', async () => { - const identityAPIRequest = BAD_USER_IDENTITIES_AS_UNDEFINED; - mParticle.Identity.identify(identityAPIRequest); + it('should not make a request when an invalid request is sent as a undefined', async () => { + const identityAPIRequest = BAD_USER_IDENTITIES_AS_UNDEFINED; + mParticle.Identity.identify(identityAPIRequest); - await waitForCondition(hasIdentityCallInflightReturned) - expect(fetchMock.calls().length).to.equal(0); - }); + await waitForCondition(hasIdentityCallInflightReturned); + expect(fetchMock.calls().length).to.equal(0); + }); - it('should not make a request when an invalid request is sent as a boolean', async () => { - const identityAPIRequest = BAD_USER_IDENTITIES_AS_BOOLEAN; - mParticle.Identity.identify(identityAPIRequest); + it('should not make a request when an invalid request is sent as a boolean', async () => { + const identityAPIRequest = BAD_USER_IDENTITIES_AS_BOOLEAN; + mParticle.Identity.identify(identityAPIRequest); - await waitForCondition(hasIdentityCallInflightReturned) - expect(fetchMock.calls().length).to.equal(0); - }); + await waitForCondition(hasIdentityCallInflightReturned); + expect(fetchMock.calls().length).to.equal(0); + }); - it('should not make a request when an invalid callback is set', async () => { - const identityRequest: IdentityApiData = { - userIdentities: { - customerid: '123', - }, - }; - const badCallback = BadCallbackAsString; + it('should not make a request when an invalid callback is set', async () => { + const identityRequest: IdentityApiData = { + userIdentities: { + customerid: '123', + }, + }; + const badCallback = BadCallbackAsString; - mParticle.Identity.identify(identityRequest, badCallback); + mParticle.Identity.identify(identityRequest, badCallback); - await waitForCondition(hasIdentityCallInflightReturned) - expect(fetchMock.calls().length).to.equal(0); - }); + await waitForCondition(hasIdentityCallInflightReturned); + expect(fetchMock.calls().length).to.equal(0); + }); }); it('should have old_value === null when there is no previous identity of a certain type and a new identity of that type', function (done) { @@ -1364,7 +1469,7 @@ describe('identity', function() { 'test-platform', 'test-sdk-vendor', 'test-sdk-version', - 'test-context' + 'test-context', ); expect(identityRequest.identity_changes[0]).to.have.all.keys([ @@ -1374,13 +1479,13 @@ describe('identity', function() { ]); expect(identityRequest.identity_changes[0]).to.have.property( 'old_value', - null + null, ); expect(identityRequest.identity_changes[0].identity_type).to.equal( - 'other' + 'other', ); expect(identityRequest.identity_changes[0].new_value).to.equal( - 'new_other_id' + 'new_other_id', ); expect(identityRequest.identity_changes[1]).to.have.all.keys([ @@ -1390,13 +1495,13 @@ describe('identity', function() { ]); expect(identityRequest.identity_changes[1]).to.have.property( 'old_value', - 'old_facebook_id' + 'old_facebook_id', ); expect(identityRequest.identity_changes[1].identity_type).to.equal( - 'facebook' + 'facebook', ); expect(identityRequest.identity_changes[1].new_value).to.equal( - 'new_facebook_id' + 'new_facebook_id', ); done(); @@ -1417,7 +1522,7 @@ describe('identity', function() { 'test-platform', 'test-sdk-vendor', 'test-sdk-version', - 'test-context' + 'test-context', ); expect(identityRequest.identity_changes[0]).to.have.all.keys([ @@ -1426,13 +1531,13 @@ describe('identity', function() { 'old_value', ]); expect(identityRequest.identity_changes[0].old_value).to.equal( - 'old_facebook_id' + 'old_facebook_id', ); expect(identityRequest.identity_changes[0].identity_type).to.equal( - 'facebook' + 'facebook', ); expect(identityRequest.identity_changes[0].new_value).to.equal( - 'new_facebook_id' + 'new_facebook_id', ); expect(identityRequest.identity_changes.length).to.equal(1); @@ -1442,7 +1547,7 @@ describe('identity', function() { // https://go.mparticle.com/work/SQDSDKS-6568 it('should create a proper send request when passing identities to modify', async () => { - await waitForCondition(hasIdentifyReturned) + await waitForCondition(hasIdentifyReturned); const identityAPIData: IdentityApiData = { userIdentities: { email: 'rob@gmail.com', @@ -1451,47 +1556,49 @@ describe('identity', function() { mParticle.init(apiKey, window.mParticle.config); fetchMockSuccess(urls.modify, { - change_results: [ - { - identity_type: 'email', - modified_mpid: testMPID, - }, - ], + change_results: [ + { + identity_type: 'email', + modified_mpid: testMPID, + }, + ], }); - await waitForCondition(hasIdentityCallInflightReturned) + await waitForCondition(hasIdentityCallInflightReturned); fetchMock.resetHistory(); mParticle.Identity.modify(identityAPIData); - await waitForCondition(hasIdentityCallInflightReturned) - // 1st call is modify, 2nd call is the UIC event - console.log('fetchMock.calls()', fetchMock.calls()); - expect(fetchMock.calls().length).to.equal(2); + await waitForCondition(hasIdentityCallInflightReturned); + // 1st call is modify, 2nd call is the UIC event + console.log('fetchMock.calls()', fetchMock.calls()); + expect(fetchMock.calls().length).to.equal(2); - const modifyCall = fetchMock.calls()[0]; - expect(modifyCall[0].split('/')[5]).to.equal('modify'); + const modifyCall = fetchMock.calls()[0]; + expect(modifyCall[0].split('/')[5]).to.equal('modify'); - const data: IIdentityAPIModifyRequestData = JSON.parse(modifyCall[1].body as unknown as string); + const data: IIdentityAPIModifyRequestData = JSON.parse( + modifyCall[1].body as unknown as string, + ); - expect(data.identity_changes.length).to.equal(1); - expect(data.identity_changes[0]).to.have.keys( - 'old_value', - 'new_value', - 'identity_type' - ); - expect(data.identity_changes[0]).to.have.keys( - 'old_value', - 'new_value', - 'identity_type' - ); + expect(data.identity_changes.length).to.equal(1); + expect(data.identity_changes[0]).to.have.keys( + 'old_value', + 'new_value', + 'identity_type', + ); + expect(data.identity_changes[0]).to.have.keys( + 'old_value', + 'new_value', + 'identity_type', + ); }); it('ensure that automatic identify is not called more than once.', async () => { mParticle._resetForTests(MPConfig); const spy = sinon.spy(); - await waitForCondition(hasIdentifyReturned) + await waitForCondition(hasIdentifyReturned); mParticle.config.identityCallback = spy; fetchMockSuccess(urls.identify, { @@ -1502,12 +1609,14 @@ describe('identity', function() { mParticle.init(apiKey, window.mParticle.config); await waitForCondition(() => { - return mParticle.Identity.getCurrentUser()?.getMPID() === 'otherMPID'; - }) + return ( + mParticle.Identity.getCurrentUser()?.getMPID() === 'otherMPID' + ); + }); spy.calledOnce.should.be.ok(); mParticle.startNewSession(); - await waitForCondition(hasIdentityCallInflightReturned) + await waitForCondition(hasIdentityCallInflightReturned); spy.calledOnce.should.be.ok(); }); @@ -1515,17 +1624,14 @@ describe('identity', function() { mParticle._resetForTests(MPConfig); fetchMock.resetHistory(); - fetchMockSuccess( - urls.identify, - { - status: 400, - body: JSON.stringify({}), - } - ); + fetchMockSuccess(urls.identify, { + status: 400, + body: JSON.stringify({}), + }); mParticle.init(apiKey, window.mParticle.config); - await waitForCondition(hasIdentityCallInflightReturned) + await waitForCondition(hasIdentityCallInflightReturned); mParticle.logEvent('Test Event 1'); // There should be 3 calls here: @@ -1537,7 +1643,7 @@ describe('identity', function() { let testEvent1 = findEventFromRequest( fetchMock.calls(), - 'Test Event 1' + 'Test Event 1', ); expect(testEvent1).to.not.be.ok; @@ -1550,35 +1656,32 @@ describe('identity', function() { mParticle.logEvent('Test Event 2'); mParticle.Identity.login(); - await waitForCondition(hasLoginReturned) + await waitForCondition(hasLoginReturned); // server requests will now have the following events: // 1. Identify (from init) // 2. AST // 3. Session start // 4. Test1, - // 5. Login + // 5. Login // 6. Test2 expect(fetchMock.calls().length).to.equal(6); - testEvent1 = findEventFromRequest( - fetchMock.calls(), - 'Test Event 1' - ); + testEvent1 = findEventFromRequest(fetchMock.calls(), 'Test Event 1'); const testEvent2 = findEventFromRequest( fetchMock.calls(), - 'Test Event 2' + 'Test Event 2', ); const ASTEvent = findEventFromRequest( fetchMock.calls(), - 'application_state_transition' + 'application_state_transition', ); const sessionStartEvent = findEventFromRequest( fetchMock.calls(), - 'session_start' + 'session_start', ); const loginCall = fetchMock.calls()[3]; @@ -1613,7 +1716,7 @@ describe('identity', function() { mParticle.init(apiKey, window.mParticle.config); - await waitForCondition(hasIdentityCallInflightReturned) + await waitForCondition(hasIdentityCallInflightReturned); // get user 1 into cookies fetchMockSuccess(urls.login, { @@ -1623,7 +1726,7 @@ describe('identity', function() { mParticle.Identity.login(userIdentities1); - await waitForCondition(hasIdentityCallInflightReturned) + await waitForCondition(hasIdentityCallInflightReturned); // get user 2 into cookies fetchMockSuccess(urls.login, { @@ -1633,7 +1736,7 @@ describe('identity', function() { mParticle.Identity.login(userIdentities2); - await waitForCondition(hasIdentityCallInflightReturned) + await waitForCondition(hasIdentityCallInflightReturned); // get user 3 into cookies fetchMockSuccess(urls.login, { @@ -1643,7 +1746,7 @@ describe('identity', function() { mParticle.Identity.login(userIdentities3); - await waitForCondition(hasIdentityCallInflightReturned) + await waitForCondition(hasIdentityCallInflightReturned); // init again using user 1 fetchMockSuccess(urls.login, { @@ -1653,12 +1756,14 @@ describe('identity', function() { mParticle.init(apiKey, window.mParticle.config); - await waitForCondition(() => mParticle.Identity?.getUsers().length === 4) + await waitForCondition( + () => mParticle.Identity?.getUsers().length === 4, + ); const users = mParticle.Identity.getUsers(); // This includes the original, starting user, in addition to the 3 added above expect(users.length).to.equal(4); - for (let i of users) { + for (const i of users) { const mpid = i.getMPID(); expect(mParticle.Identity.getUser(mpid)).to.exist; } @@ -1694,7 +1799,7 @@ describe('identity', function() { mParticle.init(apiKey, window.mParticle.config); - await waitForCondition(hasIdentityCallInflightReturned) + await waitForCondition(hasIdentityCallInflightReturned); // get user 1 into cookies fetchMockSuccess(urls.login, { @@ -1704,7 +1809,7 @@ describe('identity', function() { mParticle.Identity.login(user1); - await waitForCondition(hasIdentityCallInflightReturned) + await waitForCondition(hasIdentityCallInflightReturned); mParticle.Identity.getCurrentUser().setUserAttribute('user', 'user1'); @@ -1716,7 +1821,7 @@ describe('identity', function() { mParticle.Identity.login(user2); - await waitForCondition(hasIdentityCallInflightReturned) + await waitForCondition(hasIdentityCallInflightReturned); mParticle.Identity.getCurrentUser().setUserAttribute('user', 'user2'); @@ -1728,7 +1833,7 @@ describe('identity', function() { mParticle.Identity.login(user3); - await waitForCondition(hasIdentityCallInflightReturned) + await waitForCondition(hasIdentityCallInflightReturned); mParticle.Identity.getCurrentUser().setUserAttribute('user', 'user3'); @@ -1740,13 +1845,12 @@ describe('identity', function() { mParticle.init(apiKey, window.mParticle.config); - await waitForCondition(hasIdentityCallInflightReturned) + await waitForCondition(hasIdentityCallInflightReturned); const localStorage = mParticle .getInstance() ._Persistence.getLocalStorage(); - expect(localStorage.user1, 'Local Storage User 1').to.be.ok; expect(localStorage.user2, 'Local Storage User 2').to.be.ok; expect(localStorage.user3, 'Local Storage User 3').to.be.ok; @@ -1754,7 +1858,7 @@ describe('identity', function() { localStorage.user1.ua.user.should.equal('user1'); localStorage.user1.ui.should.have.property('1', 'customerid1'); localStorage.user1.ui.should.have.property('7', 'email1@test.com'); - + localStorage.user2.ua.user.should.equal('user2'); localStorage.user2.ui.should.have.property('1', 'customerid2'); localStorage.user2.ui.should.have.property('7', 'email2@test.com'); @@ -1781,7 +1885,7 @@ describe('identity', function() { .getInstance() ._Identity.IdentityRequest.combineUserIdentities( previousUIByName, - newUIByName + newUIByName, ); // if an invalid identity type is added to the identity call, @@ -1829,22 +1933,22 @@ describe('identity', function() { mParticle.init(apiKey, window.mParticle.config); fetchMockSuccess(urls.modify, { - change_results: [ - { - identity_type: 'email', - modified_mpid: testMPID, - }, - ], + change_results: [ + { + identity_type: 'email', + modified_mpid: testMPID, + }, + ], }); - await waitForCondition(hasIdentifyReturned) + await waitForCondition(hasIdentifyReturned); mParticle.Identity.modify(user1modified); // Should contain the following calls: // 1 for the initial identify // 3 for the events (Session Start, UAT and UIC) // 1 for the modify // 1 for the UIC event - await waitForCondition(hasIdentityCallInflightReturned) + await waitForCondition(hasIdentityCallInflightReturned); expect(fetchMock.calls().length).to.equal(6); // This will add a new UAC Event to the call @@ -1855,7 +1959,7 @@ describe('identity', function() { 'iPhone', '12345', '1000', - 2 + 2, ); mParticle.eCommerce.Cart.add(product1); @@ -1863,12 +1967,14 @@ describe('identity', function() { mParticle.logEvent('Test Event 1'); expect(fetchMock.calls().length).to.equal(8); - const testEvent1Batch = JSON.parse(fetchMock.calls()[7][1].body as string); + const testEvent1Batch = JSON.parse( + fetchMock.calls()[7][1].body as string, + ); - expect(testEvent1Batch.user_attributes).to.deep.equal({ 'foo1': 'bar1' }); + expect(testEvent1Batch.user_attributes).to.deep.equal({ foo1: 'bar1' }); expect(testEvent1Batch.user_identities).to.deep.equal({ - 'customer_id': 'customerid1', - 'email': 'email2@test.com' + customer_id: 'customerid1', + email: 'email2@test.com', }); const products = getLocalStorageProducts(); @@ -1877,7 +1983,7 @@ describe('identity', function() { 'Name', 'iPhone', 'sku', - 'quantity' + 'quantity', ); products.testMPID.cp[0].should.have.property('Sku', '12345'); products.testMPID.cp[0].should.have.property('Price', 1000); @@ -1892,11 +1998,11 @@ describe('identity', function() { fetchMockSuccess(urls.logout, { mpid: 'logged-out-user', is_logged_in: true, - }); + }); mParticle.Identity.logout(user2); - await waitForCondition(hasLogOutReturned) + await waitForCondition(hasLogOutReturned); // This will add the following new calls: // 1 for the logout @@ -1906,23 +2012,25 @@ describe('identity', function() { expect(fetchMock.calls().length).to.equal(11); - const testEvent2Batch = JSON.parse(fetchMock.calls()[10][1].body as string); + const testEvent2Batch = JSON.parse( + fetchMock.calls()[10][1].body as string, + ); Object.keys(testEvent2Batch.user_attributes).length.should.equal(0); testEvent2Batch.user_identities.should.have.property( 'customer_id', - 'customerid2' + 'customerid2', ); fetchMockSuccess(urls.login, { mpid: 'testMPID', is_logged_in: true, - }); + }); mParticle.Identity.login(user1); await waitForCondition(() => { return mParticle.Identity.getCurrentUser().getMPID() === 'testMPID'; - }) + }); // This will add the following new calls: // 1 for the login @@ -1930,12 +2038,14 @@ describe('identity', function() { mParticle.logEvent('Test Event 3'); expect(fetchMock.calls().length).to.equal(13); - const testEvent3Batch = JSON.parse(fetchMock.calls()[12][1].body as string); + const testEvent3Batch = JSON.parse( + fetchMock.calls()[12][1].body as string, + ); - expect(testEvent3Batch.user_attributes).to.deep.equal({'foo1': 'bar1'}); + expect(testEvent3Batch.user_attributes).to.deep.equal({ foo1: 'bar1' }); expect(testEvent3Batch.user_identities).to.deep.equal({ - 'customer_id': 'customerid1', - 'email': 'email2@test.com' + customer_id: 'customerid1', + email: 'email2@test.com', }); const products2 = getLocalStorageProducts(); @@ -1944,7 +2054,7 @@ describe('identity', function() { 'Name', 'iPhone', 'sku', - 'quantity' + 'quantity', ); products2.testMPID.cp[0].should.have.property('Sku', '12345'); products2.testMPID.cp[0].should.have.property('Price', 1000); @@ -1982,9 +2092,10 @@ describe('identity', function() { mParticle.init(apiKey, window.mParticle.config); - await waitForCondition(hasIdentityCallInflightReturned) + await waitForCondition(hasIdentityCallInflightReturned); - const user1UIs = mParticle.Identity.getCurrentUser().getUserIdentities(); + const user1UIs = + mParticle.Identity.getCurrentUser().getUserIdentities(); user1UIs.userIdentities.customerid.should.equal('1'); @@ -1995,9 +2106,10 @@ describe('identity', function() { mParticle.Identity.login(user2); - await waitForCondition(hasIdentityCallInflightReturned) + await waitForCondition(hasIdentityCallInflightReturned); - const user2UIs = mParticle.Identity.getCurrentUser().getUserIdentities(); + const user2UIs = + mParticle.Identity.getCurrentUser().getUserIdentities(); user2UIs.userIdentities.customerid.should.equal('2'); fetchMockSuccess(urls.login, { @@ -2007,9 +2119,10 @@ describe('identity', function() { mParticle.Identity.login(user3); - await waitForCondition(hasIdentityCallInflightReturned) + await waitForCondition(hasIdentityCallInflightReturned); - const user3UIs = mParticle.Identity.getCurrentUser().getUserIdentities(); + const user3UIs = + mParticle.Identity.getCurrentUser().getUserIdentities(); user3UIs.userIdentities.customerid.should.equal('3'); fetchMockSuccess(urls.login, { @@ -2017,12 +2130,12 @@ describe('identity', function() { is_logged_in: true, }); - mParticle.Identity.login(user4); - await waitForCondition(hasIdentityCallInflightReturned) + await waitForCondition(hasIdentityCallInflightReturned); - const user4UIs = mParticle.Identity.getCurrentUser().getUserIdentities(); + const user4UIs = + mParticle.Identity.getCurrentUser().getUserIdentities(); user4UIs.userIdentities.customerid.should.equal('4'); fetchMockSuccess(urls.identify, { @@ -2032,7 +2145,7 @@ describe('identity', function() { mParticle.init(apiKey, window.mParticle.config); - await waitForCondition(hasIdentityCallInflightReturned) + await waitForCondition(hasIdentityCallInflightReturned); const user5 = mParticle.Identity.getCurrentUser(); user5.getUserIdentities().userIdentities.customerid.should.equal('4'); @@ -2050,7 +2163,7 @@ describe('identity', function() { it('should not send requests to the server with invalid userIdentity values', async () => { mParticle.init(apiKey, window.mParticle.config); - await waitForCondition(hasIdentityCallInflightReturned) + await waitForCondition(hasIdentityCallInflightReturned); fetchMock.resetHistory(); @@ -2092,7 +2205,7 @@ describe('identity', function() { }, }; - const callback = function(resp) { + const callback = function (resp) { result = resp; }; @@ -2134,7 +2247,7 @@ describe('identity', function() { result.httpCode.should.equal(-4); result.body.should.equal( Constants.Messages.ValidationMessages - .UserIdentitiesInvalidValues + .UserIdentitiesInvalidValues, ); // Reset result for next iteration of the loop @@ -2145,48 +2258,48 @@ describe('identity', function() { // for invalid values if (identityMethod !== 'modify') { // for some reason this is returning -4 for a good identity. - validUserIdentities.forEach(async(goodIdentities) => { + validUserIdentities.forEach(async (goodIdentities) => { mParticle.Identity[identityMethod]( goodIdentities, - callback + callback, ); - await waitForCondition(hasIdentityCallInflightReturned) + await waitForCondition(hasIdentityCallInflightReturned); expect(result, identityMethod).to.be.ok; expect( result.httpCode, - `valid ${identityMethod} httpCode` + `valid ${identityMethod} httpCode`, ).to.equal(200); const body = result.body as IdentityResultBody; expect(body.mpid, `valid ${identityMethod} mpid `).to.be.ok; expect(body.mpid, `valid ${identityMethod} mpid`).to.equal( - testMPID + testMPID, ); // Reset result for next iteration of the loop result = null; }); } else { - validUserIdentities.forEach(async(goodIdentities) => { + validUserIdentities.forEach(async (goodIdentities) => { mParticle.Identity.modify(goodIdentities, callback); - await waitForCondition(hasIdentityCallInflightReturned) + await waitForCondition(hasIdentityCallInflightReturned); expect(result, identityMethod).to.be.ok; expect(result.httpCode, `valid modify httpCode`).to.equal( - 200 + 200, ); const body = result.body as IdentityModifyResultBody; expect( body.change_results[0].modified_mpid, - `valid modify change_results modified_mpid` + `valid modify change_results modified_mpid`, ).to.equal(testMPID); expect( body.change_results[0].identity_type, - `valid modify change_results identity_type` + `valid modify change_results identity_type`, ).to.be.ok; // Reset result for next iteration of the loop @@ -2217,21 +2330,25 @@ describe('identity', function() { is_logged_in: false, }); - await waitForCondition(hasIdentifyReturned) + await waitForCondition(hasIdentifyReturned); mParticle.Identity.login(user); - await waitForCondition(hasLoginReturned) + await waitForCondition(hasLoginReturned); - const userIdentities1 = mParticle.Identity.getCurrentUser().getUserIdentities(); + const userIdentities1 = + mParticle.Identity.getCurrentUser().getUserIdentities(); - expect(userIdentities1.userIdentities).to.deep.equal({ customerid: '123' }); + expect(userIdentities1.userIdentities).to.deep.equal({ + customerid: '123', + }); mParticle.Identity.logout(); - await waitForCondition(hasLogOutReturned) + await waitForCondition(hasLogOutReturned); - const userIdentities2 = mParticle.Identity.getCurrentUser().getUserIdentities(); + const userIdentities2 = + mParticle.Identity.getCurrentUser().getUserIdentities(); expect(userIdentities2.userIdentities).to.deep.equal({}); }); @@ -2246,7 +2363,7 @@ describe('identity', function() { }; mParticle.init(apiKey, window.mParticle.config); - await waitForCondition(hasIdentifyReturned) + await waitForCondition(hasIdentifyReturned); const product1 = mParticle.eCommerce.createProduct('iPhone', 'SKU1', 1), product2 = mParticle.eCommerce.createProduct('Android', 'SKU2', 2), @@ -2274,7 +2391,9 @@ describe('identity', function() { mParticle.Identity.login(identityAPIRequest2); - await waitForCondition(() => mParticle.Identity.getCurrentUser().getMPID() === 'otherMPID') + await waitForCondition( + () => mParticle.Identity.getCurrentUser().getMPID() === 'otherMPID', + ); mParticle.eCommerce.Cart.add([product3, product4]); @@ -2288,314 +2407,383 @@ describe('identity', function() { mParticle.eCommerce.logCheckout(1); const checkoutEvent = findEventFromRequest( - fetchMock.calls(), - 'checkout' - ); - - checkoutEvent.data.product_action.should.have.property( - 'products', - null - ); - - fetchMockSuccess(urls.login, { - mpid: testMPID, - is_logged_in: true, - }); - - mParticle.Identity.login(identityAPIRequest1); - - await waitForCondition(() => mParticle.Identity.getCurrentUser().getMPID() === 'otherMPID') - - fetchMock.resetHistory(); - - // https://go.mparticle.com/work/SQDSDKS-6846 - mParticle.eCommerce.logCheckout(1); - - const checkoutEvent2 = findEventFromRequest( - fetchMock.calls(), - 'checkout' - ); - - checkoutEvent2.data.product_action.should.have.property( - 'products', - null - ); - }); - - it('should update cookies after modifying identities', async () => { - mParticle.init(apiKey, window.mParticle.config); - const user = { - userIdentities: { - customerid: 'customerId1', - }, - }; - - const modifiedUser = { - userIdentities: { - customerid: 'customerId2', - }, - }; - - fetchMockSuccess(urls.login, { - mpid: 'logged-in-user', - is_logged_in: true, - }); - - fetchMockSuccess( - 'https://identity.mparticle.com/v1/logged-in-user/modify', - { - change_results: [ - { - identity_type: 'customerid', - modified_mpid: 'modified-mpid', - }, - ], - } - ); - - await waitForCondition(hasIdentifyReturned) - mParticle.Identity.login(user); - - await waitForCondition(hasLoginReturned) - mParticle.Identity.modify(modifiedUser); - - await waitForCondition(() => { - return mParticle.Identity.getCurrentUser()?.getUserIdentities().userIdentities['customerid'] === 'customerId2'; - }) - const cookie = mParticle.getInstance()._Persistence.getLocalStorage(); - - cookie['logged-in-user'].ui[1].should.equal('customerId2'); - }); - - describe.skip('#onUserAlias', function() { - // https://go.mparticle.com/work/SQDSDKS-6854 - it('does not run onUserAlias if it is not a function', async (done) => { - mParticle.init(apiKey, window.mParticle.config); - - waitForCondition(hasIdentifyReturned) - .then(() => { - - const user1 = { - userIdentities: { - customerid: 'customerId1', - }, - }; - - const user2 = { - userIdentities: { - customerid: 'customerId2', - }, - onUserAlias: null, - }; - - const product1 = mParticle.eCommerce.createProduct('iPhone', 'SKU1', 1), - product2 = mParticle.eCommerce.createProduct('Android', 'SKU2', 1); - - mParticle.eCommerce.Cart.add([product1, product2]); - - fetchMockSuccess(urls.login, { - mpid: testMPID, - is_logged_in: true, - }); - - mParticle.Identity.login(user1); - - waitForCondition(hasIdentifyReturned) - .then(() => { - - fetchMockSuccess(urls.login, { - mpid: 'otherMPID', - is_logged_in: true, - }); - - fetchMock.resetHistory(); - mParticle.Identity.login(user2); - - waitForCondition(hasIdentityCallInflightReturned) - .then(() => { - - // This should have a call for the UIC that will occur because - // we are logging in as two different users - fetchMock.calls().length.should.equal(1); - expect(fetchMock.lastCall()[0]).to.equal(urls.events); - - - done(); - }).catch(done); - }).catch(done); - }).catch(done); - }); - - it('should run onUserAlias if it is a function', async (done) => { - mParticle.init(apiKey, window.mParticle.config); - - waitForCondition(hasIdentifyReturned) - .then(() => { - - let hasBeenRun = false; - const user1 = { - userIdentities: { - customerid: 'customerId1', - }, - }; - - const user2 = { - userIdentities: { - customerid: 'customerId2', - }, - onUserAlias: function() { - hasBeenRun = true; - }, - }; - - fetchMockSuccess(urls.login, { - mpid: testMPID, - is_logged_in: true, - }); - - mParticle.Identity.login(user1); - - waitForCondition(hasIdentityCallInflightReturned) - .then(() => { - - fetchMockSuccess(urls.login, { - mpid: 'otherMPID', - is_logged_in: true, - }); - - mParticle.Identity.login(user2); - - waitForCondition(hasIdentityCallInflightReturned) - .then(() => { - - expect(hasBeenRun).to.be.true; - - done(); - }).catch(done); - }).catch(done); - }).catch(done); - }); - - it('should setUserAttributes, setUserAttributeLists, removeUserAttributes, and removeUserAttributeLists properly in onUserAlias', async (done) => { - mParticle.init(apiKey, window.mParticle.config); - - waitForCondition(hasIdentifyReturned) - .then(() => { + fetchMock.calls(), + 'checkout', + ); - const user1 = { - userIdentities: { - customerid: 'customerId1', - }, - }; + checkoutEvent.data.product_action.should.have.property( + 'products', + null, + ); fetchMockSuccess(urls.login, { mpid: testMPID, is_logged_in: true, }); - mParticle.Identity.login(user1); + mParticle.Identity.login(identityAPIRequest1); - waitForCondition(hasIdentityCallInflightReturned) - .then(() => { - mParticle.Identity.getCurrentUser().setUserAttribute('gender', 'male'); - mParticle.Identity.getCurrentUser().setUserAttribute('age', 27); + await waitForCondition( + () => mParticle.Identity.getCurrentUser().getMPID() === 'otherMPID', + ); - const user1Attrs = mParticle.Identity.getCurrentUser().getAllUserAttributes(); - user1Attrs.should.have.property('gender', 'male'); - user1Attrs.should.have.property('age', 27); + fetchMock.resetHistory(); + // https://go.mparticle.com/work/SQDSDKS-6846 + mParticle.eCommerce.logCheckout(1); - fetchMockSuccess(urls.login, { - mpid: 'otherMPID', - is_logged_in: true, - }); + const checkoutEvent2 = findEventFromRequest( + fetchMock.calls(), + 'checkout', + ); - let user1Object, user2Object; + checkoutEvent2.data.product_action.should.have.property( + 'products', + null, + ); + }); - const user2 = { + it('should update cookies after modifying identities', async () => { + mParticle.init(apiKey, window.mParticle.config); + const user = { userIdentities: { - customerid: 'customerId2', + customerid: 'customerId1', }, - onUserAlias: function(user1, user2) { - const user1Attributes = user1.getAllUserAttributes(); - for (const key in user1Attributes) { - if (key !== 'gender') { - user2.setUserAttribute(key, user1Attributes[key]); - } - } - user2.setUserAttributeList('list', [1, 2, 3, 4, 5]); - user1.removeUserAttribute('age'); + }; - user1Object = user1; - user2Object = user2; + const modifiedUser = { + userIdentities: { + customerid: 'customerId2', }, }; - mParticle.Identity.login(user2); + fetchMockSuccess(urls.login, { + mpid: 'logged-in-user', + is_logged_in: true, + }); - waitForCondition(() => mParticle.Identity.getCurrentUser().getMPID() === 'otherMPID') - .then(() => { + fetchMockSuccess( + 'https://identity.mparticle.com/v1/logged-in-user/modify', + { + change_results: [ + { + identity_type: 'customerid', + modified_mpid: 'modified-mpid', + }, + ], + }, + ); - const user1ObjectAttrs = user1Object.getAllUserAttributes(); - user1ObjectAttrs.should.not.have.property('age'); - user1ObjectAttrs.should.have.property('gender', 'male'); + await waitForCondition(hasIdentifyReturned); + mParticle.Identity.login(user); - const user2Attrs = mParticle.Identity.getCurrentUser().getAllUserAttributes(); - user2Attrs.should.not.have.property('gender'); - user2Attrs.should.have.property('age', 27); - const user2ObjectAttrs = user2Object.getAllUserAttributes(); - user2ObjectAttrs.should.not.have.property('gender'); - user2ObjectAttrs.should.have.property('age', 27); + await waitForCondition(hasLoginReturned); + mParticle.Identity.modify(modifiedUser); - fetchMockSuccess(urls.login, { - mpid: 'otherMPID2', - is_logged_in: true, + await waitForCondition(() => { + return ( + mParticle.Identity.getCurrentUser()?.getUserIdentities() + .userIdentities['customerid'] === 'customerId2' + ); }); + const cookie = mParticle.getInstance()._Persistence.getLocalStorage(); + + cookie['logged-in-user'].ui[1].should.equal('customerId2'); + }); - let user2AttributeListsBeforeRemoving, - user3UserAttributeListsBeforeAdding, - user2AttributeListsAfterRemoving, - user3UserAttributeListsAfterAdding; + describe.skip('#onUserAlias', function () { + // https://go.mparticle.com/work/SQDSDKS-6854 + it('does not run onUserAlias if it is not a function', async (done) => { + mParticle.init(apiKey, window.mParticle.config); - const user3 = { - userIdentities: { - customerid: 'customerId3', - }, - onUserAlias: function(user2, user3) { - user2AttributeListsBeforeRemoving = user2.getUserAttributesLists(); - user3UserAttributeListsBeforeAdding = user3.getUserAttributesLists(); - user2.removeAllUserAttributes(); - user3.setUserAttributeList('list', [1, 2, 3, 4, 5]); - user2AttributeListsAfterRemoving = user2.getUserAttributesLists(); - user3UserAttributeListsAfterAdding = user3.getUserAttributesLists(); - }, - }; + waitForCondition(hasIdentifyReturned) + .then(() => { + const user1 = { + userIdentities: { + customerid: 'customerId1', + }, + }; - mParticle.Identity.login(user3); + const user2 = { + userIdentities: { + customerid: 'customerId2', + }, + onUserAlias: null, + }; + + const product1 = mParticle.eCommerce.createProduct( + 'iPhone', + 'SKU1', + 1, + ), + product2 = mParticle.eCommerce.createProduct( + 'Android', + 'SKU2', + 1, + ); + + mParticle.eCommerce.Cart.add([product1, product2]); + + fetchMockSuccess(urls.login, { + mpid: testMPID, + is_logged_in: true, + }); + + mParticle.Identity.login(user1); + + waitForCondition(hasIdentifyReturned) + .then(() => { + fetchMockSuccess(urls.login, { + mpid: 'otherMPID', + is_logged_in: true, + }); + + fetchMock.resetHistory(); + mParticle.Identity.login(user2); + + waitForCondition(hasIdentityCallInflightReturned) + .then(() => { + // This should have a call for the UIC that will occur because + // we are logging in as two different users + fetchMock.calls().length.should.equal(1); + expect(fetchMock.lastCall()[0]).to.equal( + urls.events, + ); + + done(); + }) + .catch(done); + }) + .catch(done); + }) + .catch(done); + }); - waitForCondition(() => mParticle.Identity.getCurrentUser().getMPID() === 'otherMPID2') - .then(() => { + it('should run onUserAlias if it is a function', async (done) => { + mParticle.init(apiKey, window.mParticle.config); + waitForCondition(hasIdentifyReturned) + .then(() => { + let hasBeenRun = false; + const user1 = { + userIdentities: { + customerid: 'customerId1', + }, + }; - expect(user2AttributeListsBeforeRemoving.list.length).to.equal(5); - expect(Object.keys(user3UserAttributeListsBeforeAdding).length).to.not - .be.ok; + const user2 = { + userIdentities: { + customerid: 'customerId2', + }, + onUserAlias: function () { + hasBeenRun = true; + }, + }; + + fetchMockSuccess(urls.login, { + mpid: testMPID, + is_logged_in: true, + }); + + mParticle.Identity.login(user1); + + waitForCondition(hasIdentityCallInflightReturned) + .then(() => { + fetchMockSuccess(urls.login, { + mpid: 'otherMPID', + is_logged_in: true, + }); + + mParticle.Identity.login(user2); + + waitForCondition(hasIdentityCallInflightReturned) + .then(() => { + expect(hasBeenRun).to.be.true; + + done(); + }) + .catch(done); + }) + .catch(done); + }) + .catch(done); + }); - expect(Object.keys(user2AttributeListsAfterRemoving).length).to.not.be - .ok; - expect(user3UserAttributeListsAfterAdding.list.length).to.equal(5); + it('should setUserAttributes, setUserAttributeLists, removeUserAttributes, and removeUserAttributeLists properly in onUserAlias', async (done) => { + mParticle.init(apiKey, window.mParticle.config); - done(); - }).catch(done); - }).catch(done); - }).catch(done); - }).catch(done); - }); + waitForCondition(hasIdentifyReturned) + .then(() => { + const user1 = { + userIdentities: { + customerid: 'customerId1', + }, + }; + + fetchMockSuccess(urls.login, { + mpid: testMPID, + is_logged_in: true, + }); + + mParticle.Identity.login(user1); + + waitForCondition(hasIdentityCallInflightReturned) + .then(() => { + mParticle.Identity.getCurrentUser().setUserAttribute( + 'gender', + 'male', + ); + mParticle.Identity.getCurrentUser().setUserAttribute( + 'age', + 27, + ); + + const user1Attrs = + mParticle.Identity.getCurrentUser().getAllUserAttributes(); + user1Attrs.should.have.property('gender', 'male'); + user1Attrs.should.have.property('age', 27); + + fetchMockSuccess(urls.login, { + mpid: 'otherMPID', + is_logged_in: true, + }); + + let user1Object, user2Object; + + const user2 = { + userIdentities: { + customerid: 'customerId2', + }, + onUserAlias: function (user1, user2) { + const user1Attributes = + user1.getAllUserAttributes(); + for (const key in user1Attributes) { + if (key !== 'gender') { + user2.setUserAttribute( + key, + user1Attributes[key], + ); + } + } + user2.setUserAttributeList( + 'list', + [1, 2, 3, 4, 5], + ); + user1.removeUserAttribute('age'); + + user1Object = user1; + user2Object = user2; + }, + }; + + mParticle.Identity.login(user2); + + waitForCondition( + () => + mParticle.Identity.getCurrentUser().getMPID() === + 'otherMPID', + ) + .then(() => { + const user1ObjectAttrs = + user1Object.getAllUserAttributes(); + user1ObjectAttrs.should.not.have.property( + 'age', + ); + user1ObjectAttrs.should.have.property( + 'gender', + 'male', + ); + + const user2Attrs = + mParticle.Identity.getCurrentUser().getAllUserAttributes(); + user2Attrs.should.not.have.property( + 'gender', + ); + user2Attrs.should.have.property('age', 27); + const user2ObjectAttrs = + user2Object.getAllUserAttributes(); + user2ObjectAttrs.should.not.have.property( + 'gender', + ); + user2ObjectAttrs.should.have.property( + 'age', + 27, + ); + + fetchMockSuccess(urls.login, { + mpid: 'otherMPID2', + is_logged_in: true, + }); + + let user2AttributeListsBeforeRemoving, + user3UserAttributeListsBeforeAdding, + user2AttributeListsAfterRemoving, + user3UserAttributeListsAfterAdding; + + const user3 = { + userIdentities: { + customerid: 'customerId3', + }, + onUserAlias: function (user2, user3) { + user2AttributeListsBeforeRemoving = + user2.getUserAttributesLists(); + user3UserAttributeListsBeforeAdding = + user3.getUserAttributesLists(); + user2.removeAllUserAttributes(); + user3.setUserAttributeList( + 'list', + [1, 2, 3, 4, 5], + ); + user2AttributeListsAfterRemoving = + user2.getUserAttributesLists(); + user3UserAttributeListsAfterAdding = + user3.getUserAttributesLists(); + }, + }; + + mParticle.Identity.login(user3); + + waitForCondition( + () => + mParticle.Identity.getCurrentUser().getMPID() === + 'otherMPID2', + ) + .then(() => { + expect( + user2AttributeListsBeforeRemoving + .list.length, + ).to.equal(5); + expect( + Object.keys( + user3UserAttributeListsBeforeAdding, + ).length, + ).to.not.be.ok; + + expect( + Object.keys( + user2AttributeListsAfterRemoving, + ).length, + ).to.not.be.ok; + expect( + user3UserAttributeListsAfterAdding + .list.length, + ).to.equal(5); + + done(); + }) + .catch(done); + }) + .catch(done); + }) + .catch(done); + }) + .catch(done); + }); }); it('should return an empty array when no cart products exist', async () => { mParticle.init(apiKey, window.mParticle.config); - await waitForCondition(hasIdentifyReturned) + await waitForCondition(hasIdentifyReturned); const user1 = { userIdentities: { customerid: 'customerId1', @@ -2609,7 +2797,7 @@ describe('identity', function() { mParticle.Identity.login(user1); - await waitForCondition(hasIdentityCallInflightReturned) + await waitForCondition(hasIdentityCallInflightReturned); const products = mParticle.Identity.getCurrentUser() .getCart() @@ -2621,7 +2809,7 @@ describe('identity', function() { it('should make a request when copyUserAttributes is included on the identity request', async () => { mParticle.init(apiKey, window.mParticle.config); - await waitForCondition(hasIdentifyReturned) + await waitForCondition(hasIdentifyReturned); const identityAPIRequest1 = { userIdentities: { @@ -2630,7 +2818,6 @@ describe('identity', function() { copyUserAttributes: true, }; - fetchMockSuccess(urls.logout, { mpid: testMPID, is_logged_in: true, @@ -2640,7 +2827,7 @@ describe('identity', function() { mParticle.Identity.logout(identityAPIRequest1); - await waitForCondition(hasIdentityCallInflightReturned) + await waitForCondition(hasIdentityCallInflightReturned); // This should have a call for the logout and UIC expect(fetchMock.calls().length).to.equal(2); @@ -2660,7 +2847,7 @@ describe('identity', function() { mParticle.Identity.login(identityAPIRequest1); - await waitForCondition(hasIdentityCallInflightReturned) + await waitForCondition(hasIdentityCallInflightReturned); expect(fetchMock.calls().length).to.equal(1); @@ -2679,7 +2866,7 @@ describe('identity', function() { mParticle.Identity.modify(identityAPIRequest1); - await waitForCondition(hasIdentityCallInflightReturned) + await waitForCondition(hasIdentityCallInflightReturned); expect(fetchMock.calls().length).to.equal(1); @@ -2701,13 +2888,13 @@ describe('identity', function() { }); // https://go.mparticle.com/work/SQDSDKS-6460 - mParticle.config.identityCallback = function({ body }) { + mParticle.config.identityCallback = function ({ body }) { mpid = (body as IdentityResultBody).mpid; }; mParticle.init(apiKey, window.mParticle.config); - await waitForCondition(hasIdentityCallInflightReturned) + await waitForCondition(hasIdentityCallInflightReturned); expect(mpid).to.equal('MPID1'); }); @@ -2715,7 +2902,7 @@ describe('identity', function() { it('should trigger the identityCallback before eventQueue is flushed', async () => { mParticle._resetForTests(MPConfig); - await waitForCondition(hasBeforeEachCallbackReturned) + await waitForCondition(hasBeforeEachCallbackReturned); fetchMock.resetHistory(); @@ -2726,7 +2913,7 @@ describe('identity', function() { let callbackCalled = false; - mParticle.config.identityCallback = function() { + mParticle.config.identityCallback = function () { mParticle.Identity.getCurrentUser().setUserAttribute('foo', 'bar'); callbackCalled = true; }; @@ -2742,7 +2929,7 @@ describe('identity', function() { const identifyCall = fetchMock.lastCall(); expect(identifyCall[0].split('/')[4]).to.equal('identify'); - await waitForCondition(() => callbackCalled) + await waitForCondition(() => callbackCalled); // Force an upload so we can verify the correct events have fired mParticle.upload(); @@ -2756,16 +2943,16 @@ describe('identity', function() { const sessionStartEventBatch = findBatch( fetchMock.calls(), - 'session_start' + 'session_start', ); const ASTEventBatch = findBatch( fetchMock.calls(), - 'application_state_transition' + 'application_state_transition', ); sessionStartEventBatch.user_attributes.should.have.property( 'foo', - 'bar' + 'bar', ); ASTEventBatch.user_attributes.should.have.property('foo', 'bar'); }); @@ -2780,38 +2967,40 @@ describe('identity', function() { setCookie(workspaceCookieName, cookies, true); //does not actually hit the server because identity request is not sent let result; - mParticle.config.identityCallback = function(resp) { + mParticle.config.identityCallback = function (resp) { resp.getUser().setUserAttribute('attr', 'value'); result = resp; }; mParticle.init(apiKey, window.mParticle.config); - await waitForCondition(hasIdentifyReturned) + await waitForCondition(hasIdentifyReturned); // Should contain: // 1 for the Identify Request // 1 for the AST // 1 for the UAC - + expect(fetchMock.calls().length).to.equal(3); fetchMockSuccess(urls.identify, { mpid: 'MPID1', - is_logged_in: false , + is_logged_in: false, }); fetchMock.resetHistory(); mParticle.init(apiKey, window.mParticle.config); - await waitForCondition(hasIdentityCallInflightReturned) + await waitForCondition(hasIdentityCallInflightReturned); // the server request is the AST, there is no request to Identity fetchMock.calls().length.should.equal(1); const eventCall = fetchMock.calls()[0]; const eventData = JSON.parse(eventCall[1].body as string); expect(eventData.events.length).to.equal(1); - expect(eventData.events[0].event_type).to.equal('application_state_transition'); + expect(eventData.events[0].event_type).to.equal( + 'application_state_transition', + ); result.should.have.properties('body', 'httpCode', 'getUser'); @@ -2820,19 +3009,16 @@ describe('identity', function() { 'context', 'is_ephemeral', 'matched_identities', - 'mpid' + 'mpid', ); expect(result.body.context).to.not.be.ok; expect(result.body.is_ephemeral).to.not.be.ok; result.body.matched_identities.should.have.property( 'customerid', - 'customerid1' + 'customerid1', ); result.body.mpid.should.equal('testMPID'); - result - .getUser() - .getMPID() - .should.equal('testMPID'); + result.getUser().getMPID().should.equal('testMPID'); result .getUser() .getAllUserAttributes() @@ -2846,16 +3032,16 @@ describe('identity', function() { fetchMockSuccess(urls.identify, { mpid: 'MPID1', is_logged_in: false, - }); + }); - mParticle.config.identityCallback = function(resp) { + mParticle.config.identityCallback = function (resp) { result = resp; resp.getUser().setUserAttribute('test', 'value'); }; mParticle.init(apiKey, window.mParticle.config); - await waitForCondition(hasIdentityCallInflightReturned) + await waitForCondition(hasIdentityCallInflightReturned); result.should.have.property('getUser'); @@ -2865,182 +3051,184 @@ describe('identity', function() { }); describe('identityCallback responses', function () { - it('should have a getUser function on identify result object', async () => { - let result; + it('should have a getUser function on identify result object', async () => { + let result; - mParticle._resetForTests(MPConfig); + mParticle._resetForTests(MPConfig); - mParticle.config.identityCallback = function(resp) { - resp.getUser().setUserAttribute('attr', 'value'); - result = resp; - }; + mParticle.config.identityCallback = function (resp) { + resp.getUser().setUserAttribute('attr', 'value'); + result = resp; + }; - fetchMockSuccess(urls.identify, { - mpid: 'MPID1', - is_logged_in: false, - }); + fetchMockSuccess(urls.identify, { + mpid: 'MPID1', + is_logged_in: false, + }); - // Init fires an identify call - mParticle.init(apiKey, window.mParticle.config); + // Init fires an identify call + mParticle.init(apiKey, window.mParticle.config); - await waitForCondition(() => { - return mParticle.Identity.getCurrentUser()?.getMPID() === 'MPID1'; - }) + await waitForCondition(() => { + return ( + mParticle.Identity.getCurrentUser()?.getMPID() === 'MPID1' + ); + }); - result.should.have.properties('body', 'httpCode', 'getUser'); - result.httpCode.should.equal(200); - result.body.should.have.properties('mpid', 'is_logged_in'); - result.body.mpid.should.equal('MPID1'); - result - .getUser() - .getMPID() - .should.equal('MPID1'); - result - .getUser() - .getAllUserAttributes() - .should.have.property('attr', 'value'); - }); + result.should.have.properties('body', 'httpCode', 'getUser'); + result.httpCode.should.equal(200); + result.body.should.have.properties('mpid', 'is_logged_in'); + result.body.mpid.should.equal('MPID1'); + result.getUser().getMPID().should.equal('MPID1'); + result + .getUser() + .getAllUserAttributes() + .should.have.property('attr', 'value'); + }); - it('should have a getUser function on login result object', async () => { - let result - let loginResult; + it('should have a getUser function on login result object', async () => { + let result; + let loginResult; - mParticle._resetForTests(MPConfig); + mParticle._resetForTests(MPConfig); - mParticle.config.identityCallback = function(resp) { - resp.getUser().setUserAttribute('attr', 'value'); - result = resp; - }; + mParticle.config.identityCallback = function (resp) { + resp.getUser().setUserAttribute('attr', 'value'); + result = resp; + }; - fetchMockSuccess(urls.identify, { - mpid: 'MPID1', - is_logged_in: false, - }); + fetchMockSuccess(urls.identify, { + mpid: 'MPID1', + is_logged_in: false, + }); - fetchMockSuccess(urls.login, { - mpid: 'MPID1', - is_logged_in: true, - }); + fetchMockSuccess(urls.login, { + mpid: 'MPID1', + is_logged_in: true, + }); - mParticle.init(apiKey, window.mParticle.config); + mParticle.init(apiKey, window.mParticle.config); - await waitForCondition(() => { - return mParticle.Identity.getCurrentUser()?.getMPID() === 'MPID1'; - }) + await waitForCondition(() => { + return ( + mParticle.Identity.getCurrentUser()?.getMPID() === 'MPID1' + ); + }); - const identityRequest = { userIdentities: { customerid: 'test123' } }; - function loginCallback(result) { - loginResult = result; - } + const identityRequest = { + userIdentities: { customerid: 'test123' }, + }; + function loginCallback(result) { + loginResult = result; + } - mParticle.Identity.login(identityRequest, loginCallback); + mParticle.Identity.login(identityRequest, loginCallback); - await waitForCondition(hasIdentityCallInflightReturned) + await waitForCondition(hasIdentityCallInflightReturned); - loginResult - .getUser() - .getMPID() - .should.equal('MPID1'); + loginResult.getUser().getMPID().should.equal('MPID1'); - loginResult - .getUser() - .getAllUserAttributes() - .should.have.property('attr', 'value'); - }); + loginResult + .getUser() + .getAllUserAttributes() + .should.have.property('attr', 'value'); + }); - it('should have a getUser function on logout result object', async () => { - let result; - let logoutResult; + it('should have a getUser function on logout result object', async () => { + let result; + let logoutResult; - mParticle._resetForTests(MPConfig); + mParticle._resetForTests(MPConfig); - mParticle.config.identityCallback = function(resp) { - resp.getUser().setUserAttribute('attr', 'value'); - result = resp; - }; + mParticle.config.identityCallback = function (resp) { + resp.getUser().setUserAttribute('attr', 'value'); + result = resp; + }; - fetchMockSuccess(urls.identify, { - mpid: 'MPID1', - is_logged_in: false, - }); + fetchMockSuccess(urls.identify, { + mpid: 'MPID1', + is_logged_in: false, + }); - fetchMockSuccess(urls.logout, { - mpid: 'MPID1', - is_logged_in: false, - }); + fetchMockSuccess(urls.logout, { + mpid: 'MPID1', + is_logged_in: false, + }); - mParticle.init(apiKey, window.mParticle.config); + mParticle.init(apiKey, window.mParticle.config); - await waitForCondition(() => { - return mParticle.Identity.getCurrentUser()?.getMPID() === 'MPID1'; - }) + await waitForCondition(() => { + return ( + mParticle.Identity.getCurrentUser()?.getMPID() === 'MPID1' + ); + }); - const identityRequest = { userIdentities: { customerid: 'test123' } }; - function logoutCallback(result) { - logoutResult = result; - } + const identityRequest = { + userIdentities: { customerid: 'test123' }, + }; + function logoutCallback(result) { + logoutResult = result; + } - mParticle.Identity.logout(identityRequest, logoutCallback); + mParticle.Identity.logout(identityRequest, logoutCallback); - await waitForCondition(hasIdentityCallInflightReturned) + await waitForCondition(hasIdentityCallInflightReturned); - logoutResult - .getUser() - .getMPID() - .should.equal('MPID1'); + logoutResult.getUser().getMPID().should.equal('MPID1'); - logoutResult - .getUser() - .getAllUserAttributes() - .should.have.property('attr', 'value'); - }); + logoutResult + .getUser() + .getAllUserAttributes() + .should.have.property('attr', 'value'); + }); - it('should have a getUser function on modify result object', async () => { - let result - let modifyResult; + it('should have a getUser function on modify result object', async () => { + let result; + let modifyResult; - mParticle._resetForTests(MPConfig); + mParticle._resetForTests(MPConfig); - mParticle.config.identityCallback = function(resp) { - resp.getUser().setUserAttribute('attr', 'value'); - result = resp; - }; + mParticle.config.identityCallback = function (resp) { + resp.getUser().setUserAttribute('attr', 'value'); + result = resp; + }; - fetchMockSuccess(urls.identify, { - mpid: 'MPID1', - is_logged_in: false, - }); + fetchMockSuccess(urls.identify, { + mpid: 'MPID1', + is_logged_in: false, + }); - fetchMockSuccess(urls.modify, { - mpid: 'MPID1', - is_logged_in: false, - }); + fetchMockSuccess(urls.modify, { + mpid: 'MPID1', + is_logged_in: false, + }); - mParticle.init(apiKey, window.mParticle.config); + mParticle.init(apiKey, window.mParticle.config); - await waitForCondition(() => { - return mParticle.Identity.getCurrentUser()?.getMPID() === 'MPID1'; - }) + await waitForCondition(() => { + return ( + mParticle.Identity.getCurrentUser()?.getMPID() === 'MPID1' + ); + }); - const identityRequest = { userIdentities: { customerid: 'test123' } }; - function modifyCallback(result) { - modifyResult = result; - } + const identityRequest = { + userIdentities: { customerid: 'test123' }, + }; + function modifyCallback(result) { + modifyResult = result; + } - mParticle.Identity.modify(identityRequest, modifyCallback); + mParticle.Identity.modify(identityRequest, modifyCallback); - await waitForCondition(hasIdentityCallInflightReturned) + await waitForCondition(hasIdentityCallInflightReturned); - modifyResult - .getUser() - .getMPID() - .should.equal('MPID1'); + modifyResult.getUser().getMPID().should.equal('MPID1'); - modifyResult - .getUser() - .getAllUserAttributes() - .should.have.property('attr', 'value'); - }); + modifyResult + .getUser() + .getAllUserAttributes() + .should.have.property('attr', 'value'); + }); }); it('should call identify when there is an active session but no current user', async () => { @@ -3048,7 +3236,7 @@ describe('identity', function() { // client had no programmatic handling of a failed identify request mParticle._resetForTests(MPConfig); - await waitForCondition(hasIdentityCallInflightReturned) + await waitForCondition(hasIdentityCallInflightReturned); fetchMockSuccess(urls.identify, { mpid: 'MPID1', @@ -3059,13 +3247,13 @@ describe('identity', function() { // without a current user mParticle.config.identifyRequest = { userIdentities: { - customerid: (123 as unknown) as string, + customerid: 123 as unknown as string, }, }; fetchMock.resetHistory(); mParticle.init(apiKey, window.mParticle.config); - await waitForCondition(hasIdentityCallInflightReturned) + await waitForCondition(hasIdentityCallInflightReturned); let cookies = mParticle.getInstance()._Persistence.getPersistence(); cookies.should.have.property('gs'); @@ -3081,9 +3269,11 @@ describe('identity', function() { fetchMock.resetHistory(); mParticle.init(apiKey, window.mParticle.config); - await waitForCondition(() => mParticle.Identity.getCurrentUser()?.getMPID() === 'MPID1') - - cookies = mParticle.getInstance()._Persistence.getPersistence(); + await waitForCondition( + () => mParticle.Identity.getCurrentUser()?.getMPID() === 'MPID1', + ); + + cookies = mParticle.getInstance()._Persistence.getPersistence(); cookies.should.have.property('gs'); cookies.should.have.have.property('cu', 'MPID1'); mParticle.Identity.getCurrentUser().should.not.equal(null); @@ -3101,8 +3291,8 @@ describe('identity', function() { mParticle.init(apiKey, window.mParticle.config); - await waitForCondition(hasIdentityCallInflightReturned) - + await waitForCondition(hasIdentityCallInflightReturned); + // NOTE: Use sinon to "lock" in the current time for testing purposes const now = new Date(); clock = sinon.useFakeTimers(now.getTime()); @@ -3116,8 +3306,12 @@ describe('identity', function() { // The expecation is that firstSeenTime should be some time in the past // and lastSeenTime should be the closer to the current time - expect(currentUser.getFirstSeenTime(), 'First Seen Time').to.lessThan(now.getTime()); - expect(currentUser.getLastSeenTime(), 'Last Seen Time').to.equal(now.getTime()); + expect(currentUser.getFirstSeenTime(), 'First Seen Time').to.lessThan( + now.getTime(), + ); + expect(currentUser.getLastSeenTime(), 'Last Seen Time').to.equal( + now.getTime(), + ); clock.restore(); }); @@ -3139,7 +3333,7 @@ describe('identity', function() { mParticle.init(apiKey, window.mParticle.config); - await waitForCondition(hasIdentityCallInflightReturned) + await waitForCondition(hasIdentityCallInflightReturned); let currentUser = mParticle.Identity.getCurrentUser(); currentUser.should.not.equal(null); @@ -3162,7 +3356,9 @@ describe('identity', function() { mParticle.Identity.login(userIdentities1); - await waitForCondition(() => mParticle.Identity.getCurrentUser().getMPID() === 'MPID1') + await waitForCondition( + () => mParticle.Identity.getCurrentUser().getMPID() === 'MPID1', + ); const nowAfterLogin = new Date(); @@ -3170,12 +3366,18 @@ describe('identity', function() { currentUser.getMPID().should.equal('MPID1'); // new user's firstSeenTime should be greater than or equal to the preceeding user's lastSeenTime - expect(currentUser.getFirstSeenTime()).to.greaterThanOrEqual(user1LastSeen); + expect(currentUser.getFirstSeenTime()).to.greaterThanOrEqual( + user1LastSeen, + ); // We should expect the FirstSeenTime to be between the time the test started // the logged in request completed - expect(currentUser.getFirstSeenTime()).to.greaterThan(nowTestStart.getTime()); - expect(currentUser.getFirstSeenTime()).to.lessThan(nowAfterLogin.getTime()); + expect(currentUser.getFirstSeenTime()).to.greaterThan( + nowTestStart.getTime(), + ); + expect(currentUser.getFirstSeenTime()).to.lessThan( + nowAfterLogin.getTime(), + ); const user1 = mParticle.Identity.getUser(testMPID); user1.getFirstSeenTime().should.equal(user1FirstSeen); @@ -3190,7 +3392,9 @@ describe('identity', function() { mParticle.Identity.login(); - await waitForCondition(() => mParticle.Identity.getCurrentUser().getMPID() === testMPID) + await waitForCondition( + () => mParticle.Identity.getCurrentUser().getMPID() === testMPID, + ); currentUser = mParticle.Identity.getCurrentUser(); expect(currentUser.getMPID()).to.equal(testMPID); @@ -3242,7 +3446,7 @@ describe('identity', function() { const errorMessages = []; mParticle._resetForTests(MPConfig); mParticle.config.logger = { - error: function(msg) { + error: function (msg) { errorMessages.push(msg); }, }; @@ -3287,12 +3491,12 @@ describe('identity', function() { mParticle.init(apiKey, window.mParticle.config); - await waitForCondition(hasIdentityCallInflightReturned) + await waitForCondition(hasIdentityCallInflightReturned); expect(identityResult.getUser().getMPID()).to.equal('testMPID'); expect(identityResult.getPreviousUser()).to.not.equal(null); expect(identityResult.getPreviousUser().getMPID()).to.equal( - 'testMPID2' + 'testMPID2', ); }); @@ -3313,7 +3517,7 @@ describe('identity', function() { mParticle.init(apiKey, window.mParticle.config); - await waitForCondition(hasIdentifyReturned) + await waitForCondition(hasIdentifyReturned); fetchMockSuccess(urls.login, { mpid: testMPID, @@ -3328,7 +3532,7 @@ describe('identity', function() { mParticle.Identity.login(EmptyUserIdentities, identityCallback); expect(mParticle.Identity.getCurrentUser().getMPID()).to.equal( - 'testMPID' + 'testMPID', ); expect(loginResult.getUser().getMPID()).to.equal('testMPID'); expect(loginResult.getPreviousUser()).to.not.be.null; @@ -3339,7 +3543,7 @@ describe('identity', function() { mParticle._resetForTests(MPConfig); let callbackCalled = false; - await waitForCondition(hasBeforeEachCallbackReturned) + await waitForCondition(hasBeforeEachCallbackReturned); const cookies = JSON.stringify({ gs: { @@ -3375,22 +3579,18 @@ describe('identity', function() { let identityResult; - await waitForCondition(() => mParticle.Identity.getCurrentUser()?.getMPID() === '1') + await waitForCondition( + () => mParticle.Identity.getCurrentUser()?.getMPID() === '1', + ); - mParticle.Identity.identify(EmptyUserIdentities, function(result) { + mParticle.Identity.identify(EmptyUserIdentities, function (result) { identityResult = result; callbackCalled = true; }); - await waitForCondition(() => callbackCalled) - identityResult - .getUser() - .getMPID() - .should.equal('1'); - identityResult - .getPreviousUser() - .getMPID() - .should.equal('4'); + await waitForCondition(() => callbackCalled); + identityResult.getUser().getMPID().should.equal('1'); + identityResult.getPreviousUser().getMPID().should.equal('4'); }); it('Alias request should be received when API is called validly', async (done) => { @@ -3416,7 +3616,7 @@ describe('identity', function() { expect(requestBody['request_type']).to.equal('alias'); expect(requestBody['environment']).to.equal('production'); expect(requestBody['api_key']).to.equal( - mParticle.getInstance()._Store.devToken + mParticle.getInstance()._Store.devToken, ); const dataBody = requestBody['data']; expect(dataBody).to.not.equal(null); @@ -3459,7 +3659,7 @@ describe('identity', function() { let warnMessage = null; mParticle.config.logger = { - warning: function(msg) { + warning: function (msg) { warnMessage = msg; }, }; @@ -3467,41 +3667,41 @@ describe('identity', function() { let callbackResult; // intentionally missing sourceMpid - let aliasRequest: IAliasRequest = ({ + let aliasRequest: IAliasRequest = { destinationMpid: 'destinationMpid', startTime: 3, endTime: 4, - } as unknown) as IAliasRequest; + } as unknown as IAliasRequest; - mParticle.Identity.aliasUsers(aliasRequest, function(callback) { + mParticle.Identity.aliasUsers(aliasRequest, function (callback) { callbackResult = callback; }); callbackResult.httpCode.should.equal(HTTPCodes.validationIssue); expect(callbackResult.message).to.equal( - Constants.Messages.ValidationMessages.AliasMissingMpid + Constants.Messages.ValidationMessages.AliasMissingMpid, ); expect(warnMessage).to.equal( - Constants.Messages.ValidationMessages.AliasMissingMpid + Constants.Messages.ValidationMessages.AliasMissingMpid, ); callbackResult = null; warnMessage = null; // intentionally missing destinationMpid - aliasRequest = ({ + aliasRequest = { sourceMpid: 'sourceMpid', startTime: 3, endTime: 4, - } as unknown) as IAliasRequest; + } as unknown as IAliasRequest; - mParticle.Identity.aliasUsers(aliasRequest, function(callback) { + mParticle.Identity.aliasUsers(aliasRequest, function (callback) { callbackResult = callback; }); callbackResult.httpCode.should.equal(HTTPCodes.validationIssue); expect(callbackResult.message).to.equal( - Constants.Messages.ValidationMessages.AliasMissingMpid + Constants.Messages.ValidationMessages.AliasMissingMpid, ); expect(warnMessage).to.equal( - Constants.Messages.ValidationMessages.AliasMissingMpid + Constants.Messages.ValidationMessages.AliasMissingMpid, ); callbackResult = null; warnMessage = null; @@ -3513,16 +3713,16 @@ describe('identity', function() { startTime: 3, endTime: 4, }; - mParticle.Identity.aliasUsers(aliasRequest, function(callback) { + mParticle.Identity.aliasUsers(aliasRequest, function (callback) { callbackResult = callback; }); callbackResult.httpCode.should.equal(HTTPCodes.validationIssue); expect(callbackResult.message).to.equal( - Constants.Messages.ValidationMessages.AliasNonUniqueMpid + Constants.Messages.ValidationMessages.AliasNonUniqueMpid, ); expect(warnMessage).to.equal( - Constants.Messages.ValidationMessages.AliasNonUniqueMpid + Constants.Messages.ValidationMessages.AliasNonUniqueMpid, ); callbackResult = null; warnMessage = null; @@ -3534,34 +3734,34 @@ describe('identity', function() { startTime: 4, endTime: 3, }; - mParticle.Identity.aliasUsers(aliasRequest, function(callback) { + mParticle.Identity.aliasUsers(aliasRequest, function (callback) { callbackResult = callback; }); callbackResult.httpCode.should.equal(HTTPCodes.validationIssue); expect(callbackResult.message).to.equal( - Constants.Messages.ValidationMessages.AliasStartBeforeEndTime + Constants.Messages.ValidationMessages.AliasStartBeforeEndTime, ); expect(warnMessage).to.equal( - Constants.Messages.ValidationMessages.AliasStartBeforeEndTime + Constants.Messages.ValidationMessages.AliasStartBeforeEndTime, ); callbackResult = null; warnMessage = null; // intentionally missing endTime and startTime - aliasRequest = ({ + aliasRequest = { destinationMpid: 'destinationMpid', sourceMpid: 'sourceMpid', - } as unknown) as IAliasRequest; + } as unknown as IAliasRequest; - mParticle.Identity.aliasUsers(aliasRequest, function(callback) { + mParticle.Identity.aliasUsers(aliasRequest, function (callback) { callbackResult = callback; }); callbackResult.httpCode.should.equal(HTTPCodes.validationIssue); expect(callbackResult.message).to.equal( - Constants.Messages.ValidationMessages.AliasMissingTime + Constants.Messages.ValidationMessages.AliasMissingTime, ); expect(warnMessage).to.equal( - Constants.Messages.ValidationMessages.AliasMissingTime + Constants.Messages.ValidationMessages.AliasMissingTime, ); callbackResult = null; warnMessage = null; @@ -3581,7 +3781,7 @@ describe('identity', function() { fetchMock.resetHistory(); - mParticle.Identity.aliasUsers(aliasRequest, function(callback) { + mParticle.Identity.aliasUsers(aliasRequest, function (callback) { callbackResult = callback; callbackResult.httpCode.should.equal(HTTP_ACCEPTED); expect(callbackResult.message).to.equal(undefined); @@ -3593,17 +3793,14 @@ describe('identity', function() { it('should parse error info from Alias Requests', async () => { mParticle.init(apiKey, window.mParticle.config); const errorMessage = 'this is a sample error message'; - let callbackResult; - fetchMock.post( - urls.alias, - { - status: 400, - body: JSON.stringify({ - message: errorMessage, - code: 'ignored code', - }), - } - ); + let callbackResult; + fetchMock.post(urls.alias, { + status: 400, + body: JSON.stringify({ + message: errorMessage, + code: 'ignored code', + }), + }); const aliasRequest = { destinationMpid: 'destinationMpid', @@ -3612,7 +3809,7 @@ describe('identity', function() { endTime: 4, }; - mParticle.Identity.aliasUsers(aliasRequest, function(callback) { + mParticle.Identity.aliasUsers(aliasRequest, function (callback) { callbackResult = callback; callbackResult.httpCode.should.equal(400); callbackResult.message.should.equal(errorMessage); @@ -3638,7 +3835,7 @@ describe('identity', function() { mParticle.init(apiKey, window.mParticle.config); - await waitForCondition(hasIdentityCallInflightReturned) + await waitForCondition(hasIdentityCallInflightReturned); // Mock clock so we can use simple integers for time clock = sinon.useFakeTimers(); @@ -3649,7 +3846,7 @@ describe('identity', function() { const aliasRequest = mParticle.Identity.createAliasRequest( sourceUser, - destinationUser + destinationUser, ); expect(aliasRequest.sourceMpid).to.equal('1'); expect(aliasRequest.destinationMpid).to.equal('2'); @@ -3677,7 +3874,7 @@ describe('identity', function() { setCookie(workspaceCookieName, cookies); mParticle.init(apiKey, window.mParticle.config); - await waitForCondition(hasIdentityCallInflightReturned) + await waitForCondition(hasIdentityCallInflightReturned); // Mock clock so we can use simple integers for time clock = sinon.useFakeTimers(); @@ -3688,7 +3885,7 @@ describe('identity', function() { const aliasRequest = mParticle.Identity.createAliasRequest( sourceUser, - destinationUser + destinationUser, ); expect(aliasRequest.sourceMpid).to.equal('2'); expect(aliasRequest.destinationMpid).to.equal('3'); @@ -3722,7 +3919,7 @@ describe('identity', function() { mParticle.init(apiKey, window.mParticle.config); - await waitForCondition(hasIdentityCallInflightReturned) + await waitForCondition(hasIdentityCallInflightReturned); clock = sinon.useFakeTimers(); clock.tick(millisPerDay * 2); @@ -3732,7 +3929,7 @@ describe('identity', function() { const aliasRequest = mParticle.Identity.createAliasRequest( sourceUser, - destinationUser + destinationUser, ); expect(aliasRequest.sourceMpid).to.equal('1'); expect(aliasRequest.destinationMpid).to.equal('2'); @@ -3753,7 +3950,7 @@ describe('identity', function() { let warnMessage = null; mParticle.config.logger = { - warning: function(msg) { + warning: function (msg) { warnMessage = msg; }, }; @@ -3776,7 +3973,7 @@ describe('identity', function() { mParticle.init(apiKey, window.mParticle.config); - await waitForCondition(hasIdentityCallInflightReturned) + await waitForCondition(hasIdentityCallInflightReturned); // Mock clock so we can use simple integers for time clock = sinon.useFakeTimers(); @@ -3787,7 +3984,7 @@ describe('identity', function() { const aliasRequest = mParticle.Identity.createAliasRequest( sourceUser, - destinationUser + destinationUser, ); expect(aliasRequest.sourceMpid).to.equal('1'); expect(aliasRequest.destinationMpid).to.equal('2'); @@ -3800,7 +3997,7 @@ describe('identity', function() { expect(warnMessage).to.equal( 'Source User has not been seen in the last ' + mParticle.getInstance()._Store.SDKConfig.maxAliasWindow + - ' days, Alias Request will likely fail' + ' days, Alias Request will likely fail', ); clock.restore(); @@ -3813,7 +4010,7 @@ describe('identity', function() { fetchMock.post(urls.alias, HTTP_ACCEPTED); mParticle.init(apiKey, window.mParticle.config); - + const aliasRequest = { destinationMpid: 'destinationMpid', sourceMpid: 'sourceMpid', @@ -3823,7 +4020,7 @@ describe('identity', function() { // reset history to remove all calls from fetchMock.calls so that after alias-ing users, it will have a single call fetchMock.resetHistory(); - mParticle.Identity.aliasUsers(aliasRequest) + mParticle.Identity.aliasUsers(aliasRequest); expect(fetchMock.calls().length).to.equal(1); @@ -3836,7 +4033,7 @@ describe('identity', function() { mParticle.init(apiKey, window.mParticle.config); - await waitForCondition(hasIdentityCallInflightReturned) + await waitForCondition(hasIdentityCallInflightReturned); mParticle.getInstance()._Store.isFirstRun.should.equal(false); @@ -3847,7 +4044,7 @@ describe('identity', function() { mParticle.Identity.login({ userIdentities: { customerid: 'abc' } }); - await waitForCondition(hasIdentityCallInflightReturned) + await waitForCondition(hasIdentityCallInflightReturned); const ls = mParticle.getInstance()._Persistence.getLocalStorage(); ls['testMPID'].lst.should.not.equal(null); @@ -3862,21 +4059,24 @@ describe('identity', function() { result = response; } - fetchMock.post(urls.identify, { - status: '0', - body: JSON.stringify({ body: null }), - }, { - overwriteRoutes: true - }); + fetchMock.post( + urls.identify, + { + status: '0', + body: JSON.stringify({ body: null }), + }, + { + overwriteRoutes: true, + }, + ); mParticle.config.identityCallback = identityCallback; mParticle.init(apiKey, window.mParticle.config); - await waitForCondition(hasIdentityCallInflightReturned) + await waitForCondition(hasIdentityCallInflightReturned); result.httpCode.should.equal(-1); - }); describe('custom device', function () { @@ -3884,70 +4084,86 @@ describe('identity', function() { fetchMock.restore(); }); - it('should use the custom device id in known_identities when passed via setDeviceId', async () => { - mParticle._resetForTests(MPConfig); + it('should use the custom device id in known_identities when passed via setDeviceId', async () => { + mParticle._resetForTests(MPConfig); - fetchMockSuccess(urls.identify, { - body: null - }); + fetchMockSuccess(urls.identify, { + body: null, + }); - mParticle.init(apiKey, window.mParticle.config); + mParticle.init(apiKey, window.mParticle.config); - await waitForCondition(hasIdentityCallInflightReturned) - expect(fetchMock.calls().length).to.equal(1); - const firstCall = fetchMock.calls()[0]; - expect(firstCall[0].split('/')[4]).to.equal('identify'); - const data = JSON.parse(firstCall[1].body as unknown as string) as IIdentityAPIRequestData; - - // Should be a 36 character guid - expect(data.known_identities).to.have.keys('device_application_stamp'); - expect(data.known_identities.device_application_stamp.length).to.equal(36); + await waitForCondition(hasIdentityCallInflightReturned); + expect(fetchMock.calls().length).to.equal(1); + const firstCall = fetchMock.calls()[0]; + expect(firstCall[0].split('/')[4]).to.equal('identify'); + const data = JSON.parse( + firstCall[1].body as unknown as string, + ) as IIdentityAPIRequestData; - mParticle.setDeviceId('foo-guid'); + // Should be a 36 character guid + expect(data.known_identities).to.have.keys( + 'device_application_stamp', + ); + expect( + data.known_identities.device_application_stamp.length, + ).to.equal(36); - fetchMockSuccess(urls.login, { - mpid: 'logged-in-user', - }); + mParticle.setDeviceId('foo-guid'); - mParticle.Identity.login({ userIdentities: { customerid: 'test' } }); + fetchMockSuccess(urls.login, { + mpid: 'logged-in-user', + }); - await waitForCondition(hasLoginReturned) + mParticle.Identity.login({ + userIdentities: { customerid: 'test' }, + }); - // Should include two more calls: Login and UIC - expect(fetchMock.calls().length).to.equal(2); - const nextCall = fetchMock.calls()[1]; - expect(nextCall[0].split('/')[4]).to.equal('login'); + await waitForCondition(hasLoginReturned); - const data2 = JSON.parse(nextCall[1].body as unknown as string) as IIdentityAPIRequestData; - expect(data2.known_identities.device_application_stamp).to.equal('foo-guid'); - }); + // Should include two more calls: Login and UIC + expect(fetchMock.calls().length).to.equal(2); + const nextCall = fetchMock.calls()[1]; + expect(nextCall[0].split('/')[4]).to.equal('login'); - it('should use the custom device id in known_identities when set via mParticle.config', async (done) => { - mParticle._resetForTests(MPConfig); + const data2 = JSON.parse( + nextCall[1].body as unknown as string, + ) as IIdentityAPIRequestData; + expect(data2.known_identities.device_application_stamp).to.equal( + 'foo-guid', + ); + }); - // Resets fetchMock so we can isolate calls for this tests - fetchMock.restore(); + it('should use the custom device id in known_identities when set via mParticle.config', async (done) => { + mParticle._resetForTests(MPConfig); + + // Resets fetchMock so we can isolate calls for this tests + fetchMock.restore(); - fetchMockSuccess(urls.identify, { body: null }); + fetchMockSuccess(urls.identify, { body: null }); - window.mParticle.config.deviceId = 'foo-guid'; - mParticle.init(apiKey, window.mParticle.config); + window.mParticle.config.deviceId = 'foo-guid'; + mParticle.init(apiKey, window.mParticle.config); - expect(fetchMock.calls().length).to.equal(1); + expect(fetchMock.calls().length).to.equal(1); - const lastCall = fetchMock.lastCall(); - const data = JSON.parse( - lastCall[1].body as unknown as string - ) as IIdentityAPIRequestData; + const lastCall = fetchMock.lastCall(); + const data = JSON.parse( + lastCall[1].body as unknown as string, + ) as IIdentityAPIRequestData; - expect(data.known_identities).to.have.keys('device_application_stamp'); - expect(data.known_identities.device_application_stamp).to.equal('foo-guid'); + expect(data.known_identities).to.have.keys( + 'device_application_stamp', + ); + expect(data.known_identities.device_application_stamp).to.equal( + 'foo-guid', + ); - done(); - }); + done(); + }); }); - describe('identity caching', function() { + describe('identity caching', function () { beforeEach(function () { fetchMock.restore(); }); @@ -3959,14 +4175,14 @@ describe('identity', function() { mParticle._resetForTests(MPConfig); fetchMock.resetHistory(); - await waitForCondition(hasIdentifyReturned) + await waitForCondition(hasIdentifyReturned); fetchMockSuccess( urls.identify, { mpid: testMPID, is_logged_in: false, }, - { 'x-mp-max-age': X_MP_MAX_AGE } + { 'x-mp-max-age': X_MP_MAX_AGE }, ); const identities = { @@ -3988,15 +4204,15 @@ describe('identity', function() { mParticle.Identity.getCurrentUser()?.getUserIdentities() ?.userIdentities?.email === 'test@gmail.com' ); - }) + }); const now = new Date(); const idCache: IdentityCache = JSON.parse( - localStorage.getItem('mprtcl-v4_abcdef-id-cache') + localStorage.getItem('mprtcl-v4_abcdef-id-cache'), ); // a single identify cache key will be on the idCache expect(Object.keys(idCache).length).to.equal(1); - for (let key in idCache) { + for (const key in idCache) { // X_MP_MAX_AGE is a header value, which is a string, // We want to make sure that the expireTimestamp is evaluated // as a number. @@ -4007,11 +4223,11 @@ describe('identity', function() { // to tick the clock forward or be exact in our timing. // Instead, we can expect the expireTimestamp to be within 1 second // of the max age + expect(idCache[key].expireTimestamp).to.greaterThan( + expectedExpiredTimestamp, + ); expect( - idCache[key].expireTimestamp - ).to.greaterThan(expectedExpiredTimestamp); - expect( - idCache[key].expireTimestamp - now.getTime() + idCache[key].expireTimestamp - now.getTime(), ).to.lessThan(1000); } }); @@ -4021,12 +4237,16 @@ describe('identity', function() { mParticle._resetForTests(MPConfig); - fetchMockSuccess(urls.identify, { - mpid: testMPID, - is_logged_in: false, - }, { - 'x-mp-max-age': X_MP_MAX_AGE, - }); + fetchMockSuccess( + urls.identify, + { + mpid: testMPID, + is_logged_in: false, + }, + { + 'x-mp-max-age': X_MP_MAX_AGE, + }, + ); fetchMock.resetHistory(); @@ -4041,8 +4261,7 @@ describe('identity', function() { mParticle.config.flags.cacheIdentity = 'True'; mParticle.init(apiKey, window.mParticle.config); - - await waitForCondition(hasIdentityCallInflightReturned) + await waitForCondition(hasIdentityCallInflightReturned); // Just make sure calls were actually made expect(fetchMock.calls().length).to.greaterThanOrEqual(1); @@ -4054,7 +4273,7 @@ describe('identity', function() { const callback = sinon.spy(); mParticle.Identity.identify(identities, callback); - await waitForCondition(hasIdentifyReturned) + await waitForCondition(hasIdentifyReturned); expect(fetchMock.calls().length).to.equal(0); // callback still gets called even if the identity call is not made` @@ -4068,12 +4287,16 @@ describe('identity', function() { mParticle._resetForTests(MPConfig); - fetchMockSuccess(urls.identify, { - mpid: testMPID, - is_logged_in: false, - }, { - 'x-mp-max-age': X_MP_MAX_AGE, - }); + fetchMockSuccess( + urls.identify, + { + mpid: testMPID, + is_logged_in: false, + }, + { + 'x-mp-max-age': X_MP_MAX_AGE, + }, + ); fetchMock.resetHistory(); @@ -4088,7 +4311,7 @@ describe('identity', function() { mParticle.config.flags.cacheIdentity = 'True'; mParticle.init(apiKey, window.mParticle.config); - await waitForCondition(hasIdentityCallInflightReturned) + await waitForCondition(hasIdentityCallInflightReturned); const initialIdentityCall = fetchMock.calls()[0]; expect(initialIdentityCall[0].split('/')[4]).to.equal('identify'); @@ -4107,7 +4330,7 @@ describe('identity', function() { clock.restore(); - await waitForCondition(() => callbackCalled) + await waitForCondition(() => callbackCalled); expect(fetchMock.calls().length).to.equal(1); const duplicateIdentityCall = fetchMock.calls()[0]; @@ -4123,19 +4346,27 @@ describe('identity', function() { mParticle._resetForTests(MPConfig); - fetchMockSuccess(urls.identify, { - mpid: testMPID, - is_logged_in: true, - }, { - 'x-mp-max-age': X_MP_MAX_AGE, - }); + fetchMockSuccess( + urls.identify, + { + mpid: testMPID, + is_logged_in: true, + }, + { + 'x-mp-max-age': X_MP_MAX_AGE, + }, + ); - fetchMockSuccess(urls.login, { - mpid: testMPID, - is_logged_in: true, - }, { - 'x-mp-max-age': X_MP_MAX_AGE, - }); + fetchMockSuccess( + urls.login, + { + mpid: testMPID, + is_logged_in: true, + }, + { + 'x-mp-max-age': X_MP_MAX_AGE, + }, + ); fetchMock.resetHistory(); @@ -4150,7 +4381,7 @@ describe('identity', function() { mParticle.config.flags.cacheIdentity = 'True'; mParticle.init(apiKey, window.mParticle.config); - await waitForCondition(hasIdentityCallInflightReturned) + await waitForCondition(hasIdentityCallInflightReturned); fetchMock.resetHistory(); @@ -4160,7 +4391,11 @@ describe('identity', function() { mParticle.Identity.login(identities, callback); - await waitForCondition(() => mParticle.Identity?.getCurrentUser()?.getMPID() === testMPID) + await waitForCondition( + () => + mParticle.Identity?.getCurrentUser()?.getMPID() === + testMPID, + ); // Just make sure calls were actually made expect(fetchMock.calls().length).to.greaterThanOrEqual(1); @@ -4175,7 +4410,7 @@ describe('identity', function() { await waitForCondition(() => { return callbackCalled; - }) + }); expect(fetchMock.calls().length).to.equal(0); @@ -4190,20 +4425,27 @@ describe('identity', function() { mParticle._resetForTests(MPConfig); - fetchMockSuccess(urls.identify, { - mpid: testMPID, - is_logged_in: true, - }, { - 'x-mp-max-age': X_MP_MAX_AGE, - }); - - fetchMockSuccess(urls.login, { - mpid: testMPID, - is_logged_in: true, - }, { - 'x-mp-max-age': X_MP_MAX_AGE, - }); + fetchMockSuccess( + urls.identify, + { + mpid: testMPID, + is_logged_in: true, + }, + { + 'x-mp-max-age': X_MP_MAX_AGE, + }, + ); + fetchMockSuccess( + urls.login, + { + mpid: testMPID, + is_logged_in: true, + }, + { + 'x-mp-max-age': X_MP_MAX_AGE, + }, + ); fetchMock.resetHistory(); @@ -4218,7 +4460,7 @@ describe('identity', function() { mParticle.config.flags.cacheIdentity = 'True'; mParticle.init(apiKey, window.mParticle.config); - await waitForCondition(hasIdentityCallInflightReturned) + await waitForCondition(hasIdentityCallInflightReturned); const initialIdentityCall = fetchMock.calls()[0]; expect(initialIdentityCall[0].split('/')[4]).to.equal('identify'); @@ -4231,7 +4473,7 @@ describe('identity', function() { mParticle.Identity.login(identities, callback); - await waitForCondition(() => callbackCalled) + await waitForCondition(() => callbackCalled); // Just make sure calls were actually made expect(fetchMock.calls().length).to.greaterThanOrEqual(1); @@ -4250,7 +4492,7 @@ describe('identity', function() { clock.restore(); - await waitForCondition(() => callbackCalled) + await waitForCondition(() => callbackCalled); expect(fetchMock.calls().length).to.equal(1); const secondLoginCall = fetchMock.calls()[0]; @@ -4263,23 +4505,31 @@ describe('identity', function() { const X_MP_MAX_AGE = '1'; mParticle._resetForTests(MPConfig); - fetchMockSuccess(urls.identify, { - mpid: testMPID, - is_logged_in: true, - }, { - 'x-mp-max-age': X_MP_MAX_AGE, - }); + fetchMockSuccess( + urls.identify, + { + mpid: testMPID, + is_logged_in: true, + }, + { + 'x-mp-max-age': X_MP_MAX_AGE, + }, + ); - fetchMockSuccess(urls.modify, { - change_results: [ - { - identity_type: 'customerid', - modified_mpid: testMPID, - }, - ], - }, { - 'x-mp-max-age': X_MP_MAX_AGE, - }); + fetchMockSuccess( + urls.modify, + { + change_results: [ + { + identity_type: 'customerid', + modified_mpid: testMPID, + }, + ], + }, + { + 'x-mp-max-age': X_MP_MAX_AGE, + }, + ); fetchMock.resetHistory(); @@ -4295,7 +4545,7 @@ describe('identity', function() { mParticle.init(apiKey, window.mParticle.config); - await waitForCondition(hasIdentityCallInflightReturned) + await waitForCondition(hasIdentityCallInflightReturned); const idCache = localStorage.getItem('mprtcl-v4_abcdef-id-cache'); expect(idCache).to.be.ok; @@ -4306,9 +4556,9 @@ describe('identity', function() { }, }); - await waitForCondition(hasIdentityCallInflightReturned) + await waitForCondition(hasIdentityCallInflightReturned); const secondIdCache = localStorage.getItem( - 'mprtcl-v4_abcdef-id-cache' + 'mprtcl-v4_abcdef-id-cache', ); expect(secondIdCache).to.not.be.ok; @@ -4318,19 +4568,27 @@ describe('identity', function() { const X_MP_MAX_AGE = '1'; mParticle._resetForTests(MPConfig); - fetchMockSuccess(urls.identify, { - mpid: testMPID, - is_logged_in: true, - }, { - 'x-mp-max-age': X_MP_MAX_AGE, - }); + fetchMockSuccess( + urls.identify, + { + mpid: testMPID, + is_logged_in: true, + }, + { + 'x-mp-max-age': X_MP_MAX_AGE, + }, + ); - fetchMockSuccess(urls.logout, { - mpid: 'otherMPID', - is_logged_in: false - }, { - 'x-mp-max-age': X_MP_MAX_AGE, - }); + fetchMockSuccess( + urls.logout, + { + mpid: 'otherMPID', + is_logged_in: false, + }, + { + 'x-mp-max-age': X_MP_MAX_AGE, + }, + ); fetchMock.resetHistory(); @@ -4346,29 +4604,29 @@ describe('identity', function() { mParticle.init(apiKey, window.mParticle.config); - await waitForCondition(hasIdentityCallInflightReturned) + await waitForCondition(hasIdentityCallInflightReturned); - let idCache = localStorage.getItem('mprtcl-v4_abcdef-id-cache'); + const idCache = localStorage.getItem('mprtcl-v4_abcdef-id-cache'); expect(idCache).to.be.ok; mParticle.Identity.logout(); - await waitForCondition(hasIdentityCallInflightReturned) + await waitForCondition(hasIdentityCallInflightReturned); - let secondIdCache = localStorage.getItem( - 'mprtcl-v4_abcdef-id-cache' + const secondIdCache = localStorage.getItem( + 'mprtcl-v4_abcdef-id-cache', ); expect(secondIdCache).to.not.be.ok; }); }); - describe('Rokt Manager', function() { + describe('Rokt Manager', function () { let roktConfig: IKitConfigs; let roktKit: IRoktKit; const testRoktEmail = 'test@rokt.com'; const testRoktMPID = 'rokt-user'; - beforeEach(function() { + beforeEach(function () { mParticle._resetForTests(MPConfig); fetchMock.resetHistory(); @@ -4396,45 +4654,60 @@ describe('identity', function() { }, }); - mParticle.init(apiKey, { ...window.mParticle.config, kitConfigs: [roktConfig] }); + mParticle.init(apiKey, { + ...window.mParticle.config, + kitConfigs: [roktConfig], + }); await waitForCondition(() => hasIdentifyReturned(testRoktMPID)); const mpInstance = mParticle.getInstance(); mpInstance._RoktManager.attachKit(roktKit); - + mParticle.Identity.identify({ userIdentities: { email: testRoktEmail, }, }); - await waitForCondition(() => hasIdentifyReturnedWithEmail(testRoktEmail)); + await waitForCondition(() => + hasIdentifyReturnedWithEmail(testRoktEmail), + ); expect(mpInstance._RoktManager['currentUser']).to.not.be.null; - expect(mpInstance._RoktManager['currentUser'].getUserIdentities().userIdentities.email).to.equal(testRoktEmail); + expect( + mpInstance._RoktManager['currentUser'].getUserIdentities() + .userIdentities.email, + ).to.equal(testRoktEmail); }); it('should not set currentUser if the initial identify call is not successful', async () => { - fetchMock.post(urls.identify, { - status: HTTP_BAD_REQUEST, - body: { - Errors: [ - { - message: 'knownIdentities is empty.', - code: 'LOOKUP_ERROR' - }, - ], - ErrorCode: 'LOOKUP_ERROR', - StatusCode: HTTP_BAD_REQUEST, - RequestId: '123', + fetchMock.post( + urls.identify, + { + status: HTTP_BAD_REQUEST, + body: { + Errors: [ + { + message: 'knownIdentities is empty.', + code: 'LOOKUP_ERROR', + }, + ], + ErrorCode: 'LOOKUP_ERROR', + StatusCode: HTTP_BAD_REQUEST, + RequestId: '123', + }, }, - }, { - overwriteRoutes: true, - }); + { + overwriteRoutes: true, + }, + ); - mParticle.init(apiKey, { ...window.mParticle.config, kitConfigs: [roktConfig] }); + mParticle.init(apiKey, { + ...window.mParticle.config, + kitConfigs: [roktConfig], + }); await waitForCondition(hasIdentityCallInflightReturned); @@ -4445,7 +4718,7 @@ describe('identity', function() { await waitForCondition(hasIdentityCallInflightReturned); expect(mpInstance._RoktManager['currentUser']).be.null; - }) + }); it('should not set currentUser if the email is not positively identified', async () => { fetchMockSuccess(urls.identify, { @@ -4458,26 +4731,33 @@ describe('identity', function() { is_logged_in: false, }); - mParticle.init(apiKey, { ...window.mParticle.config, kitConfigs: [roktConfig] }); + mParticle.init(apiKey, { + ...window.mParticle.config, + kitConfigs: [roktConfig], + }); await waitForCondition(() => hasIdentifyReturned('testMPID')); - fetchMock.post(urls.identify, { - status: HTTP_BAD_REQUEST, - body: { - Errors: [ - { - message: 'knownIdentities is empty.', - code: 'LOOKUP_ERROR' - }, - ], - ErrorCode: 'LOOKUP_ERROR', - StatusCode: HTTP_BAD_REQUEST, - RequestId: '123', + fetchMock.post( + urls.identify, + { + status: HTTP_BAD_REQUEST, + body: { + Errors: [ + { + message: 'knownIdentities is empty.', + code: 'LOOKUP_ERROR', + }, + ], + ErrorCode: 'LOOKUP_ERROR', + StatusCode: HTTP_BAD_REQUEST, + RequestId: '123', + }, }, - }, { - overwriteRoutes: true, - }); + { + overwriteRoutes: true, + }, + ); const mpInstance = mParticle.getInstance(); @@ -4494,30 +4774,30 @@ describe('identity', function() { // Current user will be the initial anonymous user from the initial identify call via mParticle.init // but should not have an email expect(mpInstance._RoktManager['currentUser']).to.not.be.null; - expect(mpInstance._RoktManager['currentUser'].getUserIdentities().userIdentities.email).to.equal(undefined); - }) + expect( + mpInstance._RoktManager['currentUser'].getUserIdentities() + .userIdentities.email, + ).to.equal(undefined); + }); }); - describe('Deprecate Cart', function() { - afterEach(function() { + describe('Deprecate Cart', function () { + afterEach(function () { sinon.restore(); }); it("should deprecate the user's cart", async () => { mParticle.init(apiKey, window.mParticle.config); const bond = sinon.spy(mParticle.getInstance().Logger, 'warning'); - await waitForCondition(hasIdentifyReturned) - mParticle - .getInstance() - .Identity.getCurrentUser() - .getCart(); + await waitForCondition(hasIdentifyReturned); + mParticle.getInstance().Identity.getCurrentUser().getCart(); mParticle.Identity.getCurrentUser().getCart(); bond.called.should.eql(true); bond.callCount.should.equal(2); bond.getCalls()[0].args[0].should.eql( - 'Deprecated function Identity.getCurrentUser().getCart() will be removed in future releases' + 'Deprecated function Identity.getCurrentUser().getCart() will be removed in future releases', ); }); @@ -4525,12 +4805,12 @@ describe('identity', function() { mParticle.init(apiKey, window.mParticle.config); const bond = sinon.spy(mParticle.getInstance().Logger, 'warning'); - await waitForCondition(hasIdentifyReturned) + await waitForCondition(hasIdentifyReturned); const product: SDKProduct = mParticle.eCommerce.createProduct( 'iPhone', '12345', - 400 + 400, ); mParticle .getInstance() @@ -4538,15 +4818,13 @@ describe('identity', function() { .getCart() .add(product); - mParticle.Identity.getCurrentUser() - .getCart() - .add(product); + mParticle.Identity.getCurrentUser().getCart().add(product); bond.called.should.eql(true); // deprecates on both .getCart, then .add bond.callCount.should.equal(4); bond.getCalls()[1].args[0].should.eql( - 'Deprecated function Identity.getCurrentUser().getCart().add() will be removed in future releases' + 'Deprecated function Identity.getCurrentUser().getCart().add() will be removed in future releases', ); }); @@ -4554,12 +4832,12 @@ describe('identity', function() { mParticle.init(apiKey, window.mParticle.config); const bond = sinon.spy(mParticle.getInstance().Logger, 'warning'); - await waitForCondition(hasIdentifyReturned) + await waitForCondition(hasIdentifyReturned); const product: SDKProduct = mParticle.eCommerce.createProduct( 'iPhone', '12345', - 400 + 400, ); mParticle @@ -4567,61 +4845,50 @@ describe('identity', function() { .Identity.getCurrentUser() .getCart() .remove(product, true); - mParticle.Identity.getCurrentUser() - .getCart() - .remove(product, true); + mParticle.Identity.getCurrentUser().getCart().remove(product, true); bond.called.should.eql(true); // deprecates on both .getCart, then .add bond.callCount.should.equal(4); bond.getCalls()[1].args[0].should.eql( - 'Deprecated function Identity.getCurrentUser().getCart().remove() will be removed in future releases' + 'Deprecated function Identity.getCurrentUser().getCart().remove() will be removed in future releases', ); }); it('should deprecate clear', async () => { mParticle.init(apiKey, window.mParticle.config); const bond = sinon.spy(mParticle.getInstance().Logger, 'warning'); - await waitForCondition(hasIdentifyReturned) - mParticle - .getInstance() - .Identity.getCurrentUser() - .getCart() - .clear(); - mParticle - .Identity.getCurrentUser() - .getCart() - .clear(); + await waitForCondition(hasIdentifyReturned); + mParticle.getInstance().Identity.getCurrentUser().getCart().clear(); + mParticle.Identity.getCurrentUser().getCart().clear(); bond.called.should.eql(true); // deprecates on both .getCart, then .add bond.callCount.should.equal(4); bond.getCalls()[1].args[0].should.eql( - 'Deprecated function Identity.getCurrentUser().getCart().clear() will be removed in future releases' + 'Deprecated function Identity.getCurrentUser().getCart().clear() will be removed in future releases', ); }); - + it('should deprecate getCartProducts', async () => { mParticle.init(apiKey, window.mParticle.config); const bond = sinon.spy(mParticle.getInstance().Logger, 'warning'); - await waitForCondition(hasIdentifyReturned) + await waitForCondition(hasIdentifyReturned); mParticle .getInstance() .Identity.getCurrentUser() .getCart() .getCartProducts(); - mParticle.Identity.getCurrentUser() - .getCart() - .getCartProducts(); + mParticle.Identity.getCurrentUser().getCart().getCartProducts(); - bond.called.should.eql(true); - // deprecates on both .getCart, then .add - bond.callCount.should.equal(4); - bond.getCalls()[1].args[0].should.eql( - 'Deprecated function Identity.getCurrentUser().getCart().getCartProducts() will be removed in future releases' - ); + bond.called.should.eql(true); + // deprecates on both .getCart, then .add + bond.callCount.should.equal(4); + bond.getCalls()[1].args[0].should.eql( + 'Deprecated function Identity.getCurrentUser().getCart().getCartProducts() will be removed in future releases', + ); }); }); }); diff --git a/test/src/tests-identityApiClient.ts b/test/src/tests-identityApiClient.ts index 9b7247972..44a9062c1 100644 --- a/test/src/tests-identityApiClient.ts +++ b/test/src/tests-identityApiClient.ts @@ -15,13 +15,15 @@ import Constants, { HTTP_SERVER_ERROR, HTTP_UNAUTHORIZED, } from '../../src/constants'; -import IdentityAPIClient, { IIdentityApiClient } from '../../src/identityApiClient'; +import IdentityAPIClient, { + IIdentityApiClient, +} from '../../src/identityApiClient'; import { IIdentityResponse } from '../../src/identity-user-interfaces'; import Utils from './config/utils'; import { IMParticleWebSDKInstance } from '../../src/mp-instance'; import { IMParticleInstanceManager } from '../../src/sdkRuntimeModels'; const { fetchMockSuccess } = Utils; -const { HTTPCodes } = Constants; +const { HTTPCodes } = Constants; declare global { interface Window { @@ -62,7 +64,7 @@ describe('Identity Api Client', () => { context: 'test-context', is_ephemeral: false, matched_identities: {}, - } + }; const expectedIdentityResponse: IIdentityResponse = { status: 200, @@ -71,13 +73,12 @@ describe('Identity Api Client', () => { expireTimestamp: 0, }; - it('should call parseIdentityResponse with the correct arguments', async () => { fetchMockSuccess(urls.identify, apiSuccessResponseBody); const callbackSpy = sinon.spy(); - const mpInstance: IMParticleWebSDKInstance = ({ + const mpInstance: IMParticleWebSDKInstance = { Logger: { verbose: () => {}, error: () => {}, @@ -95,10 +96,10 @@ describe('Identity Api Client', () => { }, }, _Persistence: {}, - } as unknown) as IMParticleWebSDKInstance; + } as unknown as IMParticleWebSDKInstance; const identityApiClient: IIdentityApiClient = new IdentityAPIClient( - mpInstance + mpInstance, ); const parseIdentityResponseSpy = sinon.spy(); @@ -110,16 +111,25 @@ describe('Identity Api Client', () => { originalIdentityApiData, parseIdentityResponseSpy, testMPID, - identityRequest.known_identities + identityRequest.known_identities, ); - expect(parseIdentityResponseSpy.calledOnce, 'Call parseIdentityResponse').to.eq(true); - expect(parseIdentityResponseSpy.args[0][0]).to.deep.equal(expectedIdentityResponse); + expect( + parseIdentityResponseSpy.calledOnce, + 'Call parseIdentityResponse', + ).to.eq(true); + expect(parseIdentityResponseSpy.args[0][0]).to.deep.equal( + expectedIdentityResponse, + ); expect(parseIdentityResponseSpy.args[0][1]).to.equal(testMPID); expect(parseIdentityResponseSpy.args[0][2]).to.be.a('function'); - expect(parseIdentityResponseSpy.args[0][3]).to.deep.equal(originalIdentityApiData); + expect(parseIdentityResponseSpy.args[0][3]).to.deep.equal( + originalIdentityApiData, + ); expect(parseIdentityResponseSpy.args[0][4]).to.equal('identify'); - expect(parseIdentityResponseSpy.args[0][5]).to.deep.equal(identityRequest.known_identities); + expect(parseIdentityResponseSpy.args[0][5]).to.deep.equal( + identityRequest.known_identities, + ); expect(parseIdentityResponseSpy.args[0][6]).to.equal(false); }); @@ -128,7 +138,7 @@ describe('Identity Api Client', () => { const invokeCallbackSpy = sinon.spy(); - const mpInstance: IMParticleWebSDKInstance = ({ + const mpInstance: IMParticleWebSDKInstance = { Logger: { verbose: () => {}, error: () => {}, @@ -147,10 +157,10 @@ describe('Identity Api Client', () => { identityCallInFlight: true, }, _Persistence: {}, - } as unknown) as IMParticleWebSDKInstance; + } as unknown as IMParticleWebSDKInstance; const identityApiClient: IIdentityApiClient = new IdentityAPIClient( - mpInstance + mpInstance, ); const parseIdentityResponseSpy = sinon.spy(); @@ -165,27 +175,38 @@ describe('Identity Api Client', () => { null, ); - expect(invokeCallbackSpy.calledOnce, 'invokeCallbackSpy called').to.eq(true); + expect( + invokeCallbackSpy.calledOnce, + 'invokeCallbackSpy called', + ).to.eq(true); expect(invokeCallbackSpy.args[0][0]).to.be.a('function'); expect(invokeCallbackSpy.args[0][1]).to.equal(-2); - expect(invokeCallbackSpy.args[0][2]).to.equal('There is currently an Identity request processing. Please wait for this to return before requesting again'); - - expect(parseIdentityResponseSpy.calledOnce, 'parseIdentityResponseSpy NOT called').to.eq(false); + expect(invokeCallbackSpy.args[0][2]).to.equal( + 'There is currently an Identity request processing. Please wait for this to return before requesting again', + ); + expect( + parseIdentityResponseSpy.calledOnce, + 'parseIdentityResponseSpy NOT called', + ).to.eq(false); }); it('should call invokeCallback with an error if the fetch fails', async () => { - fetchMock.post(urls.identify, { - status: 500, - throws: { message: 'server error' }, - }, { - overwriteRoutes: true, - }); + fetchMock.post( + urls.identify, + { + status: 500, + throws: { message: 'server error' }, + }, + { + overwriteRoutes: true, + }, + ); const callbackSpy = sinon.spy(); const invokeCallbackSpy = sinon.spy(); - const mpInstance: IMParticleWebSDKInstance = ({ + const mpInstance: IMParticleWebSDKInstance = { Logger: { verbose: () => {}, error: () => {}, @@ -204,10 +225,10 @@ describe('Identity Api Client', () => { identityCallInFlight: false, }, _Persistence: {}, - } as unknown) as IMParticleWebSDKInstance; + } as unknown as IMParticleWebSDKInstance; const identityApiClient: IIdentityApiClient = new IdentityAPIClient( - mpInstance + mpInstance, ); const parseIdentityResponseSpy = sinon.spy(); @@ -222,7 +243,10 @@ describe('Identity Api Client', () => { null, ); - expect(invokeCallbackSpy.calledOnce, 'invokeCallbackSpy called').to.eq(true); + expect( + invokeCallbackSpy.calledOnce, + 'invokeCallbackSpy called', + ).to.eq(true); expect(invokeCallbackSpy.args[0][0]).to.be.a('function'); expect(invokeCallbackSpy.args[0][0]).to.equal(callbackSpy); expect(invokeCallbackSpy.args[0][1]).to.equal(-1); @@ -242,7 +266,7 @@ describe('Identity Api Client', () => { const fetch = window.fetch; delete window.fetch; - const mpInstance: IMParticleWebSDKInstance = ({ + const mpInstance: IMParticleWebSDKInstance = { Logger: { verbose: () => {}, error: () => {}, @@ -261,10 +285,10 @@ describe('Identity Api Client', () => { identityCallInFlight: false, }, _Persistence: {}, - } as unknown) as IMParticleWebSDKInstance; + } as unknown as IMParticleWebSDKInstance; const identityApiClient: IIdentityApiClient = new IdentityAPIClient( - mpInstance + mpInstance, ); const parseIdentityResponseSpy = sinon.spy(); @@ -282,16 +306,25 @@ describe('Identity Api Client', () => { originalIdentityApiData, parseIdentityResponseSpy, testMPID, - identityRequest.known_identities + identityRequest.known_identities, ); - expect(parseIdentityResponseSpy.calledOnce, 'Call parseIdentityResponse').to.eq(true); - expect(parseIdentityResponseSpy.args[0][0]).to.deep.equal(expectedIdentityResponse); + expect( + parseIdentityResponseSpy.calledOnce, + 'Call parseIdentityResponse', + ).to.eq(true); + expect(parseIdentityResponseSpy.args[0][0]).to.deep.equal( + expectedIdentityResponse, + ); expect(parseIdentityResponseSpy.args[0][1]).to.equal(testMPID); expect(parseIdentityResponseSpy.args[0][2]).to.be.a('function'); - expect(parseIdentityResponseSpy.args[0][3]).to.deep.equal(originalIdentityApiData); + expect(parseIdentityResponseSpy.args[0][3]).to.deep.equal( + originalIdentityApiData, + ); expect(parseIdentityResponseSpy.args[0][4]).to.equal('identify'); - expect(parseIdentityResponseSpy.args[0][5]).to.deep.equal(identityRequest.known_identities); + expect(parseIdentityResponseSpy.args[0][5]).to.deep.equal( + identityRequest.known_identities, + ); expect(parseIdentityResponseSpy.args[0][6]).to.equal(false); window.fetch = fetch; @@ -302,7 +335,7 @@ describe('Identity Api Client', () => { const callbackSpy = sinon.spy(); - const mpInstance: IMParticleWebSDKInstance = ({ + const mpInstance: IMParticleWebSDKInstance = { Logger: { verbose: () => {}, error: () => {}, @@ -320,10 +353,10 @@ describe('Identity Api Client', () => { }, }, _Persistence: {}, - } as unknown) as IMParticleWebSDKInstance;; + } as unknown as IMParticleWebSDKInstance; const identityApiClient: IIdentityApiClient = new IdentityAPIClient( - mpInstance + mpInstance, ); const parseIdentityResponseSpy = sinon.spy(); @@ -335,7 +368,7 @@ describe('Identity Api Client', () => { originalIdentityApiData, parseIdentityResponseSpy, testMPID, - identityRequest.known_identities + identityRequest.known_identities, ); const expectedFetchPayload = { @@ -348,37 +381,49 @@ describe('Identity Api Client', () => { body: JSON.stringify(identityRequest), }; - expect(fetchMock.calls()[0][1].method, 'Payload Method').to.deep.equal(expectedFetchPayload.method); - expect(fetchMock.calls()[0][1].body, 'Payload Body').to.deep.equal(expectedFetchPayload.body); - expect(fetchMock.calls()[0][1].headers, 'Payload Headers').to.deep.equal(expectedFetchPayload.headers); + expect( + fetchMock.calls()[0][1].method, + 'Payload Method', + ).to.deep.equal(expectedFetchPayload.method); + expect(fetchMock.calls()[0][1].body, 'Payload Body').to.deep.equal( + expectedFetchPayload.body, + ); + expect( + fetchMock.calls()[0][1].headers, + 'Payload Headers', + ).to.deep.equal(expectedFetchPayload.headers); }); it('should include a detailed error message if the fetch returns a 400 (Bad Request)', async () => { const identityRequestError = { - "Errors": [ + Errors: [ { - "code": "LOOKUP_ERROR", - "message": "knownIdentities is empty." - } + code: 'LOOKUP_ERROR', + message: 'knownIdentities is empty.', + }, ], - "ErrorCode": "LOOKUP_ERROR", - "StatusCode": 400, - "RequestId": "6c6a234f-e171-4588-90a2-d7bc02530ec3" + ErrorCode: 'LOOKUP_ERROR', + StatusCode: 400, + RequestId: '6c6a234f-e171-4588-90a2-d7bc02530ec3', }; - fetchMock.post(urls.identify, { - status: HTTP_BAD_REQUEST, - body: identityRequestError, - }, { - overwriteRoutes: true, - }); + fetchMock.post( + urls.identify, + { + status: HTTP_BAD_REQUEST, + body: identityRequestError, + }, + { + overwriteRoutes: true, + }, + ); const callbackSpy = sinon.spy(); const invokeCallbackSpy = sinon.spy(); const verboseSpy = sinon.spy(); const errorSpy = sinon.spy(); - const mpInstance: IMParticleWebSDKInstance = ({ + const mpInstance: IMParticleWebSDKInstance = { Logger: { verbose: (message) => verboseSpy(message), error: (message) => errorSpy(message), @@ -397,10 +442,10 @@ describe('Identity Api Client', () => { }, }, _Persistence: {}, - } as unknown) as IMParticleWebSDKInstance; + } as unknown as IMParticleWebSDKInstance; const identityApiClient: IIdentityApiClient = new IdentityAPIClient( - mpInstance + mpInstance, ); const parseIdentityResponseSpy = sinon.spy(); @@ -412,7 +457,7 @@ describe('Identity Api Client', () => { originalIdentityApiData, parseIdentityResponseSpy, testMPID, - identityRequest.known_identities + identityRequest.known_identities, ); const expectedIdentityErrorRequest = { @@ -420,37 +465,56 @@ describe('Identity Api Client', () => { responseText: identityRequestError, cacheMAxAge: 0, expireTimestamp: 0, - } + }; expect(verboseSpy.lastCall, 'verboseSpy called').to.be.ok; - expect(verboseSpy.lastCall.firstArg).to.equal("Issue with sending Identity Request to mParticle Servers, received HTTP Code of 400 - knownIdentities is empty."); + expect(verboseSpy.lastCall.firstArg).to.equal( + 'Issue with sending Identity Request to mParticle Servers, received HTTP Code of 400 - knownIdentities is empty.', + ); // A 400 will still call parseIdentityResponse - expect(parseIdentityResponseSpy.calledOnce, 'parseIdentityResponseSpy').to.eq(true); - expect(parseIdentityResponseSpy.args[0][0].status, 'Identity Error Request Status').to.equal(expectedIdentityErrorRequest.status); - expect(parseIdentityResponseSpy.args[0][0].responseText, 'Identity Error Request responseText').to.deep.equal(expectedIdentityErrorRequest.responseText); + expect( + parseIdentityResponseSpy.calledOnce, + 'parseIdentityResponseSpy', + ).to.eq(true); + expect( + parseIdentityResponseSpy.args[0][0].status, + 'Identity Error Request Status', + ).to.equal(expectedIdentityErrorRequest.status); + expect( + parseIdentityResponseSpy.args[0][0].responseText, + 'Identity Error Request responseText', + ).to.deep.equal(expectedIdentityErrorRequest.responseText); expect(parseIdentityResponseSpy.args[0][1]).to.equal(testMPID); expect(parseIdentityResponseSpy.args[0][2]).to.be.a('function'); - expect(parseIdentityResponseSpy.args[0][3]).to.deep.equal(originalIdentityApiData); + expect(parseIdentityResponseSpy.args[0][3]).to.deep.equal( + originalIdentityApiData, + ); expect(parseIdentityResponseSpy.args[0][4]).to.equal('identify'); - expect(parseIdentityResponseSpy.args[0][5]).to.deep.equal(identityRequest.known_identities); + expect(parseIdentityResponseSpy.args[0][5]).to.deep.equal( + identityRequest.known_identities, + ); expect(parseIdentityResponseSpy.args[0][6]).to.equal(false); }); it('should include a detailed error message if the fetch returns a 401 (Unauthorized)', async () => { - fetchMock.post(urls.identify, { - status: HTTP_UNAUTHORIZED, - body: null, - }, { - overwriteRoutes: true, - }); + fetchMock.post( + urls.identify, + { + status: HTTP_UNAUTHORIZED, + body: null, + }, + { + overwriteRoutes: true, + }, + ); const callbackSpy = sinon.spy(); const invokeCallbackSpy = sinon.spy(); const verboseSpy = sinon.spy(); const errorSpy = sinon.spy(); - const mpInstance: IMParticleWebSDKInstance = ({ + const mpInstance: IMParticleWebSDKInstance = { Logger: { verbose: (message) => verboseSpy(message), error: (message) => errorSpy(message), @@ -469,10 +533,10 @@ describe('Identity Api Client', () => { }, }, _Persistence: {}, - } as unknown) as IMParticleWebSDKInstance; + } as unknown as IMParticleWebSDKInstance; const identityApiClient: IIdentityApiClient = new IdentityAPIClient( - mpInstance + mpInstance, ); const parseIdentityResponseSpy = sinon.spy(); @@ -484,35 +548,48 @@ describe('Identity Api Client', () => { originalIdentityApiData, parseIdentityResponseSpy, testMPID, - identityRequest.known_identities + identityRequest.known_identities, ); expect(errorSpy.lastCall, 'errorSpy called').to.be.ok; - expect(errorSpy.lastCall.firstArg).to.equal("Error sending identity request to servers - Received HTTP Code of 401"); + expect(errorSpy.lastCall.firstArg).to.equal( + 'Error sending identity request to servers - Received HTTP Code of 401', + ); - expect(invokeCallbackSpy.calledOnce, 'invokeCallbackSpy').to.eq(true); + expect(invokeCallbackSpy.calledOnce, 'invokeCallbackSpy').to.eq( + true, + ); expect(invokeCallbackSpy.args[0][0]).to.equal(callbackSpy); expect(invokeCallbackSpy.args[0][1]).to.equal(-1); - expect(invokeCallbackSpy.args[0][2]).to.equal("Received HTTP Code of 401"); + expect(invokeCallbackSpy.args[0][2]).to.equal( + 'Received HTTP Code of 401', + ); // A 401 should not call parseIdentityResponse - expect(parseIdentityResponseSpy.calledOnce, 'parseIdentityResponseSpy').to.eq(false); + expect( + parseIdentityResponseSpy.calledOnce, + 'parseIdentityResponseSpy', + ).to.eq(false); }); it('should include a detailed error message if the fetch returns a 403 (Forbidden)', async () => { - fetchMock.post(urls.identify, { - status: HTTP_FORBIDDEN, - body: null, - }, { - overwriteRoutes: true, - }); + fetchMock.post( + urls.identify, + { + status: HTTP_FORBIDDEN, + body: null, + }, + { + overwriteRoutes: true, + }, + ); const callbackSpy = sinon.spy(); const invokeCallbackSpy = sinon.spy(); const verboseSpy = sinon.spy(); const errorSpy = sinon.spy(); - const mpInstance: IMParticleWebSDKInstance = ({ + const mpInstance: IMParticleWebSDKInstance = { Logger: { verbose: (message) => verboseSpy(message), error: (message) => errorSpy(message), @@ -521,7 +598,8 @@ describe('Identity Api Client', () => { createServiceUrl: () => 'https://identity.mparticle.com/v1/', - invokeCallback: (callback, httpCode, errorMessage) => invokeCallbackSpy(callback, httpCode, errorMessage), + invokeCallback: (callback, httpCode, errorMessage) => + invokeCallbackSpy(callback, httpCode, errorMessage), }, _Store: { devToken: 'test_key', @@ -530,10 +608,10 @@ describe('Identity Api Client', () => { }, }, _Persistence: {}, - } as unknown) as IMParticleWebSDKInstance; + } as unknown as IMParticleWebSDKInstance; const identityApiClient: IIdentityApiClient = new IdentityAPIClient( - mpInstance + mpInstance, ); const parseIdentityResponseSpy = sinon.spy(); @@ -545,36 +623,48 @@ describe('Identity Api Client', () => { originalIdentityApiData, parseIdentityResponseSpy, testMPID, - identityRequest.known_identities + identityRequest.known_identities, ); expect(errorSpy.lastCall, 'errorSpy called').to.be.ok; - expect(errorSpy.lastCall.firstArg).to.equal("Error sending identity request to servers - Received HTTP Code of 403"); + expect(errorSpy.lastCall.firstArg).to.equal( + 'Error sending identity request to servers - Received HTTP Code of 403', + ); - expect(invokeCallbackSpy.calledOnce, 'invokeCallbackSpy').to.eq(true); + expect(invokeCallbackSpy.calledOnce, 'invokeCallbackSpy').to.eq( + true, + ); expect(invokeCallbackSpy.args[0][0]).to.equal(callbackSpy); expect(invokeCallbackSpy.args[0][1]).to.equal(-1); - expect(invokeCallbackSpy.args[0][2]).to.equal("Received HTTP Code of 403"); + expect(invokeCallbackSpy.args[0][2]).to.equal( + 'Received HTTP Code of 403', + ); // A 403 should not call parseIdentityResponse - expect(parseIdentityResponseSpy.calledOnce, 'parseIdentityResponseSpy').to.eq(false); - + expect( + parseIdentityResponseSpy.calledOnce, + 'parseIdentityResponseSpy', + ).to.eq(false); }); it('should include a detailed error message if the fetch returns a 404 (Not Found)', async () => { - fetchMock.post(urls.identify, { - status: HTTP_NOT_FOUND, - body: null, - }, { - overwriteRoutes: true, - }); + fetchMock.post( + urls.identify, + { + status: HTTP_NOT_FOUND, + body: null, + }, + { + overwriteRoutes: true, + }, + ); const callbackSpy = sinon.spy(); const invokeCallbackSpy = sinon.spy(); const verboseSpy = sinon.spy(); const errorSpy = sinon.spy(); - const mpInstance: IMParticleWebSDKInstance = ({ + const mpInstance: IMParticleWebSDKInstance = { Logger: { verbose: (message) => verboseSpy(message), error: (message) => errorSpy(message), @@ -583,7 +673,8 @@ describe('Identity Api Client', () => { createServiceUrl: () => 'https://identity.mparticle.com/v1/', - invokeCallback: (callback, httpCode, errorMessage) => invokeCallbackSpy(callback, httpCode, errorMessage), + invokeCallback: (callback, httpCode, errorMessage) => + invokeCallbackSpy(callback, httpCode, errorMessage), }, _Store: { devToken: 'test_key', @@ -592,10 +683,10 @@ describe('Identity Api Client', () => { }, }, _Persistence: {}, - } as unknown) as IMParticleWebSDKInstance; + } as unknown as IMParticleWebSDKInstance; const identityApiClient: IIdentityApiClient = new IdentityAPIClient( - mpInstance + mpInstance, ); const parseIdentityResponseSpy = sinon.spy(); @@ -607,44 +698,57 @@ describe('Identity Api Client', () => { originalIdentityApiData, parseIdentityResponseSpy, testMPID, - identityRequest.known_identities + identityRequest.known_identities, ); expect(errorSpy.lastCall, 'errorSpy called').to.be.ok; - expect(errorSpy.lastCall.firstArg).to.equal("Error sending identity request to servers - Received HTTP Code of 404"); + expect(errorSpy.lastCall.firstArg).to.equal( + 'Error sending identity request to servers - Received HTTP Code of 404', + ); - expect(invokeCallbackSpy.calledOnce, 'invokeCallbackSpy').to.eq(true); + expect(invokeCallbackSpy.calledOnce, 'invokeCallbackSpy').to.eq( + true, + ); expect(invokeCallbackSpy.args[0][0]).to.equal(callbackSpy); expect(invokeCallbackSpy.args[0][1]).to.equal(-1); - expect(invokeCallbackSpy.args[0][2]).to.equal("Received HTTP Code of 404"); + expect(invokeCallbackSpy.args[0][2]).to.equal( + 'Received HTTP Code of 404', + ); // A 404 should not call parseIdentityResponse - expect(parseIdentityResponseSpy.calledOnce, 'parseIdentityResponseSpy').to.eq(false); + expect( + parseIdentityResponseSpy.calledOnce, + 'parseIdentityResponseSpy', + ).to.eq(false); }); it('should include a detailed error message if the fetch returns a 500 (Server Error)', async () => { - fetchMock.post(urls.identify, { - status: HTTP_SERVER_ERROR, - body: { - "Errors": [ - { - "code": "INTERNAL_ERROR", - "message": "An unknown error was encountered." - } - ], - "ErrorCode": "INTERNAL_ERROR", - "StatusCode": 500, - "RequestId": null + fetchMock.post( + urls.identify, + { + status: HTTP_SERVER_ERROR, + body: { + Errors: [ + { + code: 'INTERNAL_ERROR', + message: 'An unknown error was encountered.', + }, + ], + ErrorCode: 'INTERNAL_ERROR', + StatusCode: 500, + RequestId: null, + }, }, - }, { - overwriteRoutes: true, - }); + { + overwriteRoutes: true, + }, + ); const callbackSpy = sinon.spy(); const verboseSpy = sinon.spy(); const errorSpy = sinon.spy(); - const mpInstance: IMParticleWebSDKInstance = ({ + const mpInstance: IMParticleWebSDKInstance = { Logger: { verbose: (message) => verboseSpy(message), error: (message) => errorSpy(message), @@ -662,10 +766,10 @@ describe('Identity Api Client', () => { }, }, _Persistence: {}, - } as unknown) as IMParticleWebSDKInstance; + } as unknown as IMParticleWebSDKInstance; const identityApiClient: IIdentityApiClient = new IdentityAPIClient( - mpInstance + mpInstance, ); const parseIdentityResponseSpy = sinon.spy(); @@ -677,30 +781,34 @@ describe('Identity Api Client', () => { originalIdentityApiData, parseIdentityResponseSpy, testMPID, - identityRequest.known_identities + identityRequest.known_identities, ); expect(errorSpy.calledOnce, 'errorSpy called').to.eq(true); - expect(errorSpy.args[0][0]).to.equal('Error sending identity request to servers - Received HTTP Code of 500'); + expect(errorSpy.args[0][0]).to.equal( + 'Error sending identity request to servers - Received HTTP Code of 500', + ); }); }); describe('#sendAliasRequest', () => { - const aliasUrl = 'https://jssdks.mparticle.com/v1/identity/test_key/Alias'; + const aliasUrl = + 'https://jssdks.mparticle.com/v1/identity/test_key/Alias'; - beforeEach(function() { + beforeEach(function () { fetchMockSuccess(urls.events); mParticle.init(apiKey, window.mParticle.config); }); - afterEach(function() { + afterEach(function () { fetchMock.restore(); mParticle._resetForTests(MPConfig); }); it('should have just an httpCode on the result passed to the callback on a 200', async () => { - const mpInstance: IMParticleWebSDKInstance = mParticle.getInstance(); + const mpInstance: IMParticleWebSDKInstance = + mParticle.getInstance(); const identityApiClient = new IdentityAPIClient(mpInstance); const aliasRequest: IAliasRequest = { @@ -715,7 +823,7 @@ describe('Identity Api Client', () => { await identityApiClient.sendAliasRequest( aliasRequest, - aliasCallback + aliasCallback, ); expect(aliasCallback.calledOnce).to.eq(true); const callbackArgs = aliasCallback.getCall(0).args; @@ -723,7 +831,8 @@ describe('Identity Api Client', () => { }); it('should have just an httpCode on the result passed to the callback on a 202', async () => { - const mpInstance: IMParticleWebSDKInstance = mParticle.getInstance(); + const mpInstance: IMParticleWebSDKInstance = + mParticle.getInstance(); const identityApiClient = new IdentityAPIClient(mpInstance); const aliasRequest: IAliasRequest = { destinationMpid: '123', @@ -737,7 +846,7 @@ describe('Identity Api Client', () => { await identityApiClient.sendAliasRequest( aliasRequest, - aliasCallback + aliasCallback, ); expect(aliasCallback.calledOnce).to.eq(true); const callbackArgs = aliasCallback.getCall(0).args; @@ -745,7 +854,8 @@ describe('Identity Api Client', () => { }); it('should have just an httpCode on the result passed to the callback on a 400', async () => { - const mpInstance: IMParticleWebSDKInstance = mParticle.getInstance(); + const mpInstance: IMParticleWebSDKInstance = + mParticle.getInstance(); const identityApiClient = new IdentityAPIClient(mpInstance); const aliasRequest: IAliasRequest = { destinationMpid: '123', @@ -755,29 +865,37 @@ describe('Identity Api Client', () => { }; const aliasCallback = sinon.spy(); - fetchMock.post(aliasUrl, { - status: HTTP_BAD_REQUEST, - body: { - message:"The payload was malformed JSON or had missing fields.", - code:"INVALID_DATA"} - }, { - overwriteRoutes: true - }); + fetchMock.post( + aliasUrl, + { + status: HTTP_BAD_REQUEST, + body: { + message: + 'The payload was malformed JSON or had missing fields.', + code: 'INVALID_DATA', + }, + }, + { + overwriteRoutes: true, + }, + ); await identityApiClient.sendAliasRequest( aliasRequest, - aliasCallback + aliasCallback, ); expect(aliasCallback.calledOnce).to.eq(true); const callbackArgs = aliasCallback.getCall(0).args; expect(callbackArgs[0]).to.deep.equal({ httpCode: HTTP_BAD_REQUEST, - message: 'The payload was malformed JSON or had missing fields.', + message: + 'The payload was malformed JSON or had missing fields.', }); }); it('should have an httpCode and an error message passed to the callback on a 401', async () => { - const mpInstance: IMParticleWebSDKInstance = mParticle.getInstance(); + const mpInstance: IMParticleWebSDKInstance = + mParticle.getInstance(); const identityApiClient = new IdentityAPIClient(mpInstance); const aliasRequest: IAliasRequest = { destinationMpid: '123', @@ -794,16 +912,19 @@ describe('Identity Api Client', () => { await identityApiClient.sendAliasRequest( aliasRequest, - aliasCallback + aliasCallback, ); expect(aliasCallback.calledOnce).to.eq(true); const callbackArgs = aliasCallback.getCall(0).args; expect(callbackArgs[0].httpCode).to.equal(HTTPCodes.noHttpCoverage); - expect(callbackArgs[0].message).deep.equal('Received HTTP Code of 401'); + expect(callbackArgs[0].message).deep.equal( + 'Received HTTP Code of 401', + ); }); it('should have an httpCode and an error message passed to the callback on a 403', async () => { - const mpInstance: IMParticleWebSDKInstance = mParticle.getInstance(); + const mpInstance: IMParticleWebSDKInstance = + mParticle.getInstance(); const identityApiClient = new IdentityAPIClient(mpInstance); const aliasRequest: IAliasRequest = { destinationMpid: '123', @@ -820,16 +941,19 @@ describe('Identity Api Client', () => { await identityApiClient.sendAliasRequest( aliasRequest, - aliasCallback + aliasCallback, ); expect(aliasCallback.calledOnce).to.eq(true); const callbackArgs = aliasCallback.getCall(0).args; expect(callbackArgs[0].httpCode).to.equal(HTTPCodes.noHttpCoverage); - expect(callbackArgs[0].message).deep.equal('Received HTTP Code of 403'); + expect(callbackArgs[0].message).deep.equal( + 'Received HTTP Code of 403', + ); }); it('should have an httpCode and an error message passed to the callback on a 404', async () => { - const mpInstance: IMParticleWebSDKInstance = mParticle.getInstance(); + const mpInstance: IMParticleWebSDKInstance = + mParticle.getInstance(); const identityApiClient = new IdentityAPIClient(mpInstance); const aliasRequest: IAliasRequest = { destinationMpid: '123', @@ -846,16 +970,19 @@ describe('Identity Api Client', () => { await identityApiClient.sendAliasRequest( aliasRequest, - aliasCallback + aliasCallback, ); expect(aliasCallback.calledOnce).to.eq(true); const callbackArgs = aliasCallback.getCall(0).args; expect(callbackArgs[0].httpCode).to.equal(HTTPCodes.noHttpCoverage); - expect(callbackArgs[0].message).deep.equal('Received HTTP Code of 404'); + expect(callbackArgs[0].message).deep.equal( + 'Received HTTP Code of 404', + ); }); it('should have an httpCode and an error message passed to the callback on a 500', async () => { - const mpInstance: IMParticleWebSDKInstance = mParticle.getInstance(); + const mpInstance: IMParticleWebSDKInstance = + mParticle.getInstance(); const identityApiClient = new IdentityAPIClient(mpInstance); const aliasRequest: IAliasRequest = { destinationMpid: '123', @@ -868,26 +995,28 @@ describe('Identity Api Client', () => { fetchMock.post(aliasUrl, { status: HTTP_SERVER_ERROR, body: { - "Errors": [ + Errors: [ { - "code": "INTERNAL_ERROR", - "message": "An unknown error was encountered." - } + code: 'INTERNAL_ERROR', + message: 'An unknown error was encountered.', + }, ], - "ErrorCode": "INTERNAL_ERROR", - "StatusCode": 500, - "RequestId": null + ErrorCode: 'INTERNAL_ERROR', + StatusCode: 500, + RequestId: null, }, }); await identityApiClient.sendAliasRequest( aliasRequest, - aliasCallback + aliasCallback, ); expect(aliasCallback.calledOnce).to.eq(true); const callbackArgs = aliasCallback.getCall(0).args; expect(callbackArgs[0].httpCode).to.equal(HTTPCodes.noHttpCoverage); - expect(callbackArgs[0].message).deep.equal('Received HTTP Code of 500'); + expect(callbackArgs[0].message).deep.equal( + 'Received HTTP Code of 500', + ); }); }); }); diff --git a/test/src/tests-integration-capture.ts b/test/src/tests-integration-capture.ts index f5073c053..c3f1ec84b 100644 --- a/test/src/tests-integration-capture.ts +++ b/test/src/tests-integration-capture.ts @@ -1,8 +1,8 @@ import sinon from 'sinon'; -import { expect} from 'chai'; +import { expect } from 'chai'; import Utils from './config/utils'; import fetchMock from 'fetch-mock/esm/client'; -import { urls, apiKey, testMPID, MPConfig } from "./config/constants"; +import { urls, apiKey, testMPID, MPConfig } from './config/constants'; import { IMParticleInstanceManager } from '../../src/sdkRuntimeModels'; const { @@ -29,11 +29,12 @@ describe('Integration Capture', () => { fetchMock.post(urls.events, 200); delete mParticle._instances['default_instance']; fetchMockSuccess(urls.identify, { - mpid: testMPID, is_logged_in: false + mpid: testMPID, + is_logged_in: false, }); window.mParticle.config.flags = { - captureIntegrationSpecificIds: 'True' + captureIntegrationSpecificIds: 'True', }; window.document.cookie = '_cookie1=234'; @@ -43,51 +44,71 @@ describe('Integration Capture', () => { window.document.cookie = 'baz=qux'; window.document.cookie = '_ttp=45670808'; - // Mock the query params capture function because we cannot mock window.location.href - sinon.stub(window.mParticle.getInstance()._IntegrationCapture, 'getQueryParams').returns({ - fbclid: '1234', - gclid: '234', - gbraid: '6574', - rtid: '45670808', - rclid: '7183717', - wbraid: '1234111', - ScCid: '1234', - }); + sinon + .stub( + window.mParticle.getInstance()._IntegrationCapture, + 'getQueryParams', + ) + .returns({ + fbclid: '1234', + gclid: '234', + gbraid: '6574', + rtid: '45670808', + rclid: '7183717', + wbraid: '1234111', + ScCid: '1234', + }); mParticle.init(apiKey, window.mParticle.config); }); - afterEach(function() { + afterEach(function () { sinon.restore(); fetchMock.restore(); mParticle._resetForTests(MPConfig); deleteAllCookies(); }); - it('should add captured integrations to event custom flags', async () => { await waitForCondition(hasIdentifyReturned); - mParticle.logEvent( - 'Test Event', - mParticle.EventType.Navigation, - { mykey: 'myvalue' } - ); + mParticle.logEvent('Test Event', mParticle.EventType.Navigation, { + mykey: 'myvalue', + }); const testEvent = findEventFromRequest(fetchMock.calls(), 'Test Event'); - const initialTimestamp = window.mParticle.getInstance()._IntegrationCapture.initialTimestamp; + const initialTimestamp = + window.mParticle.getInstance()._IntegrationCapture.initialTimestamp; expect(testEvent).to.have.property('data'); expect(testEvent.data).to.have.property('event_name', 'Test Event'); expect(testEvent.data).to.have.property('custom_flags'); - expect(testEvent.data.custom_flags['Facebook.ClickId'], 'Facebook Click Id').to.equal(`fb.1.${initialTimestamp}.1234`); - expect(testEvent.data.custom_flags['Facebook.BrowserId'], 'Facebook Browser Id').to.equal('54321'); - expect(testEvent.data.custom_flags['GoogleEnhancedConversions.Gclid'], 'Google Enhanced Conversions Gclid').to.equal('234'); - expect(testEvent.data.custom_flags['GoogleEnhancedConversions.Gbraid'], 'Google Enhanced Conversions Gbraid').to.equal('6574'); - expect(testEvent.data.custom_flags['GoogleEnhancedConversions.Wbraid'], 'Google Enhanced Conversions Wbraid').to.equal('1234111'); - expect(testEvent.data.custom_flags['SnapchatConversions.ClickId'], 'Snapchat Click ID').to.equal('1234'); + expect( + testEvent.data.custom_flags['Facebook.ClickId'], + 'Facebook Click Id', + ).to.equal(`fb.1.${initialTimestamp}.1234`); + expect( + testEvent.data.custom_flags['Facebook.BrowserId'], + 'Facebook Browser Id', + ).to.equal('54321'); + expect( + testEvent.data.custom_flags['GoogleEnhancedConversions.Gclid'], + 'Google Enhanced Conversions Gclid', + ).to.equal('234'); + expect( + testEvent.data.custom_flags['GoogleEnhancedConversions.Gbraid'], + 'Google Enhanced Conversions Gbraid', + ).to.equal('6574'); + expect( + testEvent.data.custom_flags['GoogleEnhancedConversions.Wbraid'], + 'Google Enhanced Conversions Wbraid', + ).to.equal('1234111'); + expect( + testEvent.data.custom_flags['SnapchatConversions.ClickId'], + 'Snapchat Click ID', + ).to.equal('1234'); }); it('should add captured integrations to event custom flags, prioritizing passed in custom flags', async () => { @@ -105,113 +126,224 @@ describe('Integration Capture', () => { expect(testEvent.data).to.have.property('event_name', 'Test Event'); expect(testEvent.data).to.have.property('custom_flags'); - expect(testEvent.data.custom_flags['Facebook.ClickId'], 'Facebook Click Id').to.equal('passed-in'); - expect(testEvent.data.custom_flags['Facebook.BrowserId'], 'Facebook Browser Id').to.equal('54321'); - expect(testEvent.data.custom_flags['GoogleEnhancedConversions.Gclid'], 'Google Enhanced Conversions Gclid').to.equal('234'); - expect(testEvent.data.custom_flags['GoogleEnhancedConversions.Gbraid'], 'Google Enhanced Conversions Gbraid').to.equal('6574'); - expect(testEvent.data.custom_flags['GoogleEnhancedConversions.Wbraid'], 'Google Enhanced Conversions Wbraid').to.equal('1234111'); - expect(testEvent.data.custom_flags['SnapchatConversions.ClickId'], 'Snapchat Click ID').to.equal('1234'); + expect( + testEvent.data.custom_flags['Facebook.ClickId'], + 'Facebook Click Id', + ).to.equal('passed-in'); + expect( + testEvent.data.custom_flags['Facebook.BrowserId'], + 'Facebook Browser Id', + ).to.equal('54321'); + expect( + testEvent.data.custom_flags['GoogleEnhancedConversions.Gclid'], + 'Google Enhanced Conversions Gclid', + ).to.equal('234'); + expect( + testEvent.data.custom_flags['GoogleEnhancedConversions.Gbraid'], + 'Google Enhanced Conversions Gbraid', + ).to.equal('6574'); + expect( + testEvent.data.custom_flags['GoogleEnhancedConversions.Wbraid'], + 'Google Enhanced Conversions Wbraid', + ).to.equal('1234111'); + expect( + testEvent.data.custom_flags['SnapchatConversions.ClickId'], + 'Snapchat Click ID', + ).to.equal('1234'); }); it('should add captured integrations to page view custom flags', async () => { await waitForCondition(hasIdentifyReturned); - window.mParticle.logPageView( + window.mParticle.logPageView('Test Page View', { + 'foo-attr': 'bar-attr', + }); + + const testEvent = findEventFromRequest( + fetchMock.calls(), 'Test Page View', - {'foo-attr': 'bar-attr'} ); - const testEvent = findEventFromRequest(fetchMock.calls(), 'Test Page View'); - - const initialTimestamp = window.mParticle.getInstance()._IntegrationCapture.initialTimestamp; + const initialTimestamp = + window.mParticle.getInstance()._IntegrationCapture.initialTimestamp; expect(testEvent).to.have.property('data'); - expect(testEvent.data).to.have.property('screen_name', 'Test Page View'); + expect(testEvent.data).to.have.property( + 'screen_name', + 'Test Page View', + ); expect(testEvent.data).to.have.property('custom_flags'); - expect(testEvent.data.custom_flags['Facebook.ClickId'], 'Facebook Click Id').to.equal(`fb.1.${initialTimestamp}.1234`); - expect(testEvent.data.custom_flags['Facebook.BrowserId'], 'Facebook Browser Id').to.equal('54321'); - expect(testEvent.data.custom_flags['GoogleEnhancedConversions.Gclid'], 'Google Enhanced Conversions Gclid').to.equal('234'); - expect(testEvent.data.custom_flags['GoogleEnhancedConversions.Gbraid'], 'Google Enhanced Conversions Gbraid').to.equal('6574'); - expect(testEvent.data.custom_flags['GoogleEnhancedConversions.Wbraid'], 'Google Enhanced Conversions Wbraid').to.equal('1234111'); - expect(testEvent.data.custom_flags['SnapchatConversions.ClickId'], 'Snapchat Click ID').to.equal('1234'); + expect( + testEvent.data.custom_flags['Facebook.ClickId'], + 'Facebook Click Id', + ).to.equal(`fb.1.${initialTimestamp}.1234`); + expect( + testEvent.data.custom_flags['Facebook.BrowserId'], + 'Facebook Browser Id', + ).to.equal('54321'); + expect( + testEvent.data.custom_flags['GoogleEnhancedConversions.Gclid'], + 'Google Enhanced Conversions Gclid', + ).to.equal('234'); + expect( + testEvent.data.custom_flags['GoogleEnhancedConversions.Gbraid'], + 'Google Enhanced Conversions Gbraid', + ).to.equal('6574'); + expect( + testEvent.data.custom_flags['GoogleEnhancedConversions.Wbraid'], + 'Google Enhanced Conversions Wbraid', + ).to.equal('1234111'); + expect( + testEvent.data.custom_flags['SnapchatConversions.ClickId'], + 'Snapchat Click ID', + ).to.equal('1234'); }); it('should add captured integrations to page view custom flags, prioritizing passed in custom flags', async () => { await waitForCondition(hasIdentifyReturned); window.mParticle.logPageView( 'Test Page View', - {'foo-attr': 'bar-attr'}, - {'Facebook.ClickId': 'passed-in'}, + { 'foo-attr': 'bar-attr' }, + { 'Facebook.ClickId': 'passed-in' }, ); - const testEvent = findEventFromRequest(fetchMock.calls(), 'Test Page View'); + const testEvent = findEventFromRequest( + fetchMock.calls(), + 'Test Page View', + ); expect(testEvent).to.have.property('data'); - expect(testEvent.data).to.have.property('screen_name', 'Test Page View'); + expect(testEvent.data).to.have.property( + 'screen_name', + 'Test Page View', + ); expect(testEvent.data).to.have.property('custom_flags'); - expect(testEvent.data.custom_flags['Facebook.ClickId'], 'Facebook Click Id').to.equal('passed-in'); - expect(testEvent.data.custom_flags['Facebook.BrowserId'], 'Facebook Browser Id').to.equal('54321'); - expect(testEvent.data.custom_flags['GoogleEnhancedConversions.Gclid'], 'Google Enhanced Conversions Gclid').to.equal('234'); - expect(testEvent.data.custom_flags['GoogleEnhancedConversions.Gbraid'], 'Google Enhanced Conversions Gbraid').to.equal('6574'); - expect(testEvent.data.custom_flags['GoogleEnhancedConversions.Wbraid'], 'Google Enhanced Conversions Wbraid').to.equal('1234111'); - expect(testEvent.data.custom_flags['SnapchatConversions.ClickId'], 'Snapchat Click ID').to.equal('1234'); + expect( + testEvent.data.custom_flags['Facebook.ClickId'], + 'Facebook Click Id', + ).to.equal('passed-in'); + expect( + testEvent.data.custom_flags['Facebook.BrowserId'], + 'Facebook Browser Id', + ).to.equal('54321'); + expect( + testEvent.data.custom_flags['GoogleEnhancedConversions.Gclid'], + 'Google Enhanced Conversions Gclid', + ).to.equal('234'); + expect( + testEvent.data.custom_flags['GoogleEnhancedConversions.Gbraid'], + 'Google Enhanced Conversions Gbraid', + ).to.equal('6574'); + expect( + testEvent.data.custom_flags['GoogleEnhancedConversions.Wbraid'], + 'Google Enhanced Conversions Wbraid', + ).to.equal('1234111'); + expect( + testEvent.data.custom_flags['SnapchatConversions.ClickId'], + 'Snapchat Click ID', + ).to.equal('1234'); }); it('should add captured integrations to commerce event custom flags', async () => { await waitForCondition(hasIdentifyReturned); - const product1 = mParticle.eCommerce.createProduct('iphone', 'iphoneSKU', 999, 1); - const product2 = mParticle.eCommerce.createProduct('galaxy', 'galaxySKU', 799, 1); + const product1 = mParticle.eCommerce.createProduct( + 'iphone', + 'iphoneSKU', + 999, + 1, + ); + const product2 = mParticle.eCommerce.createProduct( + 'galaxy', + 'galaxySKU', + 799, + 1, + ); const transactionAttributes = { Id: 'foo-transaction-id', - Revenue: 430.00, - Tax: 30 + Revenue: 430.0, + Tax: 30, }; - const customAttributes = {sale: true}; - const customFlags = {foo: 'bar'}; + const customAttributes = { sale: true }; + const customFlags = { foo: 'bar' }; mParticle.eCommerce.logProductAction( mParticle.ProductActionType.Purchase, [product1, product2], customAttributes, customFlags, - transactionAttributes); + transactionAttributes, + ); const testEvent = findEventFromRequest(fetchMock.calls(), 'purchase'); - const initialTimestamp = window.mParticle.getInstance()._IntegrationCapture.initialTimestamp; + const initialTimestamp = + window.mParticle.getInstance()._IntegrationCapture.initialTimestamp; - expect(testEvent.data.product_action).to.have.property('action', 'purchase'); + expect(testEvent.data.product_action).to.have.property( + 'action', + 'purchase', + ); expect(testEvent.data).to.have.property('custom_flags'); - expect(testEvent.data.custom_flags['foo'], 'Custom Flag').to.equal('bar'); - expect(testEvent.data.custom_flags['Facebook.ClickId'], 'Facebook Click Id').to.equal(`fb.1.${initialTimestamp}.1234`); - expect(testEvent.data.custom_flags['Facebook.BrowserId'], 'Facebook Browser Id').to.equal('54321'); - expect(testEvent.data.custom_flags['GoogleEnhancedConversions.Gclid'], 'Google Enhanced Conversions Gclid').to.equal('234'); - expect(testEvent.data.custom_flags['GoogleEnhancedConversions.Gbraid'], 'Google Enhanced Conversions Gbraid').to.equal('6574'); - expect(testEvent.data.custom_flags['GoogleEnhancedConversions.Wbraid'], 'Google Enhanced Conversions Wbraid').to.equal('1234111'); - expect(testEvent.data.custom_flags['SnapchatConversions.ClickId'], 'Snapchat Click ID').to.equal('1234'); + expect(testEvent.data.custom_flags['foo'], 'Custom Flag').to.equal( + 'bar', + ); + expect( + testEvent.data.custom_flags['Facebook.ClickId'], + 'Facebook Click Id', + ).to.equal(`fb.1.${initialTimestamp}.1234`); + expect( + testEvent.data.custom_flags['Facebook.BrowserId'], + 'Facebook Browser Id', + ).to.equal('54321'); + expect( + testEvent.data.custom_flags['GoogleEnhancedConversions.Gclid'], + 'Google Enhanced Conversions Gclid', + ).to.equal('234'); + expect( + testEvent.data.custom_flags['GoogleEnhancedConversions.Gbraid'], + 'Google Enhanced Conversions Gbraid', + ).to.equal('6574'); + expect( + testEvent.data.custom_flags['GoogleEnhancedConversions.Wbraid'], + 'Google Enhanced Conversions Wbraid', + ).to.equal('1234111'); + expect( + testEvent.data.custom_flags['SnapchatConversions.ClickId'], + 'Snapchat Click ID', + ).to.equal('1234'); }); it('should add captured integrations to commerce event custom flags, prioritizing passed in flags', async () => { await waitForCondition(hasIdentifyReturned); - const product1 = mParticle.eCommerce.createProduct('iphone', 'iphoneSKU', 999, 1); - const product2 = mParticle.eCommerce.createProduct('galaxy', 'galaxySKU', 799, 1); + const product1 = mParticle.eCommerce.createProduct( + 'iphone', + 'iphoneSKU', + 999, + 1, + ); + const product2 = mParticle.eCommerce.createProduct( + 'galaxy', + 'galaxySKU', + 799, + 1, + ); const transactionAttributes = { Id: 'foo-transaction-id', - Revenue: 430.00, - Tax: 30 + Revenue: 430.0, + Tax: 30, }; - const customAttributes = {sale: true}; + const customAttributes = { sale: true }; const customFlags = { - 'Facebook.ClickId': 'passed-in' + 'Facebook.ClickId': 'passed-in', }; mParticle.eCommerce.logProductAction( @@ -219,75 +351,141 @@ describe('Integration Capture', () => { [product1, product2], customAttributes, customFlags, - transactionAttributes); - + transactionAttributes, + ); const testEvent = findEventFromRequest(fetchMock.calls(), 'purchase'); - expect(testEvent.data.product_action).to.have.property('action', 'purchase'); + expect(testEvent.data.product_action).to.have.property( + 'action', + 'purchase', + ); expect(testEvent.data).to.have.property('custom_flags'); - expect(testEvent.data.custom_flags['Facebook.ClickId'], 'Facebook Click Id').to.equal('passed-in'); - expect(testEvent.data.custom_flags['Facebook.BrowserId'], 'Facebook Browser Id').to.equal('54321'); - expect(testEvent.data.custom_flags['GoogleEnhancedConversions.Gclid'], 'Google Enhanced Conversions Gclid').to.equal('234'); - expect(testEvent.data.custom_flags['GoogleEnhancedConversions.Gbraid'], 'Google Enhanced Conversions Gbraid').to.equal('6574'); - expect(testEvent.data.custom_flags['GoogleEnhancedConversions.Wbraid'], 'Google Enhanced Conversions Wbraid').to.equal('1234111'); - expect(testEvent.data.custom_flags['SnapchatConversions.ClickId'], 'Snapchat Click ID').to.equal('1234'); + expect( + testEvent.data.custom_flags['Facebook.ClickId'], + 'Facebook Click Id', + ).to.equal('passed-in'); + expect( + testEvent.data.custom_flags['Facebook.BrowserId'], + 'Facebook Browser Id', + ).to.equal('54321'); + expect( + testEvent.data.custom_flags['GoogleEnhancedConversions.Gclid'], + 'Google Enhanced Conversions Gclid', + ).to.equal('234'); + expect( + testEvent.data.custom_flags['GoogleEnhancedConversions.Gbraid'], + 'Google Enhanced Conversions Gbraid', + ).to.equal('6574'); + expect( + testEvent.data.custom_flags['GoogleEnhancedConversions.Wbraid'], + 'Google Enhanced Conversions Wbraid', + ).to.equal('1234111'); + expect( + testEvent.data.custom_flags['SnapchatConversions.ClickId'], + 'Snapchat Click ID', + ).to.equal('1234'); }); it('should add captured integrations to commerce event custom flags', async () => { await waitForCondition(hasIdentifyReturned); - const product1 = mParticle.eCommerce.createProduct('iphone', 'iphoneSKU', 999, 1); - const product2 = mParticle.eCommerce.createProduct('galaxy', 'galaxySKU', 799, 1); + const product1 = mParticle.eCommerce.createProduct( + 'iphone', + 'iphoneSKU', + 999, + 1, + ); + const product2 = mParticle.eCommerce.createProduct( + 'galaxy', + 'galaxySKU', + 799, + 1, + ); const transactionAttributes = { Id: 'foo-transaction-id', - Revenue: 430.00, - Tax: 30 + Revenue: 430.0, + Tax: 30, }; - const customAttributes = {sale: true}; - const customFlags = {foo: 'bar'}; + const customAttributes = { sale: true }; + const customFlags = { foo: 'bar' }; mParticle.eCommerce.logProductAction( mParticle.ProductActionType.Purchase, [product1, product2], customAttributes, customFlags, - transactionAttributes); + transactionAttributes, + ); const testEvent = findEventFromRequest(fetchMock.calls(), 'purchase'); - const initialTimestamp = window.mParticle.getInstance()._IntegrationCapture.initialTimestamp; + const initialTimestamp = + window.mParticle.getInstance()._IntegrationCapture.initialTimestamp; - expect(testEvent.data.product_action).to.have.property('action', 'purchase'); + expect(testEvent.data.product_action).to.have.property( + 'action', + 'purchase', + ); expect(testEvent.data).to.have.property('custom_flags'); - expect(testEvent.data.custom_flags['foo'], 'Custom Flag').to.equal('bar'); - expect(testEvent.data.custom_flags['Facebook.ClickId'], 'Facebook Click Id').to.equal(`fb.1.${initialTimestamp}.1234`); - expect(testEvent.data.custom_flags['Facebook.BrowserId'], 'Facebook Browser Id').to.equal('54321'); - expect(testEvent.data.custom_flags['GoogleEnhancedConversions.Gclid'], 'Google Enhanced Conversions Gclid').to.equal('234'); - expect(testEvent.data.custom_flags['GoogleEnhancedConversions.Gbraid'], 'Google Enhanced Conversions Gbraid').to.equal('6574'); - expect(testEvent.data.custom_flags['GoogleEnhancedConversions.Wbraid'], 'Google Enhanced Conversions Wbraid').to.equal('1234111'); - expect(testEvent.data.custom_flags['SnapchatConversions.ClickId'], 'Snapchat Click ID').to.equal('1234'); + expect(testEvent.data.custom_flags['foo'], 'Custom Flag').to.equal( + 'bar', + ); + expect( + testEvent.data.custom_flags['Facebook.ClickId'], + 'Facebook Click Id', + ).to.equal(`fb.1.${initialTimestamp}.1234`); + expect( + testEvent.data.custom_flags['Facebook.BrowserId'], + 'Facebook Browser Id', + ).to.equal('54321'); + expect( + testEvent.data.custom_flags['GoogleEnhancedConversions.Gclid'], + 'Google Enhanced Conversions Gclid', + ).to.equal('234'); + expect( + testEvent.data.custom_flags['GoogleEnhancedConversions.Gbraid'], + 'Google Enhanced Conversions Gbraid', + ).to.equal('6574'); + expect( + testEvent.data.custom_flags['GoogleEnhancedConversions.Wbraid'], + 'Google Enhanced Conversions Wbraid', + ).to.equal('1234111'); + expect( + testEvent.data.custom_flags['SnapchatConversions.ClickId'], + 'Snapchat Click ID', + ).to.equal('1234'); }); it('should add captured integrations to commerce event custom flags, prioritizing passed in flags', async () => { await waitForCondition(hasIdentifyReturned); - const product1 = mParticle.eCommerce.createProduct('iphone', 'iphoneSKU', 999, 1); - const product2 = mParticle.eCommerce.createProduct('galaxy', 'galaxySKU', 799, 1); + const product1 = mParticle.eCommerce.createProduct( + 'iphone', + 'iphoneSKU', + 999, + 1, + ); + const product2 = mParticle.eCommerce.createProduct( + 'galaxy', + 'galaxySKU', + 799, + 1, + ); const transactionAttributes = { Id: 'foo-transaction-id', - Revenue: 430.00, - Tax: 30 + Revenue: 430.0, + Tax: 30, }; - const customAttributes = {sale: true}; + const customAttributes = { sale: true }; const customFlags = { - 'Facebook.ClickId': 'passed-in' + 'Facebook.ClickId': 'passed-in', }; mParticle.eCommerce.logProductAction( @@ -295,20 +493,41 @@ describe('Integration Capture', () => { [product1, product2], customAttributes, customFlags, - transactionAttributes); - + transactionAttributes, + ); const testEvent = findEventFromRequest(fetchMock.calls(), 'purchase'); - expect(testEvent.data.product_action).to.have.property('action', 'purchase'); + expect(testEvent.data.product_action).to.have.property( + 'action', + 'purchase', + ); expect(testEvent.data).to.have.property('custom_flags'); - - expect(testEvent.data.custom_flags['Facebook.ClickId'], 'Facebook Click Id').to.equal('passed-in'); - expect(testEvent.data.custom_flags['Facebook.BrowserId'], 'Facebook Browser Id').to.equal('54321'); - expect(testEvent.data.custom_flags['GoogleEnhancedConversions.Gclid'], 'Google Enhanced Conversions Gclid').to.equal('234'); - expect(testEvent.data.custom_flags['GoogleEnhancedConversions.Gbraid'], 'Google Enhanced Conversions Gbraid').to.equal('6574'); - expect(testEvent.data.custom_flags['GoogleEnhancedConversions.Wbraid'], 'Google Enhanced Conversions Wbraid').to.equal('1234111'); - expect(testEvent.data.custom_flags['SnapchatConversions.ClickId'], 'Snapchat Click ID').to.equal('1234'); + + expect( + testEvent.data.custom_flags['Facebook.ClickId'], + 'Facebook Click Id', + ).to.equal('passed-in'); + expect( + testEvent.data.custom_flags['Facebook.BrowserId'], + 'Facebook Browser Id', + ).to.equal('54321'); + expect( + testEvent.data.custom_flags['GoogleEnhancedConversions.Gclid'], + 'Google Enhanced Conversions Gclid', + ).to.equal('234'); + expect( + testEvent.data.custom_flags['GoogleEnhancedConversions.Gbraid'], + 'Google Enhanced Conversions Gbraid', + ).to.equal('6574'); + expect( + testEvent.data.custom_flags['GoogleEnhancedConversions.Wbraid'], + 'Google Enhanced Conversions Wbraid', + ).to.equal('1234111'); + expect( + testEvent.data.custom_flags['SnapchatConversions.ClickId'], + 'Snapchat Click ID', + ).to.equal('1234'); }); it('should add captured integrations to batch as partner identities', async () => { @@ -327,9 +546,8 @@ describe('Integration Capture', () => { expect(batch).to.have.property('partner_identities'); expect(batch.partner_identities).to.deep.equal({ - 'tiktok_cookie_id': '45670808', + tiktok_cookie_id: '45670808', }); - }); it('should add captured integrations to batch as integration attributes', async () => { @@ -348,14 +566,14 @@ describe('Integration Capture', () => { expect(batch).to.have.property('integration_attributes'); expect(batch.integration_attributes['1277']).to.deep.equal({ - 'passbackconversiontrackingid': '45670808', + passbackconversiontrackingid: '45670808', }); }); it('should add captured integrations to batch as integration attributes without colliding with set integration attributes', async () => { await waitForCondition(hasIdentityCallInflightReturned); - window.mParticle.setIntegrationAttribute(160, { 'client_id': '12354'}); + window.mParticle.setIntegrationAttribute(160, { client_id: '12354' }); window.mParticle.logEvent('Test Event 1'); window.mParticle.logEvent('Test Event 2'); @@ -372,19 +590,20 @@ describe('Integration Capture', () => { expect(batch.integration_attributes).to.have.property('1277'); expect(batch.integration_attributes).to.have.property('160'); expect(batch.integration_attributes['1277']).to.deep.equal({ - 'passbackconversiontrackingid': '45670808', + passbackconversiontrackingid: '45670808', }); expect(batch.integration_attributes['160']).to.deep.equal({ - 'client_id': '12354', + client_id: '12354', }); - }); it('should add captured integrations to batch as integration attributes, prioritizing passed in integration attributes', async () => { await waitForCondition(hasIdentityCallInflightReturned); - window.mParticle.setIntegrationAttribute(1277, { 'passbackconversiontrackingid': 'passed-in'}); - window.mParticle.setIntegrationAttribute(160, { 'client_id': '12354'}); + window.mParticle.setIntegrationAttribute(1277, { + passbackconversiontrackingid: 'passed-in', + }); + window.mParticle.setIntegrationAttribute(160, { client_id: '12354' }); window.mParticle.logEvent('Test Event 1'); window.mParticle.logEvent('Test Event 2'); @@ -399,7 +618,7 @@ describe('Integration Capture', () => { expect(batch).to.have.property('integration_attributes'); expect(batch.integration_attributes['1277']).to.deep.equal({ - 'passbackconversiontrackingid': 'passed-in', + passbackconversiontrackingid: 'passed-in', }); }); -}); \ No newline at end of file +}); diff --git a/test/src/tests-kit-blocking.ts b/test/src/tests-kit-blocking.ts index a918a1fe9..1b9a03c62 100644 --- a/test/src/tests-kit-blocking.ts +++ b/test/src/tests-kit-blocking.ts @@ -1,7 +1,13 @@ import sinon from 'sinon'; import { expect } from 'chai'; import { urls, apiKey, MPConfig, testMPID } from './config/constants'; -import { SDKEvent, SDKProductActionType, DataPlanResult, KitBlockerDataPlan, IMParticleInstanceManager } from '../../src/sdkRuntimeModels'; +import { + SDKEvent, + SDKProductActionType, + DataPlanResult, + KitBlockerDataPlan, + IMParticleInstanceManager, +} from '../../src/sdkRuntimeModels'; import * as dataPlan from './dataPlan.json'; import Utils from './config/utils'; import KitBlocker from '../../src/kitBlocking'; @@ -11,7 +17,7 @@ import fetchMock from 'fetch-mock/esm/client'; import { IMockForwarder } from './tests-forwarders'; const { waitForCondition, fetchMockSuccess, hasIdentifyReturned } = Utils; -let forwarderDefaultConfiguration = Utils.forwarderDefaultConfiguration; +const forwarderDefaultConfiguration = Utils.forwarderDefaultConfiguration; const MockForwarder = Utils.MockForwarder; declare global { @@ -22,91 +28,145 @@ declare global { } describe('kit blocking', () => { - let kitBlockerDataPlan: KitBlockerDataPlan = { - document: dataPlan + const kitBlockerDataPlan: KitBlockerDataPlan = { + document: dataPlan, } as KitBlockerDataPlan; - beforeEach(function() { + beforeEach(function () { window.mParticle.config.dataPlan = { - document: dataPlan as DataPlanResult + document: dataPlan as DataPlanResult, }; - window.mParticle.config.kitConfigs = [] + window.mParticle.config.kitConfigs = []; }); - - afterEach(function() { + + afterEach(function () { sinon.restore(); }); describe('kitBlocker', () => { - it('kitBlocker should parse data plan into dataPlanMatchLookups properly', function(done) { - let kitBlocker = new KitBlocker(kitBlockerDataPlan, window.mParticle.getInstance()); - let dataPlanMatchLookups = kitBlocker.dataPlanMatchLookups; - dataPlanMatchLookups.should.have.property('custom_event:search:Search Event', true); - dataPlanMatchLookups.should.have.property('screen_view::another new screenview event', {}); - dataPlanMatchLookups.should.have.property('custom_event:location:locationEvent', {foo: true, 'foo foo': true, 'foo number': true}); - dataPlanMatchLookups.should.have.property('product_action:add_to_cart', { - attributeNumMinMax: true, - attributeEmail: true, - attributeNumEnum: true, - attributeStringAlpha: true, - attributeBoolean: true, - }); - dataPlanMatchLookups.should.have.property('product_action:add_to_cart:ProductAttributes', true); + it('kitBlocker should parse data plan into dataPlanMatchLookups properly', function (done) { + const kitBlocker = new KitBlocker( + kitBlockerDataPlan, + window.mParticle.getInstance(), + ); + const dataPlanMatchLookups = kitBlocker.dataPlanMatchLookups; + dataPlanMatchLookups.should.have.property( + 'custom_event:search:Search Event', + true, + ); + dataPlanMatchLookups.should.have.property( + 'screen_view::another new screenview event', + {}, + ); + dataPlanMatchLookups.should.have.property( + 'custom_event:location:locationEvent', + { foo: true, 'foo foo': true, 'foo number': true }, + ); + dataPlanMatchLookups.should.have.property( + 'product_action:add_to_cart', + { + attributeNumMinMax: true, + attributeEmail: true, + attributeNumEnum: true, + attributeStringAlpha: true, + attributeBoolean: true, + }, + ); + dataPlanMatchLookups.should.have.property( + 'product_action:add_to_cart:ProductAttributes', + true, + ); dataPlanMatchLookups.should.have.property('promotion_action:view', { 'not required': true, - 'required': true - }); - dataPlanMatchLookups.should.have.property('promotion_action:view:ProductAttributes', true); - dataPlanMatchLookups.should.have.property('custom_event:navigation:TestEvent', true); - dataPlanMatchLookups.should.have.property('product_impression:ProductAttributes', { - allowedAttr1: true, - allowedAttr2: true + required: true, }); + dataPlanMatchLookups.should.have.property( + 'promotion_action:view:ProductAttributes', + true, + ); + dataPlanMatchLookups.should.have.property( + 'custom_event:navigation:TestEvent', + true, + ); + dataPlanMatchLookups.should.have.property( + 'product_impression:ProductAttributes', + { + allowedAttr1: true, + allowedAttr2: true, + }, + ); - dataPlanMatchLookups.should.have.property('screen_view::A New ScreenViewEvent', true) - dataPlanMatchLookups.should.have.property('screen_view::my screeeen', { - test2key: true, - test1key: true, - }); - dataPlanMatchLookups.should.have.property('custom_event:navigation:something something something', true); + dataPlanMatchLookups.should.have.property( + 'screen_view::A New ScreenViewEvent', + true, + ); + dataPlanMatchLookups.should.have.property( + 'screen_view::my screeeen', + { + test2key: true, + test1key: true, + }, + ); + dataPlanMatchLookups.should.have.property( + 'custom_event:navigation:something something something', + true, + ); dataPlanMatchLookups.should.have.property('user_attributes', { 'my attribute': true, 'my other attribute': true, 'a third attribute': true, }); - dataPlanMatchLookups.should.have.property('user_identities', true) - dataPlanMatchLookups.should.have.property('custom_event:social:SocialEvent', {}) - dataPlanMatchLookups.should.have.property('product_action:purchase', { - eventAttribute1: true, - eventAttribute2: true - }) - dataPlanMatchLookups.should.have.property('product_action:purchase:ProductAttributes', { - plannedAttr1: true, - plannedAttr2: true - }) - dataPlanMatchLookups.should.have.property('promotion_action:click', { - eventAttribute1: true, - eventAttribute2: true - }) - dataPlanMatchLookups.should.have.property('promotion_action:click:ProductAttributes', true) - + dataPlanMatchLookups.should.have.property('user_identities', true); + dataPlanMatchLookups.should.have.property( + 'custom_event:social:SocialEvent', + {}, + ); + dataPlanMatchLookups.should.have.property( + 'product_action:purchase', + { + eventAttribute1: true, + eventAttribute2: true, + }, + ); + dataPlanMatchLookups.should.have.property( + 'product_action:purchase:ProductAttributes', + { + plannedAttr1: true, + plannedAttr2: true, + }, + ); + dataPlanMatchLookups.should.have.property( + 'promotion_action:click', + { + eventAttribute1: true, + eventAttribute2: true, + }, + ); + dataPlanMatchLookups.should.have.property( + 'promotion_action:click:ProductAttributes', + true, + ); + done(); }); - }) - + }); + describe('kitblocking - events and event attributes', () => { let kitBlocker; let event: SDKEvent; beforeEach(() => { - kitBlocker = new KitBlocker(kitBlockerDataPlan, window.mParticle.getInstance()); - event = { + kitBlocker = new KitBlocker( + kitBlockerDataPlan, + window.mParticle.getInstance(), + ); + event = { DeviceId: 'test', IsFirstRun: true, EventName: null, EventCategory: null, ExpandedEventCount: 0, - MPID: testMPID, + MPID: testMPID, EventAttributes: null, SDKVersion: '1.0.0', SourceMessageId: 'testSMID', @@ -116,93 +176,124 @@ describe('kit blocking', () => { EventDataType: null, Debug: true, CurrencyCode: 'usd', - ActiveTimeOnSite: 10 - } + ActiveTimeOnSite: 10, + }; }); - it('should transform an unplanned event to null if blok.ev = true', function(done) { + it('should transform an unplanned event to null if blok.ev = true', function (done) { event.EventName = 'unplanned event'; event.EventCategory = Types.EventType.Search; event.EventAttributes = { keyword2: 'test' }; event.EventDataType = Types.MessageType.PageEvent; - let transformedEvent = kitBlocker.transformEventAndEventAttributes(event); + const transformedEvent = + kitBlocker.transformEventAndEventAttributes(event); (transformedEvent === null).should.equal(true); done(); }); - it('should transform EventAttributes if an event attribute is not planned and blok.ea = true', function(done) { + it('should transform EventAttributes if an event attribute is not planned and blok.ea = true', function (done) { event.EventName = 'locationEvent'; event.EventCategory = Types.EventType.Location; event.EventAttributes = { unplannedAttr: 'test', foo: 'hi' }; event.EventDataType = Types.MessageType.PageEvent; - let transformedEvent = kitBlocker.transformEventAndEventAttributes(event); - transformedEvent.EventAttributes.should.not.have.property('unplannedAttr'); + const transformedEvent = + kitBlocker.transformEventAndEventAttributes(event); + transformedEvent.EventAttributes.should.not.have.property( + 'unplannedAttr', + ); transformedEvent.EventAttributes.should.have.property('foo', 'hi'); done(); }); - it('should transform EventAttributes if there are no custom attributes and additionalProperties === false', function(done) { + it('should transform EventAttributes if there are no custom attributes and additionalProperties === false', function (done) { event.EventName = 'another new screenview event'; event.EventCategory = Types.EventType.Location; event.EventAttributes = { unplannedAttr: 'test', foo: 'hi' }; event.EventDataType = Types.MessageType.PageView; - - let transformedEvent = kitBlocker.transformEventAndEventAttributes(event); - transformedEvent.EventAttributes.should.not.have.property('unplannedAttr'); + + const transformedEvent = + kitBlocker.transformEventAndEventAttributes(event); + transformedEvent.EventAttributes.should.not.have.property( + 'unplannedAttr', + ); transformedEvent.EventAttributes.should.not.have.property('foo'); done(); }); - it('should include unplanned event attributes if additionalProperties = true and blok.ea = true', function(done) { + it('should include unplanned event attributes if additionalProperties = true and blok.ea = true', function (done) { event.EventName = 'something something something'; event.EventCategory = Types.EventType.Navigation; event.EventAttributes = { keyword2: 'test', foo: 'hi' }; event.EventDataType = Types.MessageType.PageEvent; - let transformedEvent = kitBlocker.transformEventAndEventAttributes(event); + const transformedEvent = + kitBlocker.transformEventAndEventAttributes(event); transformedEvent.EventAttributes.should.have.property('foo', 'hi'); - transformedEvent.EventAttributes.should.have.property('keyword2', 'test'); + transformedEvent.EventAttributes.should.have.property( + 'keyword2', + 'test', + ); done(); }); - it('should block any unplanned event attributes if custom attributes is empty, additionalProperties = false, and block.ea = true.', function(done) { + it('should block any unplanned event attributes if custom attributes is empty, additionalProperties = false, and block.ea = true.', function (done) { event.EventName = 'SocialEvent'; event.EventCategory = Types.EventType.Social; event.EventAttributes = { keyword2: 'test', foo: 'hi' }; event.EventDataType = Types.MessageType.PageEvent; - let transformedEvent = kitBlocker.transformEventAndEventAttributes(event); - Object.keys(transformedEvent.EventAttributes).length.should.equal(0); + const transformedEvent = + kitBlocker.transformEventAndEventAttributes(event); + Object.keys(transformedEvent.EventAttributes).length.should.equal( + 0, + ); done(); }); - it('should not block any unplanned event attributes if custom attributes is empty, additionalProperties = true, and block.ea = true.', function(done) { - // modify this test so that the above - let socialDataPoint = dataPlan.dtpn.vers.version_document.data_points.find(dataPoint => { - return dataPoint?.match?.criteria?.event_name === 'SocialEvent' - }); - socialDataPoint.validator.definition.properties.data.properties.custom_attributes.additionalProperties = true; + it('should not block any unplanned event attributes if custom attributes is empty, additionalProperties = true, and block.ea = true.', function (done) { + // modify this test so that the above + const socialDataPoint = + dataPlan.dtpn.vers.version_document.data_points.find( + (dataPoint) => { + return ( + dataPoint?.match?.criteria?.event_name === + 'SocialEvent' + ); + }, + ); + socialDataPoint.validator.definition.properties.data.properties.custom_attributes.additionalProperties = + true; - kitBlocker = new KitBlocker(kitBlockerDataPlan, window.mParticle.getInstance()); + kitBlocker = new KitBlocker( + kitBlockerDataPlan, + window.mParticle.getInstance(), + ); event.EventName = 'SocialEvent'; event.EventCategory = Types.EventType.Social; event.EventAttributes = { keyword2: 'test', foo: 'hi' }; event.EventDataType = Types.MessageType.PageEvent; - let transformedEvent = kitBlocker.transformEventAndEventAttributes(event); - Object.keys(transformedEvent.EventAttributes).length.should.equal(2); + const transformedEvent = + kitBlocker.transformEventAndEventAttributes(event); + Object.keys(transformedEvent.EventAttributes).length.should.equal( + 2, + ); transformedEvent.EventAttributes.should.have.property('foo', 'hi'); - transformedEvent.EventAttributes.should.have.property('keyword2', 'test'); + transformedEvent.EventAttributes.should.have.property( + 'keyword2', + 'test', + ); - socialDataPoint.validator.definition.properties.data.properties.custom_attributes.additionalProperties = false; + socialDataPoint.validator.definition.properties.data.properties.custom_attributes.additionalProperties = + false; done(); }); @@ -213,14 +304,17 @@ describe('kit blocking', () => { let event: SDKEvent; beforeEach(() => { - kitBlocker = new KitBlocker(kitBlockerDataPlan, window.mParticle.getInstance()); - event = { + kitBlocker = new KitBlocker( + kitBlockerDataPlan, + window.mParticle.getInstance(), + ); + event = { DeviceId: 'test', IsFirstRun: true, EventName: null, EventCategory: null, ExpandedEventCount: 0, - MPID: testMPID, + MPID: testMPID, EventAttributes: null, SDKVersion: '1.0.0', SourceMessageId: 'testSMID', @@ -230,11 +324,11 @@ describe('kit blocking', () => { EventDataType: null, Debug: true, CurrencyCode: 'usd', - ActiveTimeOnSite: 10 + ActiveTimeOnSite: 10, }; }); - it('should block any unplanned user attributes when blok.ua = true and additionalPropertes = false', function(done) { + it('should block any unplanned user attributes when blok.ua = true and additionalPropertes = false', function (done) { event.EventName = 'something something something'; event.EventCategory = Types.EventType.Navigation; event.EventAttributes = { keyword2: 'test', foo: 'hi' }; @@ -244,69 +338,109 @@ describe('kit blocking', () => { 'my other attribute': 'test2', 'a third attribute': 'test3', 'unplanned attribute': 'test4', - } + }; - let kitBlocker = new KitBlocker(kitBlockerDataPlan, window.mParticle.getInstance()); - let transformedEvent = kitBlocker.transformUserAttributes(event); - transformedEvent.UserAttributes.should.have.property('my attribute', 'test1'); - transformedEvent.UserAttributes.should.have.property('my other attribute', 'test2'); - transformedEvent.UserAttributes.should.have.property('a third attribute', 'test3'); - transformedEvent.UserAttributes.should.not.have.property('unplanned attribute'); + const kitBlocker = new KitBlocker( + kitBlockerDataPlan, + window.mParticle.getInstance(), + ); + const transformedEvent = kitBlocker.transformUserAttributes(event); + transformedEvent.UserAttributes.should.have.property( + 'my attribute', + 'test1', + ); + transformedEvent.UserAttributes.should.have.property( + 'my other attribute', + 'test2', + ); + transformedEvent.UserAttributes.should.have.property( + 'a third attribute', + 'test3', + ); + transformedEvent.UserAttributes.should.not.have.property( + 'unplanned attribute', + ); done(); }); - it('should not block any unplanned user attributes if blok.ua = false', function(done) { + it('should not block any unplanned user attributes if blok.ua = false', function (done) { //TODO - what if this additional properties is false? shoudl we validate that? window.mParticle.config.dataPlan.document.dtpn.blok.ua = false; - event.EventName = 'something something something', - event.EventCategory = Types.EventType.Navigation, - event.EventAttributes = { keyword2: 'test', foo: 'hi' }, - event.EventDataType = Types.MessageType.PageEvent, - event.UserAttributes = { - 'my attribute': 'test1', - 'my other attribute': 'test2', - 'a third attribute': 'test3', - 'unplanned attribute': 'test4', - }; + (event.EventName = 'something something something'), + (event.EventCategory = Types.EventType.Navigation), + (event.EventAttributes = { keyword2: 'test', foo: 'hi' }), + (event.EventDataType = Types.MessageType.PageEvent), + (event.UserAttributes = { + 'my attribute': 'test1', + 'my other attribute': 'test2', + 'a third attribute': 'test3', + 'unplanned attribute': 'test4', + }); + + const kitBlocker = new KitBlocker( + kitBlockerDataPlan, + window.mParticle.getInstance(), + ); + const transformedEvent = kitBlocker.transformUserAttributes(event); + transformedEvent.UserAttributes.should.have.property( + 'my attribute', + 'test1', + ); + transformedEvent.UserAttributes.should.have.property( + 'my other attribute', + 'test2', + ); + transformedEvent.UserAttributes.should.have.property( + 'a third attribute', + 'test3', + ); + transformedEvent.UserAttributes.should.have.property( + 'unplanned attribute', + 'test4', + ); - let kitBlocker = new KitBlocker(kitBlockerDataPlan, window.mParticle.getInstance()); - let transformedEvent = kitBlocker.transformUserAttributes(event); - transformedEvent.UserAttributes.should.have.property('my attribute', 'test1'); - transformedEvent.UserAttributes.should.have.property('my other attribute', 'test2'); - transformedEvent.UserAttributes.should.have.property('a third attribute', 'test3'); - transformedEvent.UserAttributes.should.have.property('unplanned attribute', 'test4'); - //reset window.mParticle.config.dataPlan.document.dtpn.blok.ua = true; done(); }); - it('isAttributeKeyBlocked should return false for attributes that are blocked and true for properties that are not', function(done) { + it('isAttributeKeyBlocked should return false for attributes that are blocked and true for properties that are not', function (done) { // this key is blocked because the default data plan has user_attributes>additional_properties = false - const kitBlocker = new KitBlocker(kitBlockerDataPlan, window.mParticle.getInstance()); + const kitBlocker = new KitBlocker( + kitBlockerDataPlan, + window.mParticle.getInstance(), + ); let isBlocked = kitBlocker.isAttributeKeyBlocked('blocked'); isBlocked.should.equal(true); - let userAttributeDataPoint = dataPlan.dtpn.vers.version_document.data_points.find(dataPoint => { - return dataPoint.match.type === 'user_attributes' - }); - userAttributeDataPoint.validator.definition.additionalProperties = true; - - const kitBlocker2 = new KitBlocker(kitBlockerDataPlan, window.mParticle.getInstance()); + const userAttributeDataPoint = + dataPlan.dtpn.vers.version_document.data_points.find( + (dataPoint) => { + return dataPoint.match.type === 'user_attributes'; + }, + ); + userAttributeDataPoint.validator.definition.additionalProperties = + true; + + const kitBlocker2 = new KitBlocker( + kitBlockerDataPlan, + window.mParticle.getInstance(), + ); isBlocked = kitBlocker2.isAttributeKeyBlocked('my attribute'); isBlocked.should.equal(false); // reset to original data plan - userAttributeDataPoint.validator.definition.additionalProperties = false; + userAttributeDataPoint.validator.definition.additionalProperties = + false; done(); }); - it('should not block any unplanned user identities when blok.id = true and additionalProperties = true', function(done) { + it('should not block any unplanned user identities when blok.id = true and additionalProperties = true', function (done) { event.EventName = 'something something something'; event.EventCategory = Types.EventType.Navigation; event.EventAttributes = { keyword2: 'test', foo: 'hi' }; @@ -314,25 +448,38 @@ describe('kit blocking', () => { event.UserIdentities = [ { Type: 7, Identity: 'email@gmail.com' }, { Type: 1, Identity: 'customerid1' }, - { Type: 4, Identity: 'GoogleId' } + { Type: 4, Identity: 'GoogleId' }, ]; - let kitBlocker = new KitBlocker(kitBlockerDataPlan, window.mParticle.getInstance()); - let transformedEvent = kitBlocker.transformUserIdentities(event); - - transformedEvent.UserIdentities.filter(UI => UI.Type === 1)[0].should.have.property('Identity', 'customerid1'); - transformedEvent.UserIdentities.filter(UI => UI.Type === 7)[0].should.have.property('Identity', 'email@gmail.com'); - transformedEvent.UserIdentities.filter(UI => UI.Type === 4)[0].should.have.property('Identity', 'GoogleId'); + const kitBlocker = new KitBlocker( + kitBlockerDataPlan, + window.mParticle.getInstance(), + ); + const transformedEvent = kitBlocker.transformUserIdentities(event); + + transformedEvent.UserIdentities.filter( + (UI) => UI.Type === 1, + )[0].should.have.property('Identity', 'customerid1'); + transformedEvent.UserIdentities.filter( + (UI) => UI.Type === 7, + )[0].should.have.property('Identity', 'email@gmail.com'); + transformedEvent.UserIdentities.filter( + (UI) => UI.Type === 4, + )[0].should.have.property('Identity', 'GoogleId'); done(); }); - it('should block user identities when additional properties = false and blok.id = true', function(done) { - let userIdentityDataPoint = dataPlan.dtpn.vers.version_document.data_points.find(dataPoint => { - return dataPoint.match.type === 'user_identities' - }); + it('should block user identities when additional properties = false and blok.id = true', function (done) { + const userIdentityDataPoint = + dataPlan.dtpn.vers.version_document.data_points.find( + (dataPoint) => { + return dataPoint.match.type === 'user_identities'; + }, + ); - userIdentityDataPoint.validator.definition.additionalProperties = false; + userIdentityDataPoint.validator.definition.additionalProperties = + false; event.EventName = 'something something something'; event.EventCategory = Types.EventType.Navigation; @@ -341,42 +488,64 @@ describe('kit blocking', () => { event.UserIdentities = [ { Type: 7, Identity: 'email@gmail.com' }, { Type: 1, Identity: 'customerid1' }, - { Type: 4, Identity: 'GoogleId' } + { Type: 4, Identity: 'GoogleId' }, ]; - let kitBlocker = new KitBlocker(kitBlockerDataPlan, window.mParticle.getInstance()); - let transformedEvent = kitBlocker.transformUserIdentities(event); - - transformedEvent.UserIdentities.find(UI => UI.Type === 1).should.have.property('Identity', 'customerid1'); - transformedEvent.UserIdentities.find(UI => UI.Type === 7).should.have.property('Identity', 'email@gmail.com'); - (transformedEvent.UserIdentities.find(UI => UI.Type === 4) === undefined).should.equal(true); + const kitBlocker = new KitBlocker( + kitBlockerDataPlan, + window.mParticle.getInstance(), + ); + const transformedEvent = kitBlocker.transformUserIdentities(event); + + transformedEvent.UserIdentities.find( + (UI) => UI.Type === 1, + ).should.have.property('Identity', 'customerid1'); + transformedEvent.UserIdentities.find( + (UI) => UI.Type === 7, + ).should.have.property('Identity', 'email@gmail.com'); + ( + transformedEvent.UserIdentities.find((UI) => UI.Type === 4) === + undefined + ).should.equal(true); // reset - userIdentityDataPoint.validator.definition.additionalProperties = true; + userIdentityDataPoint.validator.definition.additionalProperties = + true; done(); }); - it('isIdentityBlocked should return false for identities that are blocked and true for properties that are not', function(done) { + it('isIdentityBlocked should return false for identities that are blocked and true for properties that are not', function (done) { // this identity is not blocked because the default data plan has user_identities>additional_properties = false - const kitBlocker = new KitBlocker(kitBlockerDataPlan, window.mParticle.getInstance()); + const kitBlocker = new KitBlocker( + kitBlockerDataPlan, + window.mParticle.getInstance(), + ); let isBlocked = kitBlocker.isIdentityBlocked('random identity'); isBlocked.should.equal(false); // for next test, change additionalProperties to false - let userIdentityDataPoint = dataPlan.dtpn.vers.version_document.data_points.find(dataPoint => { - return dataPoint.match.type === 'user_identities' - }); + const userIdentityDataPoint = + dataPlan.dtpn.vers.version_document.data_points.find( + (dataPoint) => { + return dataPoint.match.type === 'user_identities'; + }, + ); + + userIdentityDataPoint.validator.definition.additionalProperties = + false; - userIdentityDataPoint.validator.definition.additionalProperties = false; - - const kitBlocker2 = new KitBlocker(kitBlockerDataPlan, window.mParticle.getInstance()); + const kitBlocker2 = new KitBlocker( + kitBlockerDataPlan, + window.mParticle.getInstance(), + ); isBlocked = kitBlocker2.isIdentityBlocked('facebook'); isBlocked.should.equal(true); // reset to original data plan - userIdentityDataPoint.validator.definition.additionalProperties = true; + userIdentityDataPoint.validator.definition.additionalProperties = + true; done(); }); @@ -388,52 +557,55 @@ describe('kit blocking', () => { let products; beforeEach(() => { - kitBlocker = new KitBlocker(kitBlockerDataPlan, window.mParticle.getInstance()); - products = [ - { - Attributes: { - 'plannedAttr1': 'val1', - 'plannedAttr2': 'val2', - 'unplannedAttr1': 'val3', - 'allowedAttr1': 'val4', - 'allowedAttr2': 'val5', - }, - Name: 'iPhone', - Category: 'category', - CouponCode: 'coupon', - Position: 1, - Price: 999, - Quantity: 1, - Sku: 'iphoneSKU', - TotalAmount: 999, - Variant: '128', - }, - { - Attributes: { - 'plannedAttr1': 'val1', - 'plannedAttr2': 'val2', - 'unplannedAttr1': 'val3', - 'allowedAttr1': 'val4', - 'allowedAttr2': 'val5', - }, - Name: 'S10', - Category: 'category', - CouponCode: 'coupon', - Position: 2, - Price: 500, - Quantity: 1, - Sku: 'galaxySKU', - TotalAmount: 500, - Variant: '256', - } - ] - event = { + kitBlocker = new KitBlocker( + kitBlockerDataPlan, + window.mParticle.getInstance(), + ); + products = [ + { + Attributes: { + plannedAttr1: 'val1', + plannedAttr2: 'val2', + unplannedAttr1: 'val3', + allowedAttr1: 'val4', + allowedAttr2: 'val5', + }, + Name: 'iPhone', + Category: 'category', + CouponCode: 'coupon', + Position: 1, + Price: 999, + Quantity: 1, + Sku: 'iphoneSKU', + TotalAmount: 999, + Variant: '128', + }, + { + Attributes: { + plannedAttr1: 'val1', + plannedAttr2: 'val2', + unplannedAttr1: 'val3', + allowedAttr1: 'val4', + allowedAttr2: 'val5', + }, + Name: 'S10', + Category: 'category', + CouponCode: 'coupon', + Position: 2, + Price: 500, + Quantity: 1, + Sku: 'galaxySKU', + TotalAmount: 500, + Variant: '256', + }, + ]; + event = { DeviceId: 'test', IsFirstRun: true, EventName: null, EventCategory: null, ExpandedEventCount: 0, - MPID: testMPID, + MPID: testMPID, EventAttributes: null, SDKVersion: '1.0.0', SourceMessageId: 'testSMID', @@ -443,34 +615,50 @@ describe('kit blocking', () => { EventDataType: null, Debug: true, CurrencyCode: 'usd', - ActiveTimeOnSite: 10 + ActiveTimeOnSite: 10, }; }); - it('should transform productAttributes if an product attribute is not planned, additionalProperties = false, and blok.ea = true', function(done) { + it('should transform productAttributes if an product attribute is not planned, additionalProperties = false, and blok.ea = true', function (done) { event.EventName = 'eCommerce - Purchase'; event.EventCategory = Types.CommerceEventType.ProductPurchase; event.EventDataType = Types.MessageType.Commerce; event.ProductAction = { ProductActionType: SDKProductActionType.Purchase, ProductList: products, - } + }; - let kitBlocker = new KitBlocker(kitBlockerDataPlan, window.mParticle.getInstance()); + const kitBlocker = new KitBlocker( + kitBlockerDataPlan, + window.mParticle.getInstance(), + ); - let transformedEvent = kitBlocker.transformProductAttributes(event); - transformedEvent.ProductAction.ProductList[0].Attributes.should.not.have.property('unplannedAttr1'); - transformedEvent.ProductAction.ProductList[0].Attributes.should.have.property('plannedAttr1'); - transformedEvent.ProductAction.ProductList[0].Attributes.should.have.property('plannedAttr2'); + const transformedEvent = + kitBlocker.transformProductAttributes(event); + transformedEvent.ProductAction.ProductList[0].Attributes.should.not.have.property( + 'unplannedAttr1', + ); + transformedEvent.ProductAction.ProductList[0].Attributes.should.have.property( + 'plannedAttr1', + ); + transformedEvent.ProductAction.ProductList[0].Attributes.should.have.property( + 'plannedAttr2', + ); - transformedEvent.ProductAction.ProductList[1].Attributes.should.not.have.property('unplannedAttr1'); - transformedEvent.ProductAction.ProductList[1].Attributes.should.have.property('plannedAttr1'); - transformedEvent.ProductAction.ProductList[1].Attributes.should.have.property('plannedAttr2'); + transformedEvent.ProductAction.ProductList[1].Attributes.should.not.have.property( + 'unplannedAttr1', + ); + transformedEvent.ProductAction.ProductList[1].Attributes.should.have.property( + 'plannedAttr1', + ); + transformedEvent.ProductAction.ProductList[1].Attributes.should.have.property( + 'plannedAttr2', + ); done(); }); - it('should not transform productAttributes if a product attribute is not planned, additionalProperties = false, and blok.ea = true', function(done) { + it('should not transform productAttributes if a product attribute is not planned, additionalProperties = false, and blok.ea = true', function (done) { event.EventName = 'eCommerce - AddToCart'; event.EventCategory = Types.CommerceEventType.ProductAddToCart; event.EventDataType = Types.MessageType.Commerce; @@ -479,55 +667,115 @@ describe('kit blocking', () => { ProductList: products, }; - let kitBlocker = new KitBlocker(kitBlockerDataPlan, window.mParticle.getInstance()); - let transformedEvent = kitBlocker.transformProductAttributes(event); - - transformedEvent.ProductAction.ProductList[0].Attributes.should.have.property('unplannedAttr1'); - transformedEvent.ProductAction.ProductList[0].Attributes.should.have.property('plannedAttr1'); - transformedEvent.ProductAction.ProductList[0].Attributes.should.have.property('plannedAttr2'); + const kitBlocker = new KitBlocker( + kitBlockerDataPlan, + window.mParticle.getInstance(), + ); + const transformedEvent = + kitBlocker.transformProductAttributes(event); + + transformedEvent.ProductAction.ProductList[0].Attributes.should.have.property( + 'unplannedAttr1', + ); + transformedEvent.ProductAction.ProductList[0].Attributes.should.have.property( + 'plannedAttr1', + ); + transformedEvent.ProductAction.ProductList[0].Attributes.should.have.property( + 'plannedAttr2', + ); - transformedEvent.ProductAction.ProductList[1].Attributes.should.have.property('unplannedAttr1'); - transformedEvent.ProductAction.ProductList[1].Attributes.should.have.property('plannedAttr1'); - transformedEvent.ProductAction.ProductList[1].Attributes.should.have.property('plannedAttr2'); + transformedEvent.ProductAction.ProductList[1].Attributes.should.have.property( + 'unplannedAttr1', + ); + transformedEvent.ProductAction.ProductList[1].Attributes.should.have.property( + 'plannedAttr1', + ); + transformedEvent.ProductAction.ProductList[1].Attributes.should.have.property( + 'plannedAttr2', + ); done(); }); - it('should transform productAttributes in product impressions if an product attribute is not planned, additionalProperties = false, and blok.ea = true', function(done) { + it('should transform productAttributes in product impressions if an product attribute is not planned, additionalProperties = false, and blok.ea = true', function (done) { event.EventName = 'eCommerce - Impression'; event.ProductImpressions = [ { ProductImpressionList: 'imp1', - ProductList: products + ProductList: products, }, { ProductImpressionList: 'imp2', - ProductList: products - } - ] + ProductList: products, + }, + ]; event.EventCategory = Types.CommerceEventType.ProductImpression; event.EventDataType = Types.MessageType.Commerce; - let kitBlocker = new KitBlocker(kitBlockerDataPlan, window.mParticle.getInstance()); - let transformedEvent = kitBlocker.transformProductAttributes(event); - - transformedEvent.ProductImpressions[0].ProductList[0].Attributes.should.have.property('allowedAttr1', 'val4'); - transformedEvent.ProductImpressions[0].ProductList[0].Attributes.should.have.property('allowedAttr2', 'val5'); - transformedEvent.ProductImpressions[0].ProductList[0].Attributes.should.not.have.property('unplannedAttr1'); - transformedEvent.ProductImpressions[0].ProductList[0].Attributes.should.not.have.property('unplannedAttr2'); - transformedEvent.ProductImpressions[0].ProductList[1].Attributes.should.have.property('allowedAttr1', 'val4'); - transformedEvent.ProductImpressions[0].ProductList[1].Attributes.should.have.property('allowedAttr2', 'val5'); - transformedEvent.ProductImpressions[0].ProductList[1].Attributes.should.not.have.property('unplannedAttr1'); - transformedEvent.ProductImpressions[0].ProductList[1].Attributes.should.not.have.property('unplannedAttr2'); - - transformedEvent.ProductImpressions[1].ProductList[0].Attributes.should.have.property('allowedAttr1', 'val4'); - transformedEvent.ProductImpressions[1].ProductList[0].Attributes.should.have.property('allowedAttr2', 'val5'); - transformedEvent.ProductImpressions[1].ProductList[0].Attributes.should.not.have.property('unplannedAttr1'); - transformedEvent.ProductImpressions[1].ProductList[0].Attributes.should.not.have.property('unplannedAttr2'); - transformedEvent.ProductImpressions[1].ProductList[1].Attributes.should.have.property('allowedAttr1', 'val4'); - transformedEvent.ProductImpressions[1].ProductList[1].Attributes.should.have.property('allowedAttr2', 'val5'); - transformedEvent.ProductImpressions[1].ProductList[1].Attributes.should.not.have.property('unplannedAttr1'); - transformedEvent.ProductImpressions[1].ProductList[1].Attributes.should.not.have.property('unplannedAttr2'); + const kitBlocker = new KitBlocker( + kitBlockerDataPlan, + window.mParticle.getInstance(), + ); + const transformedEvent = + kitBlocker.transformProductAttributes(event); + + transformedEvent.ProductImpressions[0].ProductList[0].Attributes.should.have.property( + 'allowedAttr1', + 'val4', + ); + transformedEvent.ProductImpressions[0].ProductList[0].Attributes.should.have.property( + 'allowedAttr2', + 'val5', + ); + transformedEvent.ProductImpressions[0].ProductList[0].Attributes.should.not.have.property( + 'unplannedAttr1', + ); + transformedEvent.ProductImpressions[0].ProductList[0].Attributes.should.not.have.property( + 'unplannedAttr2', + ); + transformedEvent.ProductImpressions[0].ProductList[1].Attributes.should.have.property( + 'allowedAttr1', + 'val4', + ); + transformedEvent.ProductImpressions[0].ProductList[1].Attributes.should.have.property( + 'allowedAttr2', + 'val5', + ); + transformedEvent.ProductImpressions[0].ProductList[1].Attributes.should.not.have.property( + 'unplannedAttr1', + ); + transformedEvent.ProductImpressions[0].ProductList[1].Attributes.should.not.have.property( + 'unplannedAttr2', + ); + + transformedEvent.ProductImpressions[1].ProductList[0].Attributes.should.have.property( + 'allowedAttr1', + 'val4', + ); + transformedEvent.ProductImpressions[1].ProductList[0].Attributes.should.have.property( + 'allowedAttr2', + 'val5', + ); + transformedEvent.ProductImpressions[1].ProductList[0].Attributes.should.not.have.property( + 'unplannedAttr1', + ); + transformedEvent.ProductImpressions[1].ProductList[0].Attributes.should.not.have.property( + 'unplannedAttr2', + ); + transformedEvent.ProductImpressions[1].ProductList[1].Attributes.should.have.property( + 'allowedAttr1', + 'val4', + ); + transformedEvent.ProductImpressions[1].ProductList[1].Attributes.should.have.property( + 'allowedAttr2', + 'val5', + ); + transformedEvent.ProductImpressions[1].ProductList[1].Attributes.should.not.have.property( + 'unplannedAttr1', + ); + transformedEvent.ProductImpressions[1].ProductList[1].Attributes.should.not.have.property( + 'unplannedAttr2', + ); done(); }); @@ -540,31 +788,31 @@ describe('kit blocking', () => { is_logged_in: false, }); - let mockForwarder = new MockForwarder(); + const mockForwarder = new MockForwarder(); window.mParticle.addForwarder(mockForwarder); }); - it('integration test - should log an error if the data plan has an error on it', function(done) { + it('integration test - should log an error if the data plan has an error on it', function (done) { const errorMessage = 'This is an error'; window.mParticle.config.dataPlan = { document: { - error_message: errorMessage - } + error_message: errorMessage, + }, }; - let errorMessages = []; + const errorMessages = []; window.mParticle._resetForTests(MPConfig); - let mockForwarder = new MockForwarder(); + const mockForwarder = new MockForwarder(); window.mParticle.addForwarder(mockForwarder); window.mParticle.config.logLevel = 'verbose'; window.mParticle.config.logger = { - error: function(err) { - errorMessages.push(err) - } - } + error: function (err) { + errorMessages.push(err); + }, + }; window.mParticle.init(apiKey, window.mParticle.config); errorMessages[0].should.equal(errorMessage); @@ -573,676 +821,1074 @@ describe('kit blocking', () => { done(); }); - it('integration test - should block a custom event from reaching the forwarder if event is unplanned and block.ev=true', function(done) { - window.mParticle.config.kitConfigs.push(forwarderDefaultConfiguration('MockForwarder')); + it('integration test - should block a custom event from reaching the forwarder if event is unplanned and block.ev=true', function (done) { + window.mParticle.config.kitConfigs.push( + forwarderDefaultConfiguration('MockForwarder'), + ); window.mParticle.init(apiKey, window.mParticle.config); window.mParticle.logEvent('Blocked event'); - let event = window.MockForwarder1.instance.receivedEvent; + const event = window.MockForwarder1.instance.receivedEvent; (event === null).should.equal(true); - + done(); }); - it('integration test - should allow unplanned custom events through to forwarder if blok.ev=false', function(done) { - window.mParticle.config.kitConfigs.push(forwarderDefaultConfiguration('MockForwarder')); + it('integration test - should allow unplanned custom events through to forwarder if blok.ev=false', function (done) { + window.mParticle.config.kitConfigs.push( + forwarderDefaultConfiguration('MockForwarder'), + ); window.mParticle.config.dataPlan.document.dtpn.blok.ev = false; window.mParticle.init(apiKey, window.mParticle.config); - waitForCondition(hasIdentifyReturned) - .then(() => { - - window.mParticle.logEvent('Unplanned Event'); - - let event = window.MockForwarder1.instance.receivedEvent; - event.should.have.property('EventName', 'Unplanned Event'); - - // reset - window.mParticle.config.dataPlan.document.dtpn.blok.ev = true; - - done(); + waitForCondition(hasIdentifyReturned).then(() => { + window.mParticle.logEvent('Unplanned Event'); + + const event = window.MockForwarder1.instance.receivedEvent; + event.should.have.property('EventName', 'Unplanned Event'); + + // reset + window.mParticle.config.dataPlan.document.dtpn.blok.ev = true; + + done(); }); }); - it('integration test - should block an unplanned attribute from being set on the forwarder if additionalProperties = false and blok.ua = true', function(done) { - window.mParticle.config.kitConfigs.push(forwarderDefaultConfiguration('MockForwarder')); + it('integration test - should block an unplanned attribute from being set on the forwarder if additionalProperties = false and blok.ua = true', function (done) { + window.mParticle.config.kitConfigs.push( + forwarderDefaultConfiguration('MockForwarder'), + ); window.mParticle.init(apiKey, window.mParticle.config); - waitForCondition(hasIdentifyReturned) - .then(() => { - - window.mParticle.Identity.getCurrentUser().setUserAttribute('unplannedAttr', true); - window.MockForwarder1.instance.should.have.property( - 'setUserAttributeCalled', - false - ); + waitForCondition(hasIdentifyReturned).then(() => { + window.mParticle.Identity.getCurrentUser().setUserAttribute( + 'unplannedAttr', + true, + ); + window.MockForwarder1.instance.should.have.property( + 'setUserAttributeCalled', + false, + ); - done(); - }) + done(); + }); }); - it('integration test - should not throw an error when unplanned user attributes are allowed and block.ua = true', function(done) { - window.mParticle.config.kitConfigs.push(forwarderDefaultConfiguration('MockForwarder')); + it('integration test - should not throw an error when unplanned user attributes are allowed and block.ua = true', function (done) { + window.mParticle.config.kitConfigs.push( + forwarderDefaultConfiguration('MockForwarder'), + ); window.mParticle.init(apiKey, window.mParticle.config); // save old data points for reset later - const oldDataPoints = dataPlan.dtpn.vers.version_document.data_points; + const oldDataPoints = + dataPlan.dtpn.vers.version_document.data_points; // when "Allow unplanned user attributes" is enabled, the data points returned is an empty array dataPlan.dtpn.vers.version_document.data_points = []; - let kitBlocker = new KitBlocker(kitBlockerDataPlan, window.mParticle.getInstance()); + const kitBlocker = new KitBlocker( + kitBlockerDataPlan, + window.mParticle.getInstance(), + ); - expect(() => { kitBlocker.isAttributeKeyBlocked('unplannedAttr') }).to.not.throw(TypeError, /Cannot read properties of undefined \(reading 'unplannedAttr'\)/) + expect(() => { + kitBlocker.isAttributeKeyBlocked('unplannedAttr'); + }).to.not.throw( + TypeError, + /Cannot read properties of undefined \(reading 'unplannedAttr'\)/, + ); // "Allow unplanned user attributes" is prioritized when blocking unplanned attributes is also enabled, hence the expected value is false - expect(kitBlocker.isAttributeKeyBlocked('unplannedAttr')).to.equal(false) + expect(kitBlocker.isAttributeKeyBlocked('unplannedAttr')).to.equal( + false, + ); // reset data points dataPlan.dtpn.vers.version_document.data_points = oldDataPoints; done(); }); - it('integration test - should allow an unplanned attribute to be set on forwarder if additionalProperties = true and blok.ua = true', function(done) { - let userAttributeDataPoint = dataPlan.dtpn.vers.version_document.data_points.find(dataPoint => { - return dataPoint.match.type === 'user_attributes' - }); + it('integration test - should allow an unplanned attribute to be set on forwarder if additionalProperties = true and blok.ua = true', function (done) { + const userAttributeDataPoint = + dataPlan.dtpn.vers.version_document.data_points.find( + (dataPoint) => { + return dataPoint.match.type === 'user_attributes'; + }, + ); - userAttributeDataPoint.validator.definition.additionalProperties = true; + userAttributeDataPoint.validator.definition.additionalProperties = + true; - window.mParticle.config.kitConfigs.push(forwarderDefaultConfiguration('MockForwarder')); + window.mParticle.config.kitConfigs.push( + forwarderDefaultConfiguration('MockForwarder'), + ); window.mParticle.init(apiKey, window.mParticle.config); - waitForCondition(hasIdentifyReturned) - .then(() => { + waitForCondition(hasIdentifyReturned).then(() => { + window.mParticle.Identity.getCurrentUser().setUserAttribute( + 'unplanned but unblocked', + true, + ); + window.MockForwarder1.instance.should.have.property( + 'setUserAttributeCalled', + true, + ); - window.mParticle.Identity.getCurrentUser().setUserAttribute('unplanned but unblocked', true); - window.MockForwarder1.instance.should.have.property( - 'setUserAttributeCalled', - true - ); + userAttributeDataPoint.validator.definition.additionalProperties = + false; - userAttributeDataPoint.validator.definition.additionalProperties = false; - - done(); + done(); }); }); - it('integration test - should allow an unplanned user attribute to be set on the forwarder if blok=false', function(done) { - window.mParticle.config.dataPlan.document.dtpn.blok.ua = false + it('integration test - should allow an unplanned user attribute to be set on the forwarder if blok=false', function (done) { + window.mParticle.config.dataPlan.document.dtpn.blok.ua = false; - window.mParticle.config.kitConfigs.push(forwarderDefaultConfiguration('MockForwarder')); + window.mParticle.config.kitConfigs.push( + forwarderDefaultConfiguration('MockForwarder'), + ); window.mParticle.init(apiKey, window.mParticle.config); - waitForCondition(hasIdentifyReturned) - .then(() => { - window.mParticle.Identity.getCurrentUser().setUserAttribute('unplanned but not blocked', true); - window.MockForwarder1.instance.should.have.property( - 'setUserAttributeCalled', - true - ); + waitForCondition(hasIdentifyReturned).then(() => { + window.mParticle.Identity.getCurrentUser().setUserAttribute( + 'unplanned but not blocked', + true, + ); + window.MockForwarder1.instance.should.have.property( + 'setUserAttributeCalled', + true, + ); - window.mParticle.config.dataPlan.document.dtpn.blok.ua = true + window.mParticle.config.dataPlan.document.dtpn.blok.ua = true; - done(); + done(); }); }); - it('integration test - should block an unplanned attribute set via setUserTag from being set on the forwarder if additionalProperties = false and blok.ua = true', function(done) { - window.mParticle.config.kitConfigs.push(forwarderDefaultConfiguration('MockForwarder')); - window.mParticle.init(apiKey, window.mParticle.config); - waitForCondition(hasIdentifyReturned) - .then(() => { - window.mParticle.Identity.getCurrentUser().setUserTag('unplannedAttr', true); - window.MockForwarder1.instance.should.have.property( - 'setUserAttributeCalled', - false + it('integration test - should block an unplanned attribute set via setUserTag from being set on the forwarder if additionalProperties = false and blok.ua = true', function (done) { + window.mParticle.config.kitConfigs.push( + forwarderDefaultConfiguration('MockForwarder'), ); + window.mParticle.init(apiKey, window.mParticle.config); + waitForCondition(hasIdentifyReturned).then(() => { + window.mParticle.Identity.getCurrentUser().setUserTag( + 'unplannedAttr', + true, + ); + window.MockForwarder1.instance.should.have.property( + 'setUserAttributeCalled', + false, + ); - done(); + done(); }); }); - it('integration test - should allow an unplanned attribute set via setUserTag to be set on forwarder if additionalProperties = true and blok.ua = true', function(done) { - let userAttributeDataPoint = dataPlan.dtpn.vers.version_document.data_points.find(dataPoint => { - return dataPoint.match.type === 'user_attributes' - }); + it('integration test - should allow an unplanned attribute set via setUserTag to be set on forwarder if additionalProperties = true and blok.ua = true', function (done) { + const userAttributeDataPoint = + dataPlan.dtpn.vers.version_document.data_points.find( + (dataPoint) => { + return dataPoint.match.type === 'user_attributes'; + }, + ); - userAttributeDataPoint.validator.definition.additionalProperties = true; + userAttributeDataPoint.validator.definition.additionalProperties = + true; - window.mParticle.config.kitConfigs.push(forwarderDefaultConfiguration('MockForwarder')); + window.mParticle.config.kitConfigs.push( + forwarderDefaultConfiguration('MockForwarder'), + ); window.mParticle.init(apiKey, window.mParticle.config); - waitForCondition(hasIdentifyReturned) - .then(() => { + waitForCondition(hasIdentifyReturned).then(() => { + window.mParticle.Identity.getCurrentUser().setUserTag( + 'unplanned but unblocked', + true, + ); + window.MockForwarder1.instance.should.have.property( + 'setUserAttributeCalled', + true, + ); - window.mParticle.Identity.getCurrentUser().setUserTag('unplanned but unblocked', true); - window.MockForwarder1.instance.should.have.property( - 'setUserAttributeCalled', - true - ); + userAttributeDataPoint.validator.definition.additionalProperties = + false; - userAttributeDataPoint.validator.definition.additionalProperties = false; - - done(); + done(); }); }); - it('integration test - should allow an unplanned user attribute set via setUserTag to be set on the forwarder if blok=false', function(done) { - window.mParticle.config.dataPlan.document.dtpn.blok.ua = false - window.mParticle.config.kitConfigs.push(forwarderDefaultConfiguration('MockForwarder')); - window.mParticle.init(apiKey, window.mParticle.config); - waitForCondition(hasIdentifyReturned) - .then(() => { - - window.mParticle.Identity.getCurrentUser().setUserTag('unplanned but not blocked', true); - window.MockForwarder1.instance.should.have.property( - 'setUserAttributeCalled', - true + it('integration test - should allow an unplanned user attribute set via setUserTag to be set on the forwarder if blok=false', function (done) { + window.mParticle.config.dataPlan.document.dtpn.blok.ua = false; + window.mParticle.config.kitConfigs.push( + forwarderDefaultConfiguration('MockForwarder'), ); + window.mParticle.init(apiKey, window.mParticle.config); + waitForCondition(hasIdentifyReturned).then(() => { + window.mParticle.Identity.getCurrentUser().setUserTag( + 'unplanned but not blocked', + true, + ); + window.MockForwarder1.instance.should.have.property( + 'setUserAttributeCalled', + true, + ); - window.mParticle.config.dataPlan.document.dtpn.blok.ua = true + window.mParticle.config.dataPlan.document.dtpn.blok.ua = true; - done(); + done(); }); }); - describe('integration tests - user identity related', ()=> { + describe('integration tests - user identity related', () => { let userIdentityRequest; beforeEach(() => { ['login', 'logout', 'modify'].forEach((identityMethod) => { - fetchMockSuccess(urls[identityMethod], { mpid: testMPID, is_logged_in: true })} - ); - let mockForwarder = new MockForwarder(); + fetchMockSuccess(urls[identityMethod], { + mpid: testMPID, + is_logged_in: true, + }); + }); + const mockForwarder = new MockForwarder(); window.mParticle.addForwarder(mockForwarder); - + userIdentityRequest = { userIdentities: { google: 'test', customerid: 'id1', other: 'id2', yahoo: 'yahoo1', - email: 'email@gmail.com' + email: 'email@gmail.com', }, }; }); - it('integration test - should not block any unplanned user identities to the forwarder when blok.id = true and additionalProperties = true', function(done) { - window.mParticle.config.kitConfigs.push(forwarderDefaultConfiguration('MockForwarder')); + it('integration test - should not block any unplanned user identities to the forwarder when blok.id = true and additionalProperties = true', function (done) { + window.mParticle.config.kitConfigs.push( + forwarderDefaultConfiguration('MockForwarder'), + ); window.mParticle.init(apiKey, window.mParticle.config); - waitForCondition(hasIdentifyReturned) - .then(() => { - window.mParticle.Identity.login({userIdentities: {customerid: 'customerid1', email: 'email@gmail.com', 'google': 'GoogleId'}}); - waitForCondition(() => { - return ( - window.mParticle.getInstance()?._Store?.identityCallInFlight === false - ); - }) - .then(() => { - window.mParticle.logEvent('something something something', Types.EventType.Navigation); - let event = window.MockForwarder1.instance.receivedEvent; - event.UserIdentities.find(UI => UI.Type === 1).should.have.property('Identity', 'customerid1'); - event.UserIdentities.find(UI => UI.Type === 7).should.have.property('Identity', 'email@gmail.com'); - event.UserIdentities.find(UI => UI.Type === 4).should.have.property('Identity', 'GoogleId'); - - done(); - }); + waitForCondition(hasIdentifyReturned).then(() => { + window.mParticle.Identity.login({ + userIdentities: { + customerid: 'customerid1', + email: 'email@gmail.com', + google: 'GoogleId', + }, + }); + waitForCondition(() => { + return ( + window.mParticle.getInstance()?._Store + ?.identityCallInFlight === false + ); + }).then(() => { + window.mParticle.logEvent( + 'something something something', + Types.EventType.Navigation, + ); + const event = + window.MockForwarder1.instance.receivedEvent; + event.UserIdentities.find( + (UI) => UI.Type === 1, + ).should.have.property('Identity', 'customerid1'); + event.UserIdentities.find( + (UI) => UI.Type === 7, + ).should.have.property('Identity', 'email@gmail.com'); + event.UserIdentities.find( + (UI) => UI.Type === 4, + ).should.have.property('Identity', 'GoogleId'); + + done(); + }); }); }); - it('integration test - should block user identities to the forwarder when additional properties = false and blok.id = true', function(done) { - let userIdentityDataPoint = dataPlan.dtpn.vers.version_document.data_points.find(dataPoint => { - return dataPoint.match.type === 'user_identities' - }); - - userIdentityDataPoint.validator.definition.additionalProperties = false; - - window.mParticle.config.kitConfigs.push(forwarderDefaultConfiguration('MockForwarder')); - window.mParticle.init(apiKey, window.mParticle.config); - waitForCondition(hasIdentifyReturned) - .then(() => { - - window.mParticle.Identity.login({userIdentities: {customerid: 'customerid1', email: 'email@gmail.com', 'google': 'GoogleId'}}); - waitForCondition(() => { - return ( - window.mParticle.getInstance()?._Store?.identityCallInFlight === false + it('integration test - should block user identities to the forwarder when additional properties = false and blok.id = true', function (done) { + const userIdentityDataPoint = + dataPlan.dtpn.vers.version_document.data_points.find( + (dataPoint) => { + return dataPoint.match.type === 'user_identities'; + }, ); - }) - .then(() => { - window.mParticle.logEvent('something something something', Types.EventType.Navigation); - let event = window.MockForwarder1.instance.receivedEvent; - event.UserIdentities.find(UI => UI.Type === 1).should.have.property('Identity', 'customerid1'); - event.UserIdentities.find(UI => UI.Type === 7).should.have.property('Identity', 'email@gmail.com'); - (event.UserIdentities.find(UI => UI.Type === 4) === undefined).should.not.have.property('Identity', 'GoogleId'); - // reset - userIdentityDataPoint.validator.definition.additionalProperties = true; + userIdentityDataPoint.validator.definition.additionalProperties = + false; - done(); - }); + window.mParticle.config.kitConfigs.push( + forwarderDefaultConfiguration('MockForwarder'), + ); + window.mParticle.init(apiKey, window.mParticle.config); + waitForCondition(hasIdentifyReturned).then(() => { + window.mParticle.Identity.login({ + userIdentities: { + customerid: 'customerid1', + email: 'email@gmail.com', + google: 'GoogleId', + }, + }); + waitForCondition(() => { + return ( + window.mParticle.getInstance()?._Store + ?.identityCallInFlight === false + ); + }).then(() => { + window.mParticle.logEvent( + 'something something something', + Types.EventType.Navigation, + ); + const event = + window.MockForwarder1.instance.receivedEvent; + event.UserIdentities.find( + (UI) => UI.Type === 1, + ).should.have.property('Identity', 'customerid1'); + event.UserIdentities.find( + (UI) => UI.Type === 7, + ).should.have.property('Identity', 'email@gmail.com'); + ( + event.UserIdentities.find((UI) => UI.Type === 4) === + undefined + ).should.not.have.property('Identity', 'GoogleId'); + + // reset + userIdentityDataPoint.validator.definition.additionalProperties = + true; + + done(); + }); }); }); - it('integration test - should not block identities from being passed to onUserIdentified/onLogoutComplete if blok.id = true and additionalProperties = true (in addition to having a filtered user identity list)', function(done) { - let config1 = forwarderDefaultConfiguration('MockForwarder', 1); + it('integration test - should not block identities from being passed to onUserIdentified/onLogoutComplete if blok.id = true and additionalProperties = true (in addition to having a filtered user identity list)', function (done) { + const config1 = forwarderDefaultConfiguration( + 'MockForwarder', + 1, + ); (config1.userIdentityFilters = [4]), window.mParticle.config.kitConfigs.push(config1); window.mParticle.init(apiKey, window.mParticle.config); - waitForCondition(hasIdentifyReturned) - .then(() => { - window.mParticle.Identity.logout(userIdentityRequest); - waitForCondition(() => { - return ( - window.mParticle.getInstance()?._Store?.identityCallInFlight === false - ); - }) - .then(() => { - let onUserIdentifiedUserIdentities = window.MockForwarder1.instance.onUserIdentifiedUser - .getUserIdentities() - .userIdentities; - onUserIdentifiedUserIdentities.should.not.have.property('google'); - onUserIdentifiedUserIdentities.should.have.property('customerid', 'id1'); - onUserIdentifiedUserIdentities.should.have.property('other', 'id2'); - onUserIdentifiedUserIdentities.should.have.property('yahoo', 'yahoo1'); - onUserIdentifiedUserIdentities.should.have.property('email', 'email@gmail.com'); - - let onLogoutCompleteUserIdentities = window.MockForwarder1.instance.onLogoutCompleteUser - .getUserIdentities() - .userIdentities; - onLogoutCompleteUserIdentities.should.not.have.property('google'); - onLogoutCompleteUserIdentities.should.have.property('customerid', 'id1'); - onLogoutCompleteUserIdentities.should.have.property('other', 'id2'); - onLogoutCompleteUserIdentities.should.have.property('yahoo', 'yahoo1'); - onLogoutCompleteUserIdentities.should.have.property('email', 'email@gmail.com'); - - done(); - }); + waitForCondition(hasIdentifyReturned).then(() => { + window.mParticle.Identity.logout(userIdentityRequest); + waitForCondition(() => { + return ( + window.mParticle.getInstance()?._Store + ?.identityCallInFlight === false + ); + }).then(() => { + const onUserIdentifiedUserIdentities = + window.MockForwarder1.instance.onUserIdentifiedUser.getUserIdentities() + .userIdentities; + onUserIdentifiedUserIdentities.should.not.have.property( + 'google', + ); + onUserIdentifiedUserIdentities.should.have.property( + 'customerid', + 'id1', + ); + onUserIdentifiedUserIdentities.should.have.property( + 'other', + 'id2', + ); + onUserIdentifiedUserIdentities.should.have.property( + 'yahoo', + 'yahoo1', + ); + onUserIdentifiedUserIdentities.should.have.property( + 'email', + 'email@gmail.com', + ); + + const onLogoutCompleteUserIdentities = + window.MockForwarder1.instance.onLogoutCompleteUser.getUserIdentities() + .userIdentities; + onLogoutCompleteUserIdentities.should.not.have.property( + 'google', + ); + onLogoutCompleteUserIdentities.should.have.property( + 'customerid', + 'id1', + ); + onLogoutCompleteUserIdentities.should.have.property( + 'other', + 'id2', + ); + onLogoutCompleteUserIdentities.should.have.property( + 'yahoo', + 'yahoo1', + ); + onLogoutCompleteUserIdentities.should.have.property( + 'email', + 'email@gmail.com', + ); + + done(); + }); }); }); - it('integration test - should block identities from being passed to onUserIdentified/onLogoutComplete if blok.id = true and additionalProperties = false (in addition to having a filtered user identity list)', function(done) { - let userIdentityDataPoint = dataPlan.dtpn.vers.version_document.data_points.find(dataPoint => { - return dataPoint.match.type === 'user_identities' - }); + it('integration test - should block identities from being passed to onUserIdentified/onLogoutComplete if blok.id = true and additionalProperties = false (in addition to having a filtered user identity list)', function (done) { + const userIdentityDataPoint = + dataPlan.dtpn.vers.version_document.data_points.find( + (dataPoint) => { + return dataPoint.match.type === 'user_identities'; + }, + ); - userIdentityDataPoint.validator.definition.additionalProperties = false; + userIdentityDataPoint.validator.definition.additionalProperties = + false; - let config1 = forwarderDefaultConfiguration('MockForwarder', 1); + const config1 = forwarderDefaultConfiguration( + 'MockForwarder', + 1, + ); (config1.userIdentityFilters = [4]), window.mParticle.config.kitConfigs.push(config1); window.mParticle.init(apiKey, window.mParticle.config); - waitForCondition(hasIdentifyReturned) - .then(() => { - window.mParticle.Identity.logout(userIdentityRequest); - waitForCondition(() => { - return ( - window.mParticle.getInstance()?._Store?.identityCallInFlight === false - ); - }) - .then(() => { - let onUserIdentifiedUserIdentities = window.MockForwarder1.instance.onUserIdentifiedUser - .getUserIdentities() - .userIdentities; - onUserIdentifiedUserIdentities.should.have.property('customerid', 'id1'); - onUserIdentifiedUserIdentities.should.have.property('email', 'email@gmail.com'); - onUserIdentifiedUserIdentities.should.not.have.property('google'); - onUserIdentifiedUserIdentities.should.not.have.property('other', 'id2'); - onUserIdentifiedUserIdentities.should.not.have.property('yahoo'); - - let onLogoutCompleteUserIdentities = window.MockForwarder1.instance.onLogoutCompleteUser - .getUserIdentities() - .userIdentities; - onLogoutCompleteUserIdentities.should.have.property('customerid', 'id1'); - onLogoutCompleteUserIdentities.should.have.property('email', 'email@gmail.com'); - onLogoutCompleteUserIdentities.should.not.have.property('google'); - onLogoutCompleteUserIdentities.should.not.have.property('other', 'id2'); - onLogoutCompleteUserIdentities.should.not.have.property('yahoo'); - - userIdentityDataPoint.validator.definition.additionalProperties = true; - - done(); - }); + waitForCondition(hasIdentifyReturned).then(() => { + window.mParticle.Identity.logout(userIdentityRequest); + waitForCondition(() => { + return ( + window.mParticle.getInstance()?._Store + ?.identityCallInFlight === false + ); + }).then(() => { + const onUserIdentifiedUserIdentities = + window.MockForwarder1.instance.onUserIdentifiedUser.getUserIdentities() + .userIdentities; + onUserIdentifiedUserIdentities.should.have.property( + 'customerid', + 'id1', + ); + onUserIdentifiedUserIdentities.should.have.property( + 'email', + 'email@gmail.com', + ); + onUserIdentifiedUserIdentities.should.not.have.property( + 'google', + ); + onUserIdentifiedUserIdentities.should.not.have.property( + 'other', + 'id2', + ); + onUserIdentifiedUserIdentities.should.not.have.property( + 'yahoo', + ); + + const onLogoutCompleteUserIdentities = + window.MockForwarder1.instance.onLogoutCompleteUser.getUserIdentities() + .userIdentities; + onLogoutCompleteUserIdentities.should.have.property( + 'customerid', + 'id1', + ); + onLogoutCompleteUserIdentities.should.have.property( + 'email', + 'email@gmail.com', + ); + onLogoutCompleteUserIdentities.should.not.have.property( + 'google', + ); + onLogoutCompleteUserIdentities.should.not.have.property( + 'other', + 'id2', + ); + onLogoutCompleteUserIdentities.should.not.have.property( + 'yahoo', + ); + + userIdentityDataPoint.validator.definition.additionalProperties = + true; + + done(); + }); }); }); - it('integration test - should not block identities from being passed to onUserIdentified/onModifyComplete if blok.id = true and additionalProperties = true (in addition to having a filtered user identity list)', function(done) { - let config1 = forwarderDefaultConfiguration('MockForwarder', 1); + it('integration test - should not block identities from being passed to onUserIdentified/onModifyComplete if blok.id = true and additionalProperties = true (in addition to having a filtered user identity list)', function (done) { + const config1 = forwarderDefaultConfiguration( + 'MockForwarder', + 1, + ); (config1.userIdentityFilters = [4]), window.mParticle.config.kitConfigs.push(config1); window.mParticle.init(apiKey, window.mParticle.config); - waitForCondition(hasIdentifyReturned) - .then(() => { - window.mParticle.Identity.modify(userIdentityRequest); - waitForCondition(() => { - return ( - window.mParticle.getInstance()?._Store?.identityCallInFlight === false - ); - }) - .then(() => { - let onUserIdentifiedUserIdentities = window.MockForwarder1.instance.onUserIdentifiedUser - .getUserIdentities() - .userIdentities; - onUserIdentifiedUserIdentities.should.not.have.property('google'); - onUserIdentifiedUserIdentities.should.have.property('customerid', 'id1'); - onUserIdentifiedUserIdentities.should.have.property('other', 'id2'); - onUserIdentifiedUserIdentities.should.have.property('yahoo', 'yahoo1'); - onUserIdentifiedUserIdentities.should.have.property('email', 'email@gmail.com'); - - let onModifyCompleteUserIdentities = window.MockForwarder1.instance.onModifyCompleteUser - .getUserIdentities() - .userIdentities; - onModifyCompleteUserIdentities.should.not.have.property('google'); - onModifyCompleteUserIdentities.should.have.property('customerid', 'id1'); - onModifyCompleteUserIdentities.should.have.property('other', 'id2'); - onModifyCompleteUserIdentities.should.have.property('yahoo', 'yahoo1'); - onModifyCompleteUserIdentities.should.have.property('email', 'email@gmail.com'); - - done(); - }); - }); + waitForCondition(hasIdentifyReturned).then(() => { + window.mParticle.Identity.modify(userIdentityRequest); + waitForCondition(() => { + return ( + window.mParticle.getInstance()?._Store + ?.identityCallInFlight === false + ); + }).then(() => { + const onUserIdentifiedUserIdentities = + window.MockForwarder1.instance.onUserIdentifiedUser.getUserIdentities() + .userIdentities; + onUserIdentifiedUserIdentities.should.not.have.property( + 'google', + ); + onUserIdentifiedUserIdentities.should.have.property( + 'customerid', + 'id1', + ); + onUserIdentifiedUserIdentities.should.have.property( + 'other', + 'id2', + ); + onUserIdentifiedUserIdentities.should.have.property( + 'yahoo', + 'yahoo1', + ); + onUserIdentifiedUserIdentities.should.have.property( + 'email', + 'email@gmail.com', + ); + + const onModifyCompleteUserIdentities = + window.MockForwarder1.instance.onModifyCompleteUser.getUserIdentities() + .userIdentities; + onModifyCompleteUserIdentities.should.not.have.property( + 'google', + ); + onModifyCompleteUserIdentities.should.have.property( + 'customerid', + 'id1', + ); + onModifyCompleteUserIdentities.should.have.property( + 'other', + 'id2', + ); + onModifyCompleteUserIdentities.should.have.property( + 'yahoo', + 'yahoo1', + ); + onModifyCompleteUserIdentities.should.have.property( + 'email', + 'email@gmail.com', + ); + + done(); + }); + }); }); - it('integration test - should block identities from being passed to onUserIdentified/onModifyComplete if blok.id = true and additionalProperties = false (in addition to having a filtered user identity list)', function(done) { - let userIdentityDataPoint = dataPlan.dtpn.vers.version_document.data_points.find(dataPoint => { - return dataPoint.match.type === 'user_identities' - }); + it('integration test - should block identities from being passed to onUserIdentified/onModifyComplete if blok.id = true and additionalProperties = false (in addition to having a filtered user identity list)', function (done) { + const userIdentityDataPoint = + dataPlan.dtpn.vers.version_document.data_points.find( + (dataPoint) => { + return dataPoint.match.type === 'user_identities'; + }, + ); - userIdentityDataPoint.validator.definition.additionalProperties = false; + userIdentityDataPoint.validator.definition.additionalProperties = + false; - let config1 = forwarderDefaultConfiguration('MockForwarder', 1); + const config1 = forwarderDefaultConfiguration( + 'MockForwarder', + 1, + ); (config1.userIdentityFilters = [4]), window.mParticle.config.kitConfigs.push(config1); window.mParticle.init(apiKey, window.mParticle.config); - waitForCondition(hasIdentifyReturned) - .then(() => { - window.mParticle.Identity.modify(userIdentityRequest); - waitForCondition(() => { - return ( - window.mParticle.getInstance()?._Store?.identityCallInFlight === false - ); - }) - .then(() => { - let onUserIdentifiedUserIdentities = window.MockForwarder1.instance.onUserIdentifiedUser - .getUserIdentities() - .userIdentities; - onUserIdentifiedUserIdentities.should.have.property('customerid', 'id1'); - onUserIdentifiedUserIdentities.should.have.property('email', 'email@gmail.com'); - onUserIdentifiedUserIdentities.should.not.have.property('google'); - onUserIdentifiedUserIdentities.should.not.have.property('other', 'id2'); - onUserIdentifiedUserIdentities.should.not.have.property('yahoo'); - - let onModifyCompleteUserIdentities = window.MockForwarder1.instance.onModifyCompleteUser - .getUserIdentities() - .userIdentities; - onModifyCompleteUserIdentities.should.have.property('customerid', 'id1'); - onModifyCompleteUserIdentities.should.have.property('email', 'email@gmail.com'); - onModifyCompleteUserIdentities.should.not.have.property('google'); - onModifyCompleteUserIdentities.should.not.have.property('other', 'id2'); - onModifyCompleteUserIdentities.should.not.have.property('yahoo'); - - userIdentityDataPoint.validator.definition.additionalProperties = true; - - done(); - }); - }); + waitForCondition(hasIdentifyReturned).then(() => { + window.mParticle.Identity.modify(userIdentityRequest); + waitForCondition(() => { + return ( + window.mParticle.getInstance()?._Store + ?.identityCallInFlight === false + ); + }).then(() => { + const onUserIdentifiedUserIdentities = + window.MockForwarder1.instance.onUserIdentifiedUser.getUserIdentities() + .userIdentities; + onUserIdentifiedUserIdentities.should.have.property( + 'customerid', + 'id1', + ); + onUserIdentifiedUserIdentities.should.have.property( + 'email', + 'email@gmail.com', + ); + onUserIdentifiedUserIdentities.should.not.have.property( + 'google', + ); + onUserIdentifiedUserIdentities.should.not.have.property( + 'other', + 'id2', + ); + onUserIdentifiedUserIdentities.should.not.have.property( + 'yahoo', + ); + + const onModifyCompleteUserIdentities = + window.MockForwarder1.instance.onModifyCompleteUser.getUserIdentities() + .userIdentities; + onModifyCompleteUserIdentities.should.have.property( + 'customerid', + 'id1', + ); + onModifyCompleteUserIdentities.should.have.property( + 'email', + 'email@gmail.com', + ); + onModifyCompleteUserIdentities.should.not.have.property( + 'google', + ); + onModifyCompleteUserIdentities.should.not.have.property( + 'other', + 'id2', + ); + onModifyCompleteUserIdentities.should.not.have.property( + 'yahoo', + ); + + userIdentityDataPoint.validator.definition.additionalProperties = + true; + + done(); + }); + }); }); - it('integration test - should not block identities from being passed to onUserIdentified/onIdentifyComplete if blok.id = true and additionalProperties = true (in addition to having a filtered user identity list)', function(done) { - let config1 = forwarderDefaultConfiguration('MockForwarder', 1); + it('integration test - should not block identities from being passed to onUserIdentified/onIdentifyComplete if blok.id = true and additionalProperties = true (in addition to having a filtered user identity list)', function (done) { + const config1 = forwarderDefaultConfiguration( + 'MockForwarder', + 1, + ); (config1.userIdentityFilters = [4]), window.mParticle.config.kitConfigs.push(config1); window.mParticle.config.identifyRequest = userIdentityRequest; window.mParticle.init(apiKey, window.mParticle.config); - waitForCondition(hasIdentifyReturned) - .then(() => { - let onUserIdentifiedUserIdentities = window.MockForwarder1.instance.onUserIdentifiedUser - .getUserIdentities() - .userIdentities; - onUserIdentifiedUserIdentities.should.not.have.property('google'); - onUserIdentifiedUserIdentities.should.have.property('customerid', 'id1'); - onUserIdentifiedUserIdentities.should.have.property('other', 'id2'); - onUserIdentifiedUserIdentities.should.have.property('yahoo', 'yahoo1'); - onUserIdentifiedUserIdentities.should.have.property('email', 'email@gmail.com'); - - let onIdentifyCompleteUserIdentities = window.MockForwarder1.instance.onIdentifyCompleteUser - .getUserIdentities() - .userIdentities; - onIdentifyCompleteUserIdentities.should.not.have.property('google'); - onIdentifyCompleteUserIdentities.should.have.property('customerid', 'id1'); - onIdentifyCompleteUserIdentities.should.have.property('other', 'id2'); - onIdentifyCompleteUserIdentities.should.have.property('yahoo', 'yahoo1'); - onIdentifyCompleteUserIdentities.should.have.property('email', 'email@gmail.com') + waitForCondition(hasIdentifyReturned).then(() => { + const onUserIdentifiedUserIdentities = + window.MockForwarder1.instance.onUserIdentifiedUser.getUserIdentities() + .userIdentities; + onUserIdentifiedUserIdentities.should.not.have.property( + 'google', + ); + onUserIdentifiedUserIdentities.should.have.property( + 'customerid', + 'id1', + ); + onUserIdentifiedUserIdentities.should.have.property( + 'other', + 'id2', + ); + onUserIdentifiedUserIdentities.should.have.property( + 'yahoo', + 'yahoo1', + ); + onUserIdentifiedUserIdentities.should.have.property( + 'email', + 'email@gmail.com', + ); - done(); + const onIdentifyCompleteUserIdentities = + window.MockForwarder1.instance.onIdentifyCompleteUser.getUserIdentities() + .userIdentities; + onIdentifyCompleteUserIdentities.should.not.have.property( + 'google', + ); + onIdentifyCompleteUserIdentities.should.have.property( + 'customerid', + 'id1', + ); + onIdentifyCompleteUserIdentities.should.have.property( + 'other', + 'id2', + ); + onIdentifyCompleteUserIdentities.should.have.property( + 'yahoo', + 'yahoo1', + ); + onIdentifyCompleteUserIdentities.should.have.property( + 'email', + 'email@gmail.com', + ); + + done(); }); }); - it('integration test - should block identities from being passed to onUserIdentified/onIdentifyComplete if blok.id = true and additionalProperties = false (in addition to having a filtered user identity list)', function(done) { - let userIdentityDataPoint = dataPlan.dtpn.vers.version_document.data_points.find(dataPoint => { - return dataPoint.match.type === 'user_identities' - }); + it('integration test - should block identities from being passed to onUserIdentified/onIdentifyComplete if blok.id = true and additionalProperties = false (in addition to having a filtered user identity list)', function (done) { + const userIdentityDataPoint = + dataPlan.dtpn.vers.version_document.data_points.find( + (dataPoint) => { + return dataPoint.match.type === 'user_identities'; + }, + ); - userIdentityDataPoint.validator.definition.additionalProperties = false; + userIdentityDataPoint.validator.definition.additionalProperties = + false; - let config1 = forwarderDefaultConfiguration('MockForwarder', 1); + const config1 = forwarderDefaultConfiguration( + 'MockForwarder', + 1, + ); (config1.userIdentityFilters = [4]), window.mParticle.config.kitConfigs.push(config1); window.mParticle.init(apiKey, window.mParticle.config); - waitForCondition(hasIdentifyReturned) - .then(() => { - - window.mParticle.Identity.identify(userIdentityRequest); - waitForCondition(() => { - return ( - window.mParticle.getInstance()?._Store?.identityCallInFlight === false - ); - }) - .then(() => { - let onUserIdentifiedUserIdentities = window.MockForwarder1.instance.onUserIdentifiedUser - .getUserIdentities() - .userIdentities; - onUserIdentifiedUserIdentities.should.have.property('customerid', 'id1'); - onUserIdentifiedUserIdentities.should.have.property('email', 'email@gmail.com'); - onUserIdentifiedUserIdentities.should.not.have.property('google'); - onUserIdentifiedUserIdentities.should.not.have.property('other', 'id2'); - onUserIdentifiedUserIdentities.should.not.have.property('yahoo'); - - let onIdentifyCompleteUserIdentities = window.MockForwarder1.instance.onIdentifyCompleteUser - .getUserIdentities() - .userIdentities; - onIdentifyCompleteUserIdentities.should.have.property('customerid', 'id1'); - onIdentifyCompleteUserIdentities.should.have.property('email', 'email@gmail.com'); - onIdentifyCompleteUserIdentities.should.not.have.property('google'); - onIdentifyCompleteUserIdentities.should.not.have.property('other', 'id2'); - onIdentifyCompleteUserIdentities.should.not.have.property('yahoo'); - - userIdentityDataPoint.validator.definition.additionalProperties = true; - - done(); - }); - }); + waitForCondition(hasIdentifyReturned).then(() => { + window.mParticle.Identity.identify(userIdentityRequest); + waitForCondition(() => { + return ( + window.mParticle.getInstance()?._Store + ?.identityCallInFlight === false + ); + }).then(() => { + const onUserIdentifiedUserIdentities = + window.MockForwarder1.instance.onUserIdentifiedUser.getUserIdentities() + .userIdentities; + onUserIdentifiedUserIdentities.should.have.property( + 'customerid', + 'id1', + ); + onUserIdentifiedUserIdentities.should.have.property( + 'email', + 'email@gmail.com', + ); + onUserIdentifiedUserIdentities.should.not.have.property( + 'google', + ); + onUserIdentifiedUserIdentities.should.not.have.property( + 'other', + 'id2', + ); + onUserIdentifiedUserIdentities.should.not.have.property( + 'yahoo', + ); + + const onIdentifyCompleteUserIdentities = + window.MockForwarder1.instance.onIdentifyCompleteUser.getUserIdentities() + .userIdentities; + onIdentifyCompleteUserIdentities.should.have.property( + 'customerid', + 'id1', + ); + onIdentifyCompleteUserIdentities.should.have.property( + 'email', + 'email@gmail.com', + ); + onIdentifyCompleteUserIdentities.should.not.have.property( + 'google', + ); + onIdentifyCompleteUserIdentities.should.not.have.property( + 'other', + 'id2', + ); + onIdentifyCompleteUserIdentities.should.not.have.property( + 'yahoo', + ); + + userIdentityDataPoint.validator.definition.additionalProperties = + true; + + done(); + }); + }); }); - it('integration test - should not block identities from being passed to onUserIdentified/onLoginComplete if blok.id = true and additionalProperties = true (in addition to having a filtered user identity list)', function(done) { - let config1 = forwarderDefaultConfiguration('MockForwarder', 1); + it('integration test - should not block identities from being passed to onUserIdentified/onLoginComplete if blok.id = true and additionalProperties = true (in addition to having a filtered user identity list)', function (done) { + const config1 = forwarderDefaultConfiguration( + 'MockForwarder', + 1, + ); (config1.userIdentityFilters = [4]), window.mParticle.config.kitConfigs.push(config1); window.mParticle.init(apiKey, window.mParticle.config); - waitForCondition(hasIdentifyReturned) - .then(() => { - - window.mParticle.Identity.login(userIdentityRequest); - - waitForCondition(() => { - return ( - window.mParticle.getInstance()?._Store?.identityCallInFlight === false - ); - }) - .then(() => { - let onUserIdentifiedUserIdentities = window.MockForwarder1.instance.onUserIdentifiedUser - .getUserIdentities() - .userIdentities; - onUserIdentifiedUserIdentities.should.not.have.property('google'); - onUserIdentifiedUserIdentities.should.have.property('customerid', 'id1'); - onUserIdentifiedUserIdentities.should.have.property('other', 'id2'); - onUserIdentifiedUserIdentities.should.have.property('yahoo', 'yahoo1'); - onUserIdentifiedUserIdentities.should.have.property('email', 'email@gmail.com'); - - let onLoginCompleteUserIdentities = window.MockForwarder1.instance.onLoginCompleteUser - .getUserIdentities() - .userIdentities; - onLoginCompleteUserIdentities.should.not.have.property('google'); - onLoginCompleteUserIdentities.should.have.property('customerid', 'id1'); - onLoginCompleteUserIdentities.should.have.property('other', 'id2'); - onLoginCompleteUserIdentities.should.have.property('yahoo', 'yahoo1'); - onLoginCompleteUserIdentities.should.have.property('email', 'email@gmail.com'); - - done(); - }); - }); + waitForCondition(hasIdentifyReturned).then(() => { + window.mParticle.Identity.login(userIdentityRequest); + + waitForCondition(() => { + return ( + window.mParticle.getInstance()?._Store + ?.identityCallInFlight === false + ); + }).then(() => { + const onUserIdentifiedUserIdentities = + window.MockForwarder1.instance.onUserIdentifiedUser.getUserIdentities() + .userIdentities; + onUserIdentifiedUserIdentities.should.not.have.property( + 'google', + ); + onUserIdentifiedUserIdentities.should.have.property( + 'customerid', + 'id1', + ); + onUserIdentifiedUserIdentities.should.have.property( + 'other', + 'id2', + ); + onUserIdentifiedUserIdentities.should.have.property( + 'yahoo', + 'yahoo1', + ); + onUserIdentifiedUserIdentities.should.have.property( + 'email', + 'email@gmail.com', + ); + + const onLoginCompleteUserIdentities = + window.MockForwarder1.instance.onLoginCompleteUser.getUserIdentities() + .userIdentities; + onLoginCompleteUserIdentities.should.not.have.property( + 'google', + ); + onLoginCompleteUserIdentities.should.have.property( + 'customerid', + 'id1', + ); + onLoginCompleteUserIdentities.should.have.property( + 'other', + 'id2', + ); + onLoginCompleteUserIdentities.should.have.property( + 'yahoo', + 'yahoo1', + ); + onLoginCompleteUserIdentities.should.have.property( + 'email', + 'email@gmail.com', + ); + + done(); + }); + }); }); - it('integration test - should block identities from being passed to onUserIdentified/onLoginComplete if blok.id = true and additionalProperties = false (in addition to having a filtered user identity list)', function(done) { - let userIdentityDataPoint = dataPlan.dtpn.vers.version_document.data_points.find(dataPoint => { - return dataPoint.match.type === 'user_identities' - }); + it('integration test - should block identities from being passed to onUserIdentified/onLoginComplete if blok.id = true and additionalProperties = false (in addition to having a filtered user identity list)', function (done) { + const userIdentityDataPoint = + dataPlan.dtpn.vers.version_document.data_points.find( + (dataPoint) => { + return dataPoint.match.type === 'user_identities'; + }, + ); - userIdentityDataPoint.validator.definition.additionalProperties = false; + userIdentityDataPoint.validator.definition.additionalProperties = + false; - let mockForwarder = new MockForwarder(); + const mockForwarder = new MockForwarder(); window.mParticle.addForwarder(mockForwarder); - let config1 = forwarderDefaultConfiguration('MockForwarder', 1); + const config1 = forwarderDefaultConfiguration( + 'MockForwarder', + 1, + ); (config1.userIdentityFilters = [4]), window.mParticle.config.kitConfigs.push(config1); window.mParticle.init(apiKey, window.mParticle.config); - waitForCondition(hasIdentifyReturned) - .then(() => { - window.mParticle.Identity.login(userIdentityRequest); - waitForCondition(() => { - return ( - window.mParticle.getInstance()?._Store?.identityCallInFlight === false - ); - }) - .then(() => { - let onUserIdentifiedUserIdentities = window.MockForwarder1.instance.onUserIdentifiedUser - .getUserIdentities() - .userIdentities; - onUserIdentifiedUserIdentities.should.have.property('customerid', 'id1'); - onUserIdentifiedUserIdentities.should.have.property('email', 'email@gmail.com'); - onUserIdentifiedUserIdentities.should.not.have.property('google'); - onUserIdentifiedUserIdentities.should.not.have.property('other', 'id2'); - onUserIdentifiedUserIdentities.should.not.have.property('yahoo'); - - let onLoginCompleteUserIdentities = window.MockForwarder1.instance.onLoginCompleteUser - .getUserIdentities() - .userIdentities; - onLoginCompleteUserIdentities.should.have.property('customerid', 'id1'); - onLoginCompleteUserIdentities.should.have.property('email', 'email@gmail.com'); - onLoginCompleteUserIdentities.should.not.have.property('google'); - onLoginCompleteUserIdentities.should.not.have.property('other', 'id2'); - onLoginCompleteUserIdentities.should.not.have.property('yahoo'); - - userIdentityDataPoint.validator.definition.additionalProperties = true; - - done(); - }); + waitForCondition(hasIdentifyReturned).then(() => { + window.mParticle.Identity.login(userIdentityRequest); + waitForCondition(() => { + return ( + window.mParticle.getInstance()?._Store + ?.identityCallInFlight === false + ); + }).then(() => { + const onUserIdentifiedUserIdentities = + window.MockForwarder1.instance.onUserIdentifiedUser.getUserIdentities() + .userIdentities; + onUserIdentifiedUserIdentities.should.have.property( + 'customerid', + 'id1', + ); + onUserIdentifiedUserIdentities.should.have.property( + 'email', + 'email@gmail.com', + ); + onUserIdentifiedUserIdentities.should.not.have.property( + 'google', + ); + onUserIdentifiedUserIdentities.should.not.have.property( + 'other', + 'id2', + ); + onUserIdentifiedUserIdentities.should.not.have.property( + 'yahoo', + ); + + const onLoginCompleteUserIdentities = + window.MockForwarder1.instance.onLoginCompleteUser.getUserIdentities() + .userIdentities; + onLoginCompleteUserIdentities.should.have.property( + 'customerid', + 'id1', + ); + onLoginCompleteUserIdentities.should.have.property( + 'email', + 'email@gmail.com', + ); + onLoginCompleteUserIdentities.should.not.have.property( + 'google', + ); + onLoginCompleteUserIdentities.should.not.have.property( + 'other', + 'id2', + ); + onLoginCompleteUserIdentities.should.not.have.property( + 'yahoo', + ); + + userIdentityDataPoint.validator.definition.additionalProperties = + true; + + done(); + }); }); }); }); describe('integration tests - product attribute related', () => { - let prodattr1, prodattr2, product1, product2, transactionAttributes, customAttributes, customFlags; + let prodattr1, + prodattr2, + product1, + product2, + transactionAttributes, + customAttributes, + customFlags; beforeEach(() => { - let mockForwarder = new MockForwarder(); + const mockForwarder = new MockForwarder(); window.mParticle.addForwarder(mockForwarder); - window.mParticle.config.kitConfigs.push(forwarderDefaultConfiguration('MockForwarder')); + window.mParticle.config.kitConfigs.push( + forwarderDefaultConfiguration('MockForwarder'), + ); window.mParticle.init(apiKey, window.mParticle.config); prodattr1 = { - 'plannedAttr1': 'val1', - 'plannedAttr2': 'val2', - 'unplannedAttr1': 'val3' + plannedAttr1: 'val1', + plannedAttr2: 'val2', + unplannedAttr1: 'val3', }; prodattr2 = { - 'plannedAttr1': 'val1', - 'plannedAttr2': 'val2', - 'unplannedAttr1': 'val3' + plannedAttr1: 'val1', + plannedAttr2: 'val2', + unplannedAttr1: 'val3', }; - - product1 = window.mParticle.eCommerce.createProduct('iphone', 'iphoneSKU', 999, 1, 'variant', 'category', 'brand', 1, 'coupon', prodattr1); - product2 = window.mParticle.eCommerce.createProduct('galaxy', 'galaxySKU', 799, 1, 'variant', 'category', 'brand', 1, 'coupon', prodattr2); - + + product1 = window.mParticle.eCommerce.createProduct( + 'iphone', + 'iphoneSKU', + 999, + 1, + 'variant', + 'category', + 'brand', + 1, + 'coupon', + prodattr1, + ); + product2 = window.mParticle.eCommerce.createProduct( + 'galaxy', + 'galaxySKU', + 799, + 1, + 'variant', + 'category', + 'brand', + 1, + 'coupon', + prodattr2, + ); + transactionAttributes = { Id: 'foo-transaction-id', - Revenue: 430.00, - Tax: 30 + Revenue: 430.0, + Tax: 30, }; - customAttributes = {sale: true}; - customFlags = {'Google.Category': 'travel'}; - }) - - it('integration test - should block any unplanned product attributes from reaching the forwarder if additionalProperties = false and block.ea=true', function(done) { - waitForCondition(hasIdentifyReturned) - .then(() => { - window.mParticle.eCommerce.logProductAction( - window.mParticle.ProductActionType['Purchase'], - [product1, product2], - customAttributes, - customFlags, - transactionAttributes); - - - let event = window.MockForwarder1.instance.receivedEvent; - let products = event.ProductAction.ProductList; - - products[0].Attributes.should.have.property('plannedAttr1', 'val1') - products[0].Attributes.should.have.property('plannedAttr2', 'val2') - products[0].Attributes.should.not.have.property('unplannedAttr1') - - products[1].Attributes.should.have.property('plannedAttr1', 'val1') - products[1].Attributes.should.have.property('plannedAttr2', 'val2') - products[1].Attributes.should.not.have.property('unplannedAttr1') - - done(); + customAttributes = { sale: true }; + customFlags = { 'Google.Category': 'travel' }; + }); + + it('integration test - should block any unplanned product attributes from reaching the forwarder if additionalProperties = false and block.ea=true', function (done) { + waitForCondition(hasIdentifyReturned).then(() => { + window.mParticle.eCommerce.logProductAction( + window.mParticle.ProductActionType['Purchase'], + [product1, product2], + customAttributes, + customFlags, + transactionAttributes, + ); + + const event = window.MockForwarder1.instance.receivedEvent; + const products = event.ProductAction.ProductList; + + products[0].Attributes.should.have.property( + 'plannedAttr1', + 'val1', + ); + products[0].Attributes.should.have.property( + 'plannedAttr2', + 'val2', + ); + products[0].Attributes.should.not.have.property( + 'unplannedAttr1', + ); + + products[1].Attributes.should.have.property( + 'plannedAttr1', + 'val1', + ); + products[1].Attributes.should.have.property( + 'plannedAttr2', + 'val2', + ); + products[1].Attributes.should.not.have.property( + 'unplannedAttr1', + ); + + done(); }); }); - it('integration test - should not block unplanned product attributes from reaching the forwarder if additionalProperties = true and block.ea=true', function(done) { - waitForCondition(hasIdentifyReturned) - .then(() => { - window.mParticle.eCommerce.logProductAction( - window.mParticle.ProductActionType['AddToCart'], - [product1, product2], - customAttributes, - customFlags, - transactionAttributes); - - let event = window.MockForwarder1.instance.receivedEvent; - let products = event.ProductAction.ProductList; - - products[0].Attributes.should.have.property('plannedAttr1', 'val1') - products[0].Attributes.should.have.property('plannedAttr2', 'val2') - products[0].Attributes.should.have.property('unplannedAttr1') - - products[1].Attributes.should.have.property('plannedAttr1', 'val1') - products[1].Attributes.should.have.property('plannedAttr2', 'val2') - products[1].Attributes.should.have.property('unplannedAttr1') - - done(); - }) + it('integration test - should not block unplanned product attributes from reaching the forwarder if additionalProperties = true and block.ea=true', function (done) { + waitForCondition(hasIdentifyReturned).then(() => { + window.mParticle.eCommerce.logProductAction( + window.mParticle.ProductActionType['AddToCart'], + [product1, product2], + customAttributes, + customFlags, + transactionAttributes, + ); + + const event = window.MockForwarder1.instance.receivedEvent; + const products = event.ProductAction.ProductList; + + products[0].Attributes.should.have.property( + 'plannedAttr1', + 'val1', + ); + products[0].Attributes.should.have.property( + 'plannedAttr2', + 'val2', + ); + products[0].Attributes.should.have.property( + 'unplannedAttr1', + ); + + products[1].Attributes.should.have.property( + 'plannedAttr1', + 'val1', + ); + products[1].Attributes.should.have.property( + 'plannedAttr2', + 'val2', + ); + products[1].Attributes.should.have.property( + 'unplannedAttr1', + ); + + done(); + }); }); - }) + }); describe('integration tests - client passed in data plan', () => { - let clientProvidedDataPlan: DataPlanVersion = { + const clientProvidedDataPlan: DataPlanVersion = { version_document: { data_points: [ { @@ -1251,8 +1897,8 @@ describe('kit blocking', () => { type: 'custom_event', criteria: { event_name: 'locationEvent123', - custom_event_type: 'location' - } + custom_event_type: 'location', + }, }, validator: { // @ts-ignore (fix this after DataPlanMatchType importing works) @@ -1266,104 +1912,121 @@ describe('kit blocking', () => { properties: { foo: {}, 'foo foo': {}, - 'foo number': {} - } - } - } - } - } - } - } - } - ] - } + 'foo number': {}, + }, + }, + }, + }, + }, + }, + }, + }, + ], + }, }; - it('integration test - should log an error if the client passes a data plan without the proper keys', function(done) { + it('integration test - should log an error if the client passes a data plan without the proper keys', function (done) { // @ts-ignore - purposely leaving out blockUserIdentities as a key below - window.mParticle.config.dataPlanOptions = { + window.mParticle.config.dataPlanOptions = { dataPlanVersion: clientProvidedDataPlan, blockUserAttributes: true, blockEventAttributes: true, blockEvents: true, }; - let errorMessages = []; + const errorMessages = []; window.mParticle._resetForTests(MPConfig); window.mParticle.config.logLevel = 'verbose'; window.mParticle.config.logger = { - error: function(err) { - errorMessages.push(err) - } - } + error: function (err) { + errorMessages.push(err); + }, + }; window.mParticle.init(apiKey, window.mParticle.config); - waitForCondition(hasIdentifyReturned) - .then(() => { - errorMessages[0].should.equal('Ensure your config.dataPlanOptions object has the following keys: a "dataPlanVersion" object, and "blockUserAttributes", "blockEventAttributes", "blockEvents", "blockUserIdentities" booleans'); + waitForCondition(hasIdentifyReturned).then(() => { + errorMessages[0].should.equal( + 'Ensure your config.dataPlanOptions object has the following keys: a "dataPlanVersion" object, and "blockUserAttributes", "blockEventAttributes", "blockEvents", "blockUserIdentities" booleans', + ); - done(); + done(); }); }); - it('integration test - should prioritize data plan from config.dataPlanOptions over server provided data plan', function(done) { + it('integration test - should prioritize data plan from config.dataPlanOptions over server provided data plan', function (done) { window.mParticle._resetForTests(MPConfig); - let mockForwarder = new MockForwarder(); + const mockForwarder = new MockForwarder(); window.mParticle.addForwarder(mockForwarder); - window.mParticle.config.kitConfigs.push(forwarderDefaultConfiguration('MockForwarder')); + window.mParticle.config.kitConfigs.push( + forwarderDefaultConfiguration('MockForwarder'), + ); window.mParticle.config.dataPlanOptions = { dataPlanVersion: clientProvidedDataPlan, blockUserAttributes: true, blockEventAttributes: true, blockEvents: true, - blockUserIdentities: true + blockUserIdentities: true, }; - let logs = []; + const logs = []; window.mParticle.config.logLevel = 'verbose'; window.mParticle.config.logger = { - verbose: function(msg) { - logs.push(msg) - } - } + verbose: function (msg) { + logs.push(msg); + }, + }; window.mParticle.init(apiKey, window.mParticle.config); - waitForCondition(hasIdentifyReturned) - .then(() => { - logs.includes('Customer provided data plan found').should.equal(true); - logs.includes('Data plan found from mParticle.js').should.equal(false); - logs.includes('Data plan found from /config').should.equal(false); + waitForCondition(hasIdentifyReturned).then(() => { + logs.includes( + 'Customer provided data plan found', + ).should.equal(true); + logs.includes( + 'Data plan found from mParticle.js', + ).should.equal(false); + logs.includes('Data plan found from /config').should.equal( + false, + ); - // this event is part of the server provided data plan (dataPlan.json) which is being ignored, so the event doesn't go through; - window.mParticle.logEvent('something something something', Types.EventType.Navigation); + // this event is part of the server provided data plan (dataPlan.json) which is being ignored, so the event doesn't go through; + window.mParticle.logEvent( + 'something something something', + Types.EventType.Navigation, + ); - let event = window.MockForwarder1.instance.receivedEvent; - (event === null).should.equal(true); + let event = window.MockForwarder1.instance.receivedEvent; + (event === null).should.equal(true); - // this event is part of the clientGeneratedDataPlan - window.mParticle.logEvent('locationEvent123', Types.EventType.Location, { - unplannedAttr: 'test', - foo: 'hi' - }); + // this event is part of the clientGeneratedDataPlan + window.mParticle.logEvent( + 'locationEvent123', + Types.EventType.Location, + { + unplannedAttr: 'test', + foo: 'hi', + }, + ); - event = window.MockForwarder1.instance.receivedEvent; + event = window.MockForwarder1.instance.receivedEvent; - event.should.have.property('EventName', 'locationEvent123'); - event.EventAttributes.should.have.property('foo', 'hi'); - event.EventAttributes.should.not.have.property('unplannedAttr'); + event.should.have.property('EventName', 'locationEvent123'); + event.EventAttributes.should.have.property('foo', 'hi'); + event.EventAttributes.should.not.have.property( + 'unplannedAttr', + ); - done(); + done(); }); }); - it('integration test - should block or unblock planned events', function(done) { + it('integration test - should block or unblock planned events', function (done) { window.mParticle._resetForTests(MPConfig); - let mockForwarder = new MockForwarder(); + const mockForwarder = new MockForwarder(); window.mParticle.addForwarder(mockForwarder); delete window.mParticle.config.dataPlan; @@ -1372,84 +2035,100 @@ describe('kit blocking', () => { blockUserAttributes: true, blockEventAttributes: true, blockEvents: true, - blockUserIdentities: true - } + blockUserIdentities: true, + }; - window.mParticle.config.kitConfigs.push(forwarderDefaultConfiguration('MockForwarder')); + window.mParticle.config.kitConfigs.push( + forwarderDefaultConfiguration('MockForwarder'), + ); window.mParticle.init(apiKey, window.mParticle.config); - waitForCondition(hasIdentifyReturned) - .then(() => { + waitForCondition(hasIdentifyReturned).then(() => { + window.mParticle.logEvent('Blocked event'); - window.mParticle.logEvent('Blocked event'); + let event = window.MockForwarder1.instance.receivedEvent; + (event === null).should.equal(true); - let event = window.MockForwarder1.instance.receivedEvent; - (event === null).should.equal(true); - - window.mParticle.logEvent('locationEvent123', Types.EventType.Location, { - unplannedAttr: 'test', - foo: 'hi' - }); + window.mParticle.logEvent( + 'locationEvent123', + Types.EventType.Location, + { + unplannedAttr: 'test', + foo: 'hi', + }, + ); - event = window.MockForwarder1.instance.receivedEvent; + event = window.MockForwarder1.instance.receivedEvent; - event.should.have.property('EventName', 'locationEvent123'); - event.EventAttributes.should.have.property('foo', 'hi'); - event.EventAttributes.should.not.have.property('unplannedAttr'); + event.should.have.property('EventName', 'locationEvent123'); + event.EventAttributes.should.have.property('foo', 'hi'); + event.EventAttributes.should.not.have.property( + 'unplannedAttr', + ); - done(); - }); + done(); + }); }); }); describe('integration tests - self hosting set up', () => { - afterEach(function() { + afterEach(function () { fetchMock.restore(); }); it('should create a proper kitblocker on a self hosted set up', async () => { - fetchMock.get(`${urls.config}&plan_id=robs_plan&plan_version=1`, { - status: 200, - body: JSON.stringify({ dataPlanResult: dataPlan }), - }); + fetchMock.get( + `${urls.config}&plan_id=robs_plan&plan_version=1`, + { + status: 200, + body: JSON.stringify({ dataPlanResult: dataPlan }), + }, + ); window.mParticle._resetForTests(MPConfig); - let mockForwarder = new MockForwarder(); + const mockForwarder = new MockForwarder(); window.mParticle.addForwarder(mockForwarder); //requestConfig = true indicates self hosted window.mParticle.config.requestConfig = true; window.mParticle.config.logLevel = 'verbose'; window.mParticle.config.dataPlan = { planId: 'robs_plan', - planVersion: 1 - } + planVersion: 1, + }; - window.mParticle.config.kitConfigs.push(forwarderDefaultConfiguration('MockForwarder')); + window.mParticle.config.kitConfigs.push( + forwarderDefaultConfiguration('MockForwarder'), + ); window.mParticle.init(apiKey, window.mParticle.config); - + window.mParticle.logEvent('Blocked event'); await waitForCondition(hasIdentifyReturned); - let event = window.MockForwarder1.instance.receivedEvent; + const event = window.MockForwarder1.instance.receivedEvent; (event === null).should.equal(true); - + window.mParticle.config.requestConfig = false; }); it('should log an error if the data plan has an error on it', async () => { const errorMessage = 'This is an error'; - fetchMock.get(`${urls.config}&plan_id=robs_plan&plan_version=1`, { - status: 200, - body: JSON.stringify({ dataPlanResult: {error_message: errorMessage} }), - }); + fetchMock.get( + `${urls.config}&plan_id=robs_plan&plan_version=1`, + { + status: 200, + body: JSON.stringify({ + dataPlanResult: { error_message: errorMessage }, + }), + }, + ); - let errorMessages = []; + const errorMessages = []; window.mParticle._resetForTests(MPConfig); - let mockForwarder = new MockForwarder(); + const mockForwarder = new MockForwarder(); window.mParticle.addForwarder(mockForwarder); //requestConfig = true indicates self hosted @@ -1457,23 +2136,25 @@ describe('kit blocking', () => { window.mParticle.config.logLevel = 'verbose'; window.mParticle.config.dataPlan = { planId: 'robs_plan', - planVersion: 1 - } + planVersion: 1, + }; - window.mParticle.config.kitConfigs.push(forwarderDefaultConfiguration('MockForwarder')); + window.mParticle.config.kitConfigs.push( + forwarderDefaultConfiguration('MockForwarder'), + ); window.mParticle.config.logLevel = 'verbose'; window.mParticle.config.logger = { - error: function(err) { - errorMessages.push(err) - } - } + error: function (err) { + errorMessages.push(err); + }, + }; window.mParticle.init(apiKey, window.mParticle.config); - await waitForCondition(hasIdentifyReturned) + await waitForCondition(hasIdentifyReturned); errorMessages[0].should.equal(errorMessage); window.mParticle.config.requestConfig = false; }); - }) + }); }); -}); \ No newline at end of file +}); diff --git a/test/src/tests-legacy-alias-requests.ts b/test/src/tests-legacy-alias-requests.ts index 208edac10..c727b5363 100644 --- a/test/src/tests-legacy-alias-requests.ts +++ b/test/src/tests-legacy-alias-requests.ts @@ -1,7 +1,11 @@ import sinon from 'sinon'; import { expect } from 'chai'; import Utils from './config/utils'; -import Constants, { HTTP_ACCEPTED, HTTP_BAD_REQUEST, HTTP_OK } from '../../src/constants'; +import Constants, { + HTTP_ACCEPTED, + HTTP_BAD_REQUEST, + HTTP_OK, +} from '../../src/constants'; import { urls, apiKey, @@ -12,12 +16,8 @@ import { import { IAliasRequest } from '../../src/identity.interfaces'; import { IMParticleInstanceManager } from '../../src/sdkRuntimeModels'; -const { - setCookie, - findRequestURL, - waitForCondition, - hasIdentifyReturned -} = Utils; +const { setCookie, findRequestURL, waitForCondition, hasIdentifyReturned } = + Utils; const { HTTPCodes } = Constants; @@ -26,16 +26,16 @@ declare global { mParticle: IMParticleInstanceManager; fetchMock: any; } -} +} const mParticle = window.mParticle as IMParticleInstanceManager; -describe('legacy Alias Requests', function() { +describe('legacy Alias Requests', function () { let mockServer; let clock; const originalFetch = window.fetch; - beforeEach(function() { + beforeEach(function () { delete window.fetch; delete mParticle.config.useCookieStorage; mockServer = sinon.createFakeServer(); @@ -61,7 +61,7 @@ describe('legacy Alias Requests', function() { mParticle.init(apiKey, window.mParticle.config); }); - afterEach(function() { + afterEach(function () { mockServer.restore(); // fetchMock.restore(); mParticle._resetForTests(MPConfig); @@ -69,7 +69,7 @@ describe('legacy Alias Requests', function() { window.fetch = originalFetch; }); - it('Alias request should be received when API is called validly', function(done) { + it('Alias request should be received when API is called validly', function (done) { mockServer.requests = []; mockServer.respondWith(urls.alias, [HTTP_OK, {}, JSON.stringify({})]); @@ -92,7 +92,7 @@ describe('legacy Alias Requests', function() { expect(requestBody['request_type']).to.equal('alias'); expect(requestBody['environment']).to.equal('production'); expect(requestBody['api_key']).to.equal( - mParticle.getInstance()._Store.devToken + mParticle.getInstance()._Store.devToken, ); const dataBody = requestBody['data']; expect(dataBody).to.not.equal(null); @@ -104,7 +104,7 @@ describe('legacy Alias Requests', function() { done(); }); - it('Alias request should include scope if specified', function(done) { + it('Alias request should include scope if specified', function (done) { mockServer.requests = []; mockServer.respondWith(urls.alias, [HTTP_OK, {}, JSON.stringify({})]); @@ -129,12 +129,12 @@ describe('legacy Alias Requests', function() { done(); }); - it('should reject malformed Alias Requests', function(done) { + it('should reject malformed Alias Requests', function (done) { mParticle.config.logLevel = 'verbose'; let warnMessage = null; mParticle.config.logger = { - warning: function(msg) { + warning: function (msg) { warnMessage = msg; }, }; @@ -142,41 +142,41 @@ describe('legacy Alias Requests', function() { let callbackResult; // intentionally missing sourceMpid - let aliasRequest: IAliasRequest = ({ + let aliasRequest: IAliasRequest = { destinationMpid: 'destinationMpid', startTime: 3, endTime: 4, - } as unknown) as IAliasRequest; + } as unknown as IAliasRequest; - mParticle.Identity.aliasUsers(aliasRequest, function(callback) { + mParticle.Identity.aliasUsers(aliasRequest, function (callback) { callbackResult = callback; }); callbackResult.httpCode.should.equal(HTTPCodes.validationIssue); expect(callbackResult.message).to.equal( - Constants.Messages.ValidationMessages.AliasMissingMpid + Constants.Messages.ValidationMessages.AliasMissingMpid, ); expect(warnMessage).to.equal( - Constants.Messages.ValidationMessages.AliasMissingMpid + Constants.Messages.ValidationMessages.AliasMissingMpid, ); callbackResult = null; warnMessage = null; // intentionally missing destinationMpid - aliasRequest = ({ + aliasRequest = { sourceMpid: 'sourceMpid', startTime: 3, endTime: 4, - } as unknown) as IAliasRequest; + } as unknown as IAliasRequest; - mParticle.Identity.aliasUsers(aliasRequest, function(callback) { + mParticle.Identity.aliasUsers(aliasRequest, function (callback) { callbackResult = callback; }); callbackResult.httpCode.should.equal(HTTPCodes.validationIssue); expect(callbackResult.message).to.equal( - Constants.Messages.ValidationMessages.AliasMissingMpid + Constants.Messages.ValidationMessages.AliasMissingMpid, ); expect(warnMessage).to.equal( - Constants.Messages.ValidationMessages.AliasMissingMpid + Constants.Messages.ValidationMessages.AliasMissingMpid, ); callbackResult = null; warnMessage = null; @@ -188,16 +188,16 @@ describe('legacy Alias Requests', function() { startTime: 3, endTime: 4, }; - mParticle.Identity.aliasUsers(aliasRequest, function(callback) { + mParticle.Identity.aliasUsers(aliasRequest, function (callback) { callbackResult = callback; }); callbackResult.httpCode.should.equal(HTTPCodes.validationIssue); expect(callbackResult.message).to.equal( - Constants.Messages.ValidationMessages.AliasNonUniqueMpid + Constants.Messages.ValidationMessages.AliasNonUniqueMpid, ); expect(warnMessage).to.equal( - Constants.Messages.ValidationMessages.AliasNonUniqueMpid + Constants.Messages.ValidationMessages.AliasNonUniqueMpid, ); callbackResult = null; warnMessage = null; @@ -209,34 +209,34 @@ describe('legacy Alias Requests', function() { startTime: 4, endTime: 3, }; - mParticle.Identity.aliasUsers(aliasRequest, function(callback) { + mParticle.Identity.aliasUsers(aliasRequest, function (callback) { callbackResult = callback; }); callbackResult.httpCode.should.equal(HTTPCodes.validationIssue); expect(callbackResult.message).to.equal( - Constants.Messages.ValidationMessages.AliasStartBeforeEndTime + Constants.Messages.ValidationMessages.AliasStartBeforeEndTime, ); expect(warnMessage).to.equal( - Constants.Messages.ValidationMessages.AliasStartBeforeEndTime + Constants.Messages.ValidationMessages.AliasStartBeforeEndTime, ); callbackResult = null; warnMessage = null; // intentionally missing endTime and startTime - aliasRequest = ({ + aliasRequest = { destinationMpid: 'destinationMpid', sourceMpid: 'sourceMpid', - } as unknown) as IAliasRequest; + } as unknown as IAliasRequest; - mParticle.Identity.aliasUsers(aliasRequest, function(callback) { + mParticle.Identity.aliasUsers(aliasRequest, function (callback) { callbackResult = callback; }); callbackResult.httpCode.should.equal(HTTPCodes.validationIssue); expect(callbackResult.message).to.equal( - Constants.Messages.ValidationMessages.AliasMissingTime + Constants.Messages.ValidationMessages.AliasMissingTime, ); expect(warnMessage).to.equal( - Constants.Messages.ValidationMessages.AliasMissingTime + Constants.Messages.ValidationMessages.AliasMissingTime, ); callbackResult = null; warnMessage = null; @@ -249,9 +249,13 @@ describe('legacy Alias Requests', function() { endTime: 4, }; - mockServer.respondWith(urls.alias, [HTTP_ACCEPTED, {}, JSON.stringify({})]); + mockServer.respondWith(urls.alias, [ + HTTP_ACCEPTED, + {}, + JSON.stringify({}), + ]); - mParticle.Identity.aliasUsers(aliasRequest, function(callback) { + mParticle.Identity.aliasUsers(aliasRequest, function (callback) { callbackResult = callback; callbackResult.httpCode.should.equal(HTTP_ACCEPTED); expect(callbackResult.message).to.equal(undefined); @@ -259,10 +263,9 @@ describe('legacy Alias Requests', function() { callbackResult = null; done(); }); - }); - it('should parse error info from Alias Requests', function(done) { + it('should parse error info from Alias Requests', function (done) { clock.restore(); mParticle.init(apiKey, window.mParticle.config); const errorMessage = 'this is a sample error message'; @@ -283,17 +286,17 @@ describe('legacy Alias Requests', function() { startTime: 3, endTime: 4, }; - - mParticle.Identity.aliasUsers(aliasRequest, function(callback) { + + mParticle.Identity.aliasUsers(aliasRequest, function (callback) { callbackResult = callback; callbackResult.httpCode.should.equal(HTTP_BAD_REQUEST); callbackResult.message.should.equal(errorMessage); - + done(); }); }); - it('should properly create AliasRequest', function(done) { + it('should properly create AliasRequest', function (done) { mParticle._resetForTests(MPConfig); const cookies = JSON.stringify({ @@ -322,7 +325,7 @@ describe('legacy Alias Requests', function() { const aliasRequest = mParticle.Identity.createAliasRequest( sourceUser, - destinationUser + destinationUser, ); expect(aliasRequest.sourceMpid).to.equal('1'); expect(aliasRequest.destinationMpid).to.equal('2'); @@ -333,7 +336,7 @@ describe('legacy Alias Requests', function() { done(); }); - it('should fill in missing fst and lst in createAliasRequest', function(done) { + it('should fill in missing fst and lst in createAliasRequest', function (done) { mParticle._resetForTests(MPConfig); const cookies = JSON.stringify({ @@ -363,7 +366,7 @@ describe('legacy Alias Requests', function() { const aliasRequest = mParticle.Identity.createAliasRequest( sourceUser, - destinationUser + destinationUser, ); expect(aliasRequest.sourceMpid).to.equal('2'); expect(aliasRequest.destinationMpid).to.equal('3'); @@ -377,7 +380,7 @@ describe('legacy Alias Requests', function() { done(); }); - it('should fix startTime when default is outside max window create AliasRequest', function(done) { + it('should fix startTime when default is outside max window create AliasRequest', function (done) { mParticle._resetForTests(MPConfig); const millisPerDay = 24 * 60 * 60 * 1000; @@ -406,7 +409,7 @@ describe('legacy Alias Requests', function() { const aliasRequest = mParticle.Identity.createAliasRequest( sourceUser, - destinationUser + destinationUser, ); expect(aliasRequest.sourceMpid).to.equal('1'); expect(aliasRequest.destinationMpid).to.equal('2'); @@ -421,14 +424,14 @@ describe('legacy Alias Requests', function() { done(); }); - it('should warn if legal aliasRequest cannot be created with MParticleUser', function(done) { + it('should warn if legal aliasRequest cannot be created with MParticleUser', function (done) { const millisPerDay = 24 * 60 * 60 * 1000; mParticle.config.logLevel = 'verbose'; let warnMessage = null; mParticle.config.logger = { - warning: function(msg) { + warning: function (msg) { warnMessage = msg; }, }; @@ -458,7 +461,7 @@ describe('legacy Alias Requests', function() { const aliasRequest = mParticle.Identity.createAliasRequest( sourceUser, - destinationUser + destinationUser, ); expect(aliasRequest.sourceMpid).to.equal('1'); expect(aliasRequest.destinationMpid).to.equal('2'); @@ -471,23 +474,27 @@ describe('legacy Alias Requests', function() { expect(warnMessage).to.equal( 'Source User has not been seen in the last ' + mParticle.getInstance()._Store.SDKConfig.maxAliasWindow + - ' days, Alias Request will likely fail' + ' days, Alias Request will likely fail', ); clock.restore(); done(); }); - it("alias request should have environment 'development' when isDevelopmentMode is true", function(done) { + it("alias request should have environment 'development' when isDevelopmentMode is true", function (done) { mParticle._resetForTests(MPConfig); window.mParticle.config.isDevelopmentMode = true; - mockServer.respondWith(urls.alias, [HTTP_ACCEPTED, {}, JSON.stringify({})]); + mockServer.respondWith(urls.alias, [ + HTTP_ACCEPTED, + {}, + JSON.stringify({}), + ]); mParticle.init(apiKey, window.mParticle.config); mockServer.requests = []; - + const aliasRequest = { destinationMpid: 'destinationMpid', sourceMpid: 'sourceMpid', @@ -500,63 +507,87 @@ describe('legacy Alias Requests', function() { const request = mockServer.requests[0]; const requestBody = JSON.parse(request.requestBody); - expect(requestBody['environment']).to.equal('development');expect(requestBody.environment).to.equal('development'); - done() + expect(requestBody['environment']).to.equal('development'); + expect(requestBody.environment).to.equal('development'); + done(); }); - it('should have default urls if no custom urls are set in config object, but use custom urls when they are set', function(done) { + it('should have default urls if no custom urls are set in config object, but use custom urls when they are set', function (done) { window.mParticle.config.v3SecureServiceUrl = 'testtesttest-custom-v3secureserviceurl/v3/JS/'; - window.mParticle.config.configUrl = - 'foo-custom-configUrl/v2/JS/'; + window.mParticle.config.configUrl = 'foo-custom-configUrl/v2/JS/'; window.mParticle.config.identityUrl = 'custom-identityUrl/'; window.mParticle.config.aliasUrl = 'custom-aliasUrl/'; - mockServer.respondWith('https://testtesttest-custom-v3secureserviceurl/v3/JS/test_key/events', HTTP_OK, JSON.stringify({ mpid: testMPID, Store: {}})); - - mParticle.init(apiKey, window.mParticle.config); - waitForCondition(hasIdentifyReturned) - .then(() => { - - mParticle.getInstance()._Store.SDKConfig.v3SecureServiceUrl.should.equal(window.mParticle.config.v3SecureServiceUrl) - mParticle.getInstance()._Store.SDKConfig.configUrl.should.equal(window.mParticle.config.configUrl) - mParticle.getInstance()._Store.SDKConfig.identityUrl.should.equal(window.mParticle.config.identityUrl) - mParticle.getInstance()._Store.SDKConfig.aliasUrl.should.equal(window.mParticle.config.aliasUrl) - - mockServer.requests = []; - // test events endpoint - mParticle.logEvent('Test Event'); - - const testEventURL = findRequestURL(mockServer.requests, 'Test Event'); - testEventURL.should.equal( - 'https://' + - window.mParticle.config.v3SecureServiceUrl + - 'test_key/events' - ); - - // test Identity endpoint - mockServer.requests = []; - mParticle.Identity.login({ userIdentities: { customerid: 'test1' } }); - mockServer.requests[0].url.should.equal( - 'https://' + window.mParticle.config.identityUrl + 'login' + mockServer.respondWith( + 'https://testtesttest-custom-v3secureserviceurl/v3/JS/test_key/events', + HTTP_OK, + JSON.stringify({ mpid: testMPID, Store: {} }), ); - // test alias endpoint - mockServer.requests = []; - - mParticle.Identity.aliasUsers({ - destinationMpid: '1', - sourceMpid: '2', - startTime: 3, - endTime: 4, + mParticle.init(apiKey, window.mParticle.config); + waitForCondition(hasIdentifyReturned).then(() => { + mParticle + .getInstance() + ._Store.SDKConfig.v3SecureServiceUrl.should.equal( + window.mParticle.config.v3SecureServiceUrl, + ); + mParticle + .getInstance() + ._Store.SDKConfig.configUrl.should.equal( + window.mParticle.config.configUrl, + ); + mParticle + .getInstance() + ._Store.SDKConfig.identityUrl.should.equal( + window.mParticle.config.identityUrl, + ); + mParticle + .getInstance() + ._Store.SDKConfig.aliasUrl.should.equal( + window.mParticle.config.aliasUrl, + ); + + mockServer.requests = []; + // test events endpoint + mParticle.logEvent('Test Event'); + + const testEventURL = findRequestURL( + mockServer.requests, + 'Test Event', + ); + testEventURL.should.equal( + 'https://' + + window.mParticle.config.v3SecureServiceUrl + + 'test_key/events', + ); + + // test Identity endpoint + mockServer.requests = []; + mParticle.Identity.login({ + userIdentities: { customerid: 'test1' }, + }); + mockServer.requests[0].url.should.equal( + 'https://' + window.mParticle.config.identityUrl + 'login', + ); + + // test alias endpoint + mockServer.requests = []; + + mParticle.Identity.aliasUsers({ + destinationMpid: '1', + sourceMpid: '2', + startTime: 3, + endTime: 4, + }); + + mockServer.requests[0].url.should.equal( + 'https://' + + window.mParticle.config.aliasUrl + + 'test_key/Alias', + ); }); - mockServer.requests[0].url.should.equal( - 'https://' + window.mParticle.config.aliasUrl + 'test_key/Alias' - ); - }) - done(); }); - -}); \ No newline at end of file +}); diff --git a/test/src/tests-mParticleUser.js b/test/src/tests-mParticleUser.js index fc65cb242..9a2894d53 100644 --- a/test/src/tests-mParticleUser.js +++ b/test/src/tests-mParticleUser.js @@ -12,29 +12,34 @@ const forwarderDefaultConfiguration = Utils.forwarderDefaultConfiguration, MockForwarder = Utils.MockForwarder; // https://go.mparticle.com/work/SQDSDKS-6508 -describe('mParticleUser', function() { - beforeEach(function() { +describe('mParticleUser', function () { + beforeEach(function () { fetchMockSuccess(urls.identify, { - mpid: 'identifyMPID', is_logged_in: false + mpid: 'identifyMPID', + is_logged_in: false, }); fetchMockSuccess(urls.login, { - mpid: 'loginMPID', is_logged_in: true + mpid: 'loginMPID', + is_logged_in: true, }); fetchMockSuccess(urls.logout, { - mpid: 'logoutMPID', is_logged_in: false + mpid: 'logoutMPID', + is_logged_in: false, }); - fetchMockSuccess('https://jssdks.mparticle.com/v1/JS/test_key/Forwarding'); + fetchMockSuccess( + 'https://jssdks.mparticle.com/v1/JS/test_key/Forwarding', + ); fetchMock.post(urls.events, 200); }); - afterEach(function() { + afterEach(function () { fetchMock.restore(); }); - it('should call forwarder onUserIdentified method with a filtered user identity list', function(done) { + it('should call forwarder onUserIdentified method with a filtered user identity list', function (done) { mParticle._resetForTests(MPConfig); const mockForwarder = new MockForwarder(); @@ -45,214 +50,211 @@ describe('mParticleUser', function() { window.mParticle.config.kitConfigs.push(config1); mParticle.init(apiKey, window.mParticle.config); - waitForCondition(hasIdentifyReturned) - .then(() => { - const userIdentityRequest = { - userIdentities: { - google: 'test', - customerid: 'id1', - other: 'id2', - }, - }; - mParticle.Identity.login(userIdentityRequest); - waitForCondition(() => { - return ( - mParticle.Identity.getCurrentUser()?.getMPID() === - 'loginMPID' - ); - }) - .then(() => { - window.MockForwarder1.instance.onUserIdentifiedUser - .getUserIdentities() - .userIdentities.should.not.have.property('google'); - window.MockForwarder1.instance.onUserIdentifiedUser - .getUserIdentities() - .userIdentities.should.have.property('customerid', 'id1'); - window.MockForwarder1.instance.onUserIdentifiedUser - .getUserIdentities() - .userIdentities.should.have.property('other', 'id2'); - done(); - }) - }) + waitForCondition(hasIdentifyReturned).then(() => { + const userIdentityRequest = { + userIdentities: { + google: 'test', + customerid: 'id1', + other: 'id2', + }, + }; + mParticle.Identity.login(userIdentityRequest); + waitForCondition(() => { + return ( + mParticle.Identity.getCurrentUser()?.getMPID() === + 'loginMPID' + ); + }).then(() => { + window.MockForwarder1.instance.onUserIdentifiedUser + .getUserIdentities() + .userIdentities.should.not.have.property('google'); + window.MockForwarder1.instance.onUserIdentifiedUser + .getUserIdentities() + .userIdentities.should.have.property('customerid', 'id1'); + window.MockForwarder1.instance.onUserIdentifiedUser + .getUserIdentities() + .userIdentities.should.have.property('other', 'id2'); + done(); + }); + }); }); - it('should call forwarder onUserIdentified method with a filtered user attributes list', function(done) { + it('should call forwarder onUserIdentified method with a filtered user attributes list', function (done) { mParticle._resetForTests(MPConfig); const mockForwarder = new MockForwarder(); mockForwarder.register(window.mParticle.config); const config1 = forwarderDefaultConfiguration('MockForwarder', 1); - config1.userAttributeFilters = [ - mParticle.generateHash('gender'), - ]; + config1.userAttributeFilters = [mParticle.generateHash('gender')]; window.mParticle.config.kitConfigs.push(config1); mParticle.init(apiKey, window.mParticle.config); - waitForCondition(hasIdentifyReturned) - .then(() => { - const userIdentityRequest = { - userIdentities: { - google: 'test', - customerid: 'id1', - other: 'id2', - }, - }; - - mParticle.Identity.login(userIdentityRequest); - waitForCondition(() => { - return ( - mParticle.Identity.getCurrentUser()?.getMPID() === - 'loginMPID' + waitForCondition(hasIdentifyReturned).then(() => { + const userIdentityRequest = { + userIdentities: { + google: 'test', + customerid: 'id1', + other: 'id2', + }, + }; + + mParticle.Identity.login(userIdentityRequest); + waitForCondition(() => { + return ( + mParticle.Identity.getCurrentUser()?.getMPID() === + 'loginMPID' + ); + }).then(() => {}); + mParticle.Identity.getCurrentUser().setUserAttribute( + 'gender', + 'male', ); - }) - .then(() => {}); - mParticle.Identity.getCurrentUser().setUserAttribute('gender', 'male'); - mParticle.Identity.getCurrentUser().setUserAttribute('color', 'blue'); - mParticle.Identity.login(userIdentityRequest); - window.MockForwarder1.instance.onUserIdentifiedUser - .getAllUserAttributes() - .should.not.have.property('gender'); - window.MockForwarder1.instance.onUserIdentifiedUser - .getAllUserAttributes() - .should.have.property('color', 'blue'); - - done(); - }); + mParticle.Identity.getCurrentUser().setUserAttribute( + 'color', + 'blue', + ); + mParticle.Identity.login(userIdentityRequest); + window.MockForwarder1.instance.onUserIdentifiedUser + .getAllUserAttributes() + .should.not.have.property('gender'); + window.MockForwarder1.instance.onUserIdentifiedUser + .getAllUserAttributes() + .should.have.property('color', 'blue'); + + done(); + }); }); - it('should call forwarder onIdentifyComplete', function(done) { + it('should call forwarder onIdentifyComplete', function (done) { mParticle._resetForTests(MPConfig); const mockForwarder = new MockForwarder(); mockForwarder.register(window.mParticle.config); const config1 = forwarderDefaultConfiguration('MockForwarder', 1); - (config1.userAttributeFilters = [ - mParticle.generateHash('gender'), - ]), - window.mParticle.config.kitConfigs.push(config1); + (config1.userAttributeFilters = [mParticle.generateHash('gender')]), + window.mParticle.config.kitConfigs.push(config1); mParticle.init(apiKey, window.mParticle.config); - waitForCondition(hasIdentifyReturned) - .then(() => { - window.MockForwarder1.instance.onIdentifyCompleteCalled.should.equal(true); - done(); - }) + waitForCondition(hasIdentifyReturned).then(() => { + window.MockForwarder1.instance.onIdentifyCompleteCalled.should.equal( + true, + ); + done(); + }); }); - it('should call forwarder onLoginComplete', function(done) { + it('should call forwarder onLoginComplete', function (done) { mParticle._resetForTests(MPConfig); const mockForwarder = new MockForwarder(); mockForwarder.register(window.mParticle.config); const config1 = forwarderDefaultConfiguration('MockForwarder', 1); - (config1.userAttributeFilters = [ - mParticle.generateHash('gender'), - ]), + (config1.userAttributeFilters = [mParticle.generateHash('gender')]), window.mParticle.config.kitConfigs.push(config1); mParticle.init(apiKey, window.mParticle.config); - waitForCondition(hasIdentifyReturned) - .then(() => { - const userIdentityRequest = { - userIdentities: { - google: 'test', - customerid: 'id1', - other: 'id2', - }, - }; - - mParticle.Identity.login(userIdentityRequest); - waitForCondition(() => { - return ( - mParticle.Identity.getCurrentUser()?.getMPID() === - 'loginMPID' - ); - }) - .then(() => { - window.MockForwarder1.instance.onLoginCompleteCalled.should.equal(true); - done(); + waitForCondition(hasIdentifyReturned).then(() => { + const userIdentityRequest = { + userIdentities: { + google: 'test', + customerid: 'id1', + other: 'id2', + }, + }; + + mParticle.Identity.login(userIdentityRequest); + waitForCondition(() => { + return ( + mParticle.Identity.getCurrentUser()?.getMPID() === + 'loginMPID' + ); + }).then(() => { + window.MockForwarder1.instance.onLoginCompleteCalled.should.equal( + true, + ); + done(); + }); }); - }) }); - it('should call forwarder onLogoutComplete', function(done) { + it('should call forwarder onLogoutComplete', function (done) { mParticle._resetForTests(MPConfig); const mockForwarder = new MockForwarder(); mockForwarder.register(window.mParticle.config); const config1 = forwarderDefaultConfiguration('MockForwarder', 1); - (config1.userAttributeFilters = [ - mParticle.generateHash('gender'), - ]), + (config1.userAttributeFilters = [mParticle.generateHash('gender')]), window.mParticle.config.kitConfigs.push(config1); mParticle.init(apiKey, window.mParticle.config); - waitForCondition(hasIdentifyReturned) - .then(() => { - const userIdentityRequest = { - userIdentities: { - google: 'test', - customerid: 'id1', - other: 'id2', - }, - }; - - mParticle.Identity.logout(userIdentityRequest); - waitForCondition(() => { - return ( - mParticle.Identity.getCurrentUser()?.getMPID() === - 'logoutMPID' - ); - }) - .then(() => { - window.MockForwarder1.instance.onLogoutCompleteCalled.should.equal(true); - done(); - }); - }) + waitForCondition(hasIdentifyReturned).then(() => { + const userIdentityRequest = { + userIdentities: { + google: 'test', + customerid: 'id1', + other: 'id2', + }, + }; + + mParticle.Identity.logout(userIdentityRequest); + waitForCondition(() => { + return ( + mParticle.Identity.getCurrentUser()?.getMPID() === + 'logoutMPID' + ); + }).then(() => { + window.MockForwarder1.instance.onLogoutCompleteCalled.should.equal( + true, + ); + done(); + }); + }); }); - it('should call forwarder onModifyComplete method with the proper identity method passed through', function(done) { + it('should call forwarder onModifyComplete method with the proper identity method passed through', function (done) { mParticle._resetForTests(MPConfig); const mockForwarder = new MockForwarder(); mockForwarder.register(window.mParticle.config); const config1 = forwarderDefaultConfiguration('MockForwarder', 1); - (config1.userAttributeFilters = [ - mParticle.generateHash('gender'), - ]), - window.mParticle.config.kitConfigs.push(config1); + (config1.userAttributeFilters = [mParticle.generateHash('gender')]), + window.mParticle.config.kitConfigs.push(config1); mParticle.init(apiKey, window.mParticle.config); - waitForCondition(hasIdentifyReturned) - .then(() => { - const userIdentityRequest = { - userIdentities: { - google: 'test', - customerid: 'id1', - other: 'id2', - }, - }; - - fetchMockSuccess('https://identity.mparticle.com/v1/identifyMPID/modify', { - mpid: 'modifyMPID', is_logged_in: false - }); - - mParticle.Identity.modify(userIdentityRequest); - waitForCondition(() => { - return ( - mParticle.Identity.getCurrentUser()?.getMPID() === - 'modifyMPID' + waitForCondition(hasIdentifyReturned).then(() => { + const userIdentityRequest = { + userIdentities: { + google: 'test', + customerid: 'id1', + other: 'id2', + }, + }; + + fetchMockSuccess( + 'https://identity.mparticle.com/v1/identifyMPID/modify', + { + mpid: 'modifyMPID', + is_logged_in: false, + }, ); - }) - .then(() => { - window.MockForwarder1.instance.onModifyCompleteCalled.should.equal(true); - done(); - }); - }) + + mParticle.Identity.modify(userIdentityRequest); + waitForCondition(() => { + return ( + mParticle.Identity.getCurrentUser()?.getMPID() === + 'modifyMPID' + ); + }).then(() => { + window.MockForwarder1.instance.onModifyCompleteCalled.should.equal( + true, + ); + done(); + }); + }); }); -}); \ No newline at end of file +}); diff --git a/test/src/tests-mockBatchCreator.ts b/test/src/tests-mockBatchCreator.ts index e91154603..54374d03e 100644 --- a/test/src/tests-mockBatchCreator.ts +++ b/test/src/tests-mockBatchCreator.ts @@ -6,18 +6,18 @@ describe('Create a batch from a base event', () => { const batchValidator = new _BatchValidator(); const baseEvent: BaseEvent = { messageType: 4, - name: 'testEvent' - } - - it('creates a batch with base event ', done => { + name: 'testEvent', + }; + + it('creates a batch with base event ', (done) => { let batch = batchValidator.returnBatch(baseEvent); expect(batch).to.have.property('environment').equal('production'); expect(batch).to.have.property('source_request_id').equal('mockId'); expect(batch).to.have.property('mpid').equal('0'); - expect(batch).to.have.property('timestamp_unixtime_ms') + expect(batch).to.have.property('timestamp_unixtime_ms'); expect(batch).to.have.property('mp_deviceid'); - expect(batch).to.have.property('sdk_version') + expect(batch).to.have.property('sdk_version'); expect(batch).to.have.property('application_info'); expect(batch).to.have.property('device_info'); expect(batch).to.have.property('user_attributes'); @@ -28,31 +28,49 @@ describe('Create a batch from a base event', () => { expect(batch.events[0]).to.have.property('event_type', 'custom_event'); expect(batch.events[0]).to.have.property('data'); - expect(batch.events[0].data).to.have.property('custom_event_type', 'unknown'); + expect(batch.events[0].data).to.have.property( + 'custom_event_type', + 'unknown', + ); expect(batch.events[0].data).to.have.property('custom_flags'); - expect(batch.events[0].data).to.have.property('event_name', 'testEvent'); + expect(batch.events[0].data).to.have.property( + 'event_name', + 'testEvent', + ); expect(batch.events[0].data).to.have.property('timestamp_unixtime_ms'); - expect(batch.events[0].data).to.have.property('session_uuid', 'mockSessionId'); - expect(batch.events[0].data).to.have.property('session_start_unixtime_ms'); + expect(batch.events[0].data).to.have.property( + 'session_uuid', + 'mockSessionId', + ); + expect(batch.events[0].data).to.have.property( + 'session_start_unixtime_ms', + ); expect(batch.events[0].data).to.have.property('custom_attributes'); expect(batch.events[0].data).to.have.property('location'); - baseEvent.eventType = 1; batch = batchValidator.returnBatch(baseEvent); - expect(batch.events[0].data).to.have.property('custom_event_type', 'navigation'); - + expect(batch.events[0].data).to.have.property( + 'custom_event_type', + 'navigation', + ); baseEvent.data = { attrFoo: 'attrBar' }; batch = batchValidator.returnBatch(baseEvent); expect(batch.events[0].data).to.have.property('custom_attributes'); - expect(batch.events[0].data.custom_attributes).to.have.property('attrFoo', 'attrBar'); - - baseEvent.customFlags = { flagFoo: 'flagBar' } + expect(batch.events[0].data.custom_attributes).to.have.property( + 'attrFoo', + 'attrBar', + ); + + baseEvent.customFlags = { flagFoo: 'flagBar' }; batch = batchValidator.returnBatch(baseEvent); expect(batch.events[0].data).to.have.property('custom_flags'); - expect(batch.events[0].data.custom_flags).to.have.property('flagFoo', 'flagBar'); + expect(batch.events[0].data.custom_flags).to.have.property( + 'flagFoo', + 'flagBar', + ); done(); }); -}); \ No newline at end of file +}); diff --git a/test/src/tests-mparticle-instance-manager.ts b/test/src/tests-mparticle-instance-manager.ts index 977c2a393..ecf63023f 100644 --- a/test/src/tests-mparticle-instance-manager.ts +++ b/test/src/tests-mparticle-instance-manager.ts @@ -4,11 +4,11 @@ import { expect } from 'chai'; import { urls, MPConfig } from './config/constants'; import Utils from './config/utils'; import { IMParticleInstanceManager } from '../../src/sdkRuntimeModels'; -const { +const { findEventFromRequest, waitForCondition, fetchMockSuccess, - hasConfigurationReturned + hasConfigurationReturned, } = Utils; declare global { @@ -17,11 +17,11 @@ declare global { } } -const mParticle = window.mParticle as IMParticleInstanceManager;; +const mParticle = window.mParticle as IMParticleInstanceManager; let mockServer; function returnEventForMPInstance(calls, apiKey, eventName) { - const requestsPerApiKey = calls.filter(function(call) { + const requestsPerApiKey = calls.filter(function (call) { return call[0].includes(apiKey); }); return findEventFromRequest(requestsPerApiKey, eventName); @@ -44,7 +44,7 @@ describe('mParticle instance manager', () => { 'RemoveFromWishlist', 'getName', 'getExpansionName', - ] + ], ); expect(mParticle.CommerceEventType, 'Commerce Event Type').to.have.keys( [ @@ -61,7 +61,7 @@ describe('mParticle instance manager', () => { 'ProductAddToWishlist', 'ProductRemoveFromWishlist', 'ProductImpression', - ] + ], ); expect(mParticle.EventType, 'Event Type').to.have.keys([ 'Unknown', @@ -239,7 +239,7 @@ describe('mParticle instance manager', () => { { status: 200, body: JSON.stringify({ workspaceToken: 'wtTest1' }), - } + }, ); //config instance 2 @@ -248,7 +248,7 @@ describe('mParticle instance manager', () => { { status: 200, body: JSON.stringify({ workspaceToken: 'wtTest2' }), - } + }, ); //config instance 3 @@ -257,21 +257,21 @@ describe('mParticle instance manager', () => { { status: 200, body: JSON.stringify({ workspaceToken: 'wtTest3' }), - } + }, ); // default instance event mock fetchMock.post( 'https://jssdks.mparticle.com/v3/JS/apiKey1/events', - 200 + 200, ); fetchMock.post( 'https://jssdks.mparticle.com/v3/JS/apiKey2/events', - 200 + 200, ); fetchMock.post( 'https://jssdks.mparticle.com/v3/JS/apiKey3/events', - 200 + 200, ); // identity mock @@ -288,21 +288,31 @@ describe('mParticle instance manager', () => { mParticle.init('apiKey3', window.mParticle.config, 'instance3'); }); - afterEach(function() { + afterEach(function () { mockServer.restore(); fetchMock.restore(); }); it('uses the correct instance name to identify an instance', async () => { - await waitForCondition(() => ( - mParticle.getInstance('default_instance')._Store.configurationLoaded === true && - mParticle.getInstance('instance2')._Store.configurationLoaded === true && - mParticle.getInstance('instance3')._Store.configurationLoaded === true - )); - - expect(mParticle.getInstance('default_instance')._instanceName).to.equal('default_instance'); - expect(mParticle.getInstance('instance2')._instanceName).to.equal('instance2'); - expect(mParticle.getInstance('instance3')._instanceName).to.equal('instance3'); + await waitForCondition( + () => + mParticle.getInstance('default_instance')._Store + .configurationLoaded === true && + mParticle.getInstance('instance2')._Store + .configurationLoaded === true && + mParticle.getInstance('instance3')._Store + .configurationLoaded === true, + ); + + expect( + mParticle.getInstance('default_instance')._instanceName, + ).to.equal('default_instance'); + expect(mParticle.getInstance('instance2')._instanceName).to.equal( + 'instance2', + ); + expect(mParticle.getInstance('instance3')._instanceName).to.equal( + 'instance3', + ); }); it('creates multiple instances with their own cookies', async () => { @@ -326,36 +336,36 @@ describe('mParticle instance manager', () => { mParticle.getInstance('instance3')._Store .configurationLoaded === true ); - }) + }); mParticle.getInstance('default_instance').logEvent('hi1'); mParticle.getInstance('instance2').logEvent('hi2'); mParticle.getInstance('instance3').logEvent('hi3'); - + const instance1Event = returnEventForMPInstance( fetchMock.calls(), 'apiKey1', - 'hi1' + 'hi1', ); expect(instance1Event).to.be.ok; const instance2Event = returnEventForMPInstance( fetchMock.calls(), 'apiKey2', - 'hi2' + 'hi2', ); expect(instance2Event).to.be.ok; const instance3Event = returnEventForMPInstance( fetchMock.calls(), 'apiKey3', - 'hi3' + 'hi3', ); expect(instance3Event).to.be.ok; const instance1EventsFail1 = returnEventForMPInstance( fetchMock.calls(), 'apiKey1', - 'hi2' + 'hi2', ); expect(instance1EventsFail1).to.not.be.ok; @@ -363,35 +373,35 @@ describe('mParticle instance manager', () => { const instance1EventsFail2 = returnEventForMPInstance( fetchMock.calls(), 'apiKey1', - 'hi3' + 'hi3', ); expect(instance1EventsFail2).to.not.be.ok; const instance2EventsFail1 = returnEventForMPInstance( fetchMock.calls(), 'apiKey2', - 'hi1' + 'hi1', ); expect(instance2EventsFail1).to.not.be.ok; const instance2EventsFail2 = returnEventForMPInstance( fetchMock.calls(), 'apiKey2', - 'hi3' + 'hi3', ); expect(instance2EventsFail2).to.not.be.ok; const instance3EventsFail1 = returnEventForMPInstance( fetchMock.calls(), 'apiKey3', - 'hi1' + 'hi1', ); expect(instance3EventsFail1).to.not.be.ok; const instance3EventsFail2 = returnEventForMPInstance( fetchMock.calls(), 'apiKey3', - 'hi2' + 'hi2', ); expect(instance3EventsFail2).to.not.be.ok; }); @@ -416,7 +426,7 @@ describe('mParticle instance manager', () => { 'brand', 1, 'coupon', - prodattr1 + prodattr1, ); const product2 = mParticle.eCommerce.createProduct( 'galaxy', @@ -428,7 +438,7 @@ describe('mParticle instance manager', () => { 'brand', 1, 'coupon', - prodattr2 + prodattr2, ); const ta = mParticle.eCommerce.createTransactionAttributes( @@ -437,29 +447,29 @@ describe('mParticle instance manager', () => { 'coupon', 1798, 10, - 5 + 5, ); mParticle - .getInstance() - .eCommerce.logPurchase(ta, [product1, product2]); + .getInstance() + .eCommerce.logPurchase(ta, [product1, product2]); await waitForCondition(hasConfigurationReturned); const instance1Event = returnEventForMPInstance( fetchMock.calls(), 'apiKey1', - 'purchase' + 'purchase', ); let instance2Event = returnEventForMPInstance( fetchMock.calls(), 'apiKey2', - 'purchase' + 'purchase', ); let instance3Event = returnEventForMPInstance( fetchMock.calls(), 'apiKey3', - 'purchase' + 'purchase', ); instance1Event.should.be.ok(); expect(instance2Event).to.not.be.ok; @@ -472,12 +482,12 @@ describe('mParticle instance manager', () => { instance2Event = returnEventForMPInstance( fetchMock.calls(), 'apiKey2', - 'purchase' + 'purchase', ); instance3Event = returnEventForMPInstance( fetchMock.calls(), 'apiKey3', - 'purchase' + 'purchase', ); expect(instance2Event).to.be.ok; @@ -490,7 +500,7 @@ describe('mParticle instance manager', () => { instance3Event = returnEventForMPInstance( fetchMock.calls(), 'apiKey3', - 'purchase' + 'purchase', ); expect(instance3Event).to.be.ok; diff --git a/test/src/tests-native-sdk.js b/test/src/tests-native-sdk.js index 8b98c87fa..23e727a22 100644 --- a/test/src/tests-native-sdk.js +++ b/test/src/tests-native-sdk.js @@ -7,9 +7,9 @@ const getLocalStorage = Utils.getLocalStorage, mParticleAndroid = Utils.mParticleAndroid, HTTPCodes = Constants.HTTPCodes; -describe('native-sdk methods', function() { - describe('Helper methods', function() { - beforeEach(function() { +describe('native-sdk methods', function () { + describe('Helper methods', function () { + beforeEach(function () { mParticle._resetForTests(MPConfig); delete window.mParticleAndroid_bridgeName_v2; delete window.webkit; @@ -24,7 +24,7 @@ describe('native-sdk methods', function() { window.mParticle.isIOS = null; }); - after(function() { + after(function () { delete window.mParticleAndroid_bridgeName_v2; delete window.webkit; delete window.mParticle.uiwebviewBridgeName; @@ -33,7 +33,7 @@ describe('native-sdk methods', function() { delete mParticle.isIOS; }); - it('isBridgeV2Available returns false if no bridges exist on window', function(done) { + it('isBridgeV2Available returns false if no bridges exist on window', function (done) { mParticle .getInstance() ._NativeSdkHelpers.isBridgeV2Available('bridgeName') @@ -42,7 +42,7 @@ describe('native-sdk methods', function() { done(); }); - it('isBridgeV2Available returns true if iOS bridge messageHandler bridge exists on window', function(done) { + it('isBridgeV2Available returns true if iOS bridge messageHandler bridge exists on window', function (done) { mParticle .getInstance() ._NativeSdkHelpers.isBridgeV2Available('bridgeName') @@ -62,7 +62,7 @@ describe('native-sdk methods', function() { done(); }); - it('isBridgeV2Available returns true if iOS bridge nonMessageHandler bridge exists on window', function(done) { + it('isBridgeV2Available returns true if iOS bridge nonMessageHandler bridge exists on window', function (done) { mParticle .getInstance() ._NativeSdkHelpers.isBridgeV2Available('bridgeName') @@ -78,7 +78,7 @@ describe('native-sdk methods', function() { done(); }); - it('isBridgeV2Available returns true if Android bridge exists on window', function(done) { + it('isBridgeV2Available returns true if Android bridge exists on window', function (done) { mParticle .getInstance() ._NativeSdkHelpers.isBridgeV2Available('bridgeName') @@ -93,7 +93,7 @@ describe('native-sdk methods', function() { done(); }); - it('isWebviewEnabled returns true if there is no v2Bridge, and minWebviewBridgeVersion is 1, and v1 bridge is available', function(done) { + it('isWebviewEnabled returns true if there is no v2Bridge, and minWebviewBridgeVersion is 1, and v1 bridge is available', function (done) { mParticle._resetForTests(MPConfig); window.mParticle.config.minWebviewBridgeVersion = 1; mParticle.config.isIOS = true; @@ -103,14 +103,14 @@ describe('native-sdk methods', function() { .getInstance() ._NativeSdkHelpers.isWebviewEnabled( 'bridgeName', - window.mParticle.config.minWebviewBridgeVersion + window.mParticle.config.minWebviewBridgeVersion, ) .should.equal(true); done(); }); - it('isWebviewEnabled returns true if there is an Android bridge, minWebviewBridgeVersion is 2', function(done) { + it('isWebviewEnabled returns true if there is an Android bridge, minWebviewBridgeVersion is 2', function (done) { mParticle._resetForTests(MPConfig); window.mParticle.config.minWebviewBridgeVersion = 2; mParticle.init(apiKey, window.mParticle.config); @@ -122,14 +122,14 @@ describe('native-sdk methods', function() { .getInstance() ._NativeSdkHelpers.isWebviewEnabled( 'bridgeName', - window.mParticle.config.minWebviewBridgeVersion + window.mParticle.config.minWebviewBridgeVersion, ) .should.equal(true); done(); }); - it('isWebviewEnabled returns true if there is an iOS bridge, minWebviewBridgeVersion is 2', function(done) { + it('isWebviewEnabled returns true if there is an iOS bridge, minWebviewBridgeVersion is 2', function (done) { mParticle._resetForTests(MPConfig); window.mParticle.config.minWebviewBridgeVersion = 2; window.webkit = { @@ -143,14 +143,14 @@ describe('native-sdk methods', function() { .getInstance() ._NativeSdkHelpers.isWebviewEnabled( 'bridgeName', - window.mParticle.config.minWebviewBridgeVersion + window.mParticle.config.minWebviewBridgeVersion, ) .should.equal(true); done(); }); - it('isWebviewEnabled returns true if there is an iOS nonMessageHandler bridge and minWebviewBridgeVersion is 2', function(done) { + it('isWebviewEnabled returns true if there is an iOS nonMessageHandler bridge and minWebviewBridgeVersion is 2', function (done) { mParticle.minWebviewBridgeVersion = 2; window.mParticle.uiwebviewBridgeName = 'mParticle_bridgeName_v2'; @@ -158,14 +158,14 @@ describe('native-sdk methods', function() { .getInstance() ._NativeSdkHelpers.isWebviewEnabled( 'bridgeName', - mParticle.minWebviewBridgeVersion + mParticle.minWebviewBridgeVersion, ) .should.equal(true); done(); }); - it('isWebviewEnabled returns true if there is an iOS nonMessageHandler bridge and minWebviewBridgeVersion is 2', function(done) { + it('isWebviewEnabled returns true if there is an iOS nonMessageHandler bridge and minWebviewBridgeVersion is 2', function (done) { mParticle.minWebviewBridgeVersion = 2; window.mParticle.uiwebviewBridgeName = 'mParticle_bridgeName_v2'; @@ -173,14 +173,14 @@ describe('native-sdk methods', function() { .getInstance() ._NativeSdkHelpers.isWebviewEnabled( 'bridgeName', - mParticle.minWebviewBridgeVersion + mParticle.minWebviewBridgeVersion, ) .should.equal(true); done(); }); - it('isWebviewEnabled returns false if there is a v1 Android bridge, and minWebviewBridgeVersion is 2', function(done) { + it('isWebviewEnabled returns false if there is a v1 Android bridge, and minWebviewBridgeVersion is 2', function (done) { mParticle._resetForTests(MPConfig); window.mParticle.config.minWebviewBridgeVersion = 2; mParticle.init(apiKey, window.mParticle.config); @@ -190,14 +190,14 @@ describe('native-sdk methods', function() { .getInstance() ._NativeSdkHelpers.isWebviewEnabled( 'bridgeName', - window.mParticle.config.minWebviewBridgeVersion + window.mParticle.config.minWebviewBridgeVersion, ) .should.equal(false); done(); }); - it('isWebviewEnabled returns false if there is a v1 iOS bridge, and minWebviewBridgeVersion is 2', function(done) { + it('isWebviewEnabled returns false if there is a v1 iOS bridge, and minWebviewBridgeVersion is 2', function (done) { mParticle._resetForTests(MPConfig); window.mParticle.config.minWebviewBridgeVersion = 2; mParticle.init(apiKey, window.mParticle.config); @@ -207,7 +207,7 @@ describe('native-sdk methods', function() { .getInstance() ._NativeSdkHelpers.isWebviewEnabled( 'bridgeName', - window.mParticle.config.minWebviewBridgeVersion + window.mParticle.config.minWebviewBridgeVersion, ) .should.equal(false); @@ -216,7 +216,7 @@ describe('native-sdk methods', function() { done(); }); - it('isWebviewEnabled returns true if there is a v2 Android bridge, and minWebviewBridgeVersion is 1, and no v1 Android bridge exists', function(done) { + it('isWebviewEnabled returns true if there is a v2 Android bridge, and minWebviewBridgeVersion is 1, and no v1 Android bridge exists', function (done) { mParticle.minWebviewBridgeVersion = 1; window.mParticleAndroid_bridgeName_v2 = new mParticleAndroid(); @@ -224,14 +224,14 @@ describe('native-sdk methods', function() { .getInstance() ._NativeSdkHelpers.isWebviewEnabled( 'bridgeName', - mParticle.minWebviewBridgeVersion + mParticle.minWebviewBridgeVersion, ) .should.equal(true); done(); }); - it('isWebviewEnabled returns true if there is a v2 iOS messageHandler bridge, and minWebviewBridgeVersion is 1, and no v1 ios bridge exists', function(done) { + it('isWebviewEnabled returns true if there is a v2 iOS messageHandler bridge, and minWebviewBridgeVersion is 1, and no v1 ios bridge exists', function (done) { mParticle.minWebviewBridgeVersion = 1; window.webkit = { messageHandlers: { @@ -243,14 +243,14 @@ describe('native-sdk methods', function() { .getInstance() ._NativeSdkHelpers.isWebviewEnabled( 'bridgeName', - mParticle.minWebviewBridgeVersion + mParticle.minWebviewBridgeVersion, ) .should.equal(true); done(); }); - it('isWebviewEnabled returns true if there is a v2 iOS nonMessageHandler bridge, and minWebviewBridgeVersion is 1, and no v1 ios bridge exists', function(done) { + it('isWebviewEnabled returns true if there is a v2 iOS nonMessageHandler bridge, and minWebviewBridgeVersion is 1, and no v1 ios bridge exists', function (done) { mParticle.minWebviewBridgeVersion = 1; window.mParticle.uiwebviewBridgeName = 'mParticle_bridgeName_v2'; @@ -258,7 +258,7 @@ describe('native-sdk methods', function() { .getInstance() ._NativeSdkHelpers.isWebviewEnabled( 'bridgeName', - mParticle.minWebviewBridgeVersion + mParticle.minWebviewBridgeVersion, ) .should.equal(true); @@ -267,7 +267,7 @@ describe('native-sdk methods', function() { done(); }); - it('isWebviewEnabled returns true if there is a v2 Android bridge, and minWebviewBridgeVersion is 1, and no v1 Android bridge exists', function(done) { + it('isWebviewEnabled returns true if there is a v2 Android bridge, and minWebviewBridgeVersion is 1, and no v1 Android bridge exists', function (done) { mParticle.minWebviewBridgeVersion = 1; window.mParticleAndroid_bridgeName_v2 = new mParticleAndroid(); @@ -275,14 +275,14 @@ describe('native-sdk methods', function() { .getInstance() ._NativeSdkHelpers.isWebviewEnabled( 'bridgeName', - mParticle.minWebviewBridgeVersion + mParticle.minWebviewBridgeVersion, ) .should.equal(true); done(); }); - it('isWebviewEnabled returns true if there is a v2 iOS messageHandler bridge, and minWebviewBridgeVersion is 1, and no v1 ios bridge exists', function(done) { + it('isWebviewEnabled returns true if there is a v2 iOS messageHandler bridge, and minWebviewBridgeVersion is 1, and no v1 ios bridge exists', function (done) { mParticle.minWebviewBridgeVersion = 1; window.webkit = { messageHandlers: { @@ -294,14 +294,14 @@ describe('native-sdk methods', function() { .getInstance() ._NativeSdkHelpers.isWebviewEnabled( 'bridgeName', - mParticle.minWebviewBridgeVersion + mParticle.minWebviewBridgeVersion, ) .should.equal(true); done(); }); - it('isWebviewEnabled returns true if there is a v2 iOS nonMessageHandler bridge, and minWebviewBridgeVersion is 1, and no v1 ios bridge exists', function(done) { + it('isWebviewEnabled returns true if there is a v2 iOS nonMessageHandler bridge, and minWebviewBridgeVersion is 1, and no v1 ios bridge exists', function (done) { mParticle.minWebviewBridgeVersion = 1; window.mParticle.uiwebviewBridgeName = 'mParticle_bridgeName_v2'; @@ -309,14 +309,14 @@ describe('native-sdk methods', function() { .getInstance() ._NativeSdkHelpers.isWebviewEnabled( 'bridgeName', - mParticle.minWebviewBridgeVersion + mParticle.minWebviewBridgeVersion, ) .should.equal(true); done(); }); - it('isWebviewEnabled returns false if there is an unmatched requiredWebviewBridgeName, even if bridge 1 exists and min version is 1', function(done) { + it('isWebviewEnabled returns false if there is an unmatched requiredWebviewBridgeName, even if bridge 1 exists and min version is 1', function (done) { mParticle.minWebviewBridgeVersion = 1; mParticle.requiredWebviewBridgeName = 'nonmatching'; window.mParticle.uiwebviewBridgeName = 'mParticle_bridgeName_v2'; @@ -325,7 +325,7 @@ describe('native-sdk methods', function() { .getInstance() ._NativeSdkHelpers.isWebviewEnabled( mParticle.requiredWebviewBridgeName, - mParticle.minWebviewBridgeVersion + mParticle.minWebviewBridgeVersion, ) .should.equal(false); delete mParticle.isIOS; @@ -333,8 +333,8 @@ describe('native-sdk methods', function() { }); }); - describe('bridge version 1', function() { - beforeEach(function() { + describe('bridge version 1', function () { + beforeEach(function () { mParticle._resetForTests(MPConfig); window.mParticleAndroid = null; window.mParticle.isIOS = null; @@ -343,7 +343,7 @@ describe('native-sdk methods', function() { mParticle.init(apiKey, window.mParticle.config); }); - it('should set mParitcle._Store.SDKConfig.isIOS to true when mParticle.isIOS is true', function(done) { + it('should set mParitcle._Store.SDKConfig.isIOS to true when mParticle.isIOS is true', function (done) { mParticle._resetForTests(MPConfig); mParticle.isIOS = true; mParticle.init(apiKey, window.mParticle.config); @@ -353,58 +353,58 @@ describe('native-sdk methods', function() { done(); }); - it('invoke setSessionAttributes of $src_key/$src_env of apikey/\'webview\' to the Android\'s on init if apiKey is available', function(done) { + it("invoke setSessionAttributes of $src_key/$src_env of apikey/'webview' to the Android's on init if apiKey is available", function (done) { mParticle._resetForTests(MPConfig); window.mParticleAndroid = new mParticleAndroid(); window.mParticle.init(apiKey, window.mParticle.config); window.mParticleAndroid.sessionAttrData.length.should.equal(2); JSON.parse( - window.mParticleAndroid.sessionAttrData[0] + window.mParticleAndroid.sessionAttrData[0], ).should.have.property('key', '$src_env'); JSON.parse( - window.mParticleAndroid.sessionAttrData[0] + window.mParticleAndroid.sessionAttrData[0], ).should.have.property('value', 'webview'); JSON.parse( - window.mParticleAndroid.sessionAttrData[1] + window.mParticleAndroid.sessionAttrData[1], ).should.have.property('key', '$src_key'); JSON.parse( - window.mParticleAndroid.sessionAttrData[1] + window.mParticleAndroid.sessionAttrData[1], ).should.have.property('value', apiKey); done(); }); - it('invoke only setSessionAttributes of $src_key/$src_env if apikey is missing from webview', function(done) { + it('invoke only setSessionAttributes of $src_key/$src_env if apikey is missing from webview', function (done) { mParticle._resetForTests(MPConfig); window.mParticleAndroid = new mParticleAndroid(); window.mParticle.init(null, window.mParticle.config); window.mParticleAndroid.sessionAttrData.length.should.equal(1); JSON.parse( - window.mParticleAndroid.sessionAttrData[0] + window.mParticleAndroid.sessionAttrData[0], ).should.have.property('key', '$src_env'); JSON.parse( - window.mParticleAndroid.sessionAttrData[0] + window.mParticleAndroid.sessionAttrData[0], ).should.have.property('value', 'webview'); done(); }); - it('should invoke setSessionAttributes on Android and pass through proper data', function(done) { + it('should invoke setSessionAttributes on Android and pass through proper data', function (done) { window.mParticleAndroid.resetSessionAttrData(); mParticle.setSessionAttribute('key', 'value'); window.mParticleAndroid.setSessionAttributeCalled.should.equal( - true + true, ); window.mParticleAndroid.sessionAttrData[0].should.equal( - JSON.stringify({ key: 'key', value: 'value' }) + JSON.stringify({ key: 'key', value: 'value' }), ); done(); }); - it('should invoke logEvent on Android and pass through proper event', function(done) { + it('should invoke logEvent on Android and pass through proper event', function (done) { mParticle.logEvent('testEvent'); window.mParticleAndroid.logEventCalled.should.equal(true); @@ -420,94 +420,94 @@ describe('native-sdk methods', function() { done(); }); - it('should invoke setAttribute on Android and pass through proper data', function(done) { + it('should invoke setAttribute on Android and pass through proper data', function (done) { mParticle.Identity.getCurrentUser().setUserAttribute( 'key', - 'value' + 'value', ); window.mParticleAndroid.setUserAttributeCalled.should.equal(true); window.mParticleAndroid.userAttrData[0].should.equal( - JSON.stringify({ key: 'key', value: 'value' }) + JSON.stringify({ key: 'key', value: 'value' }), ); window.mParticleAndroid.resetUserAttributes(); done(); }); - it('should invoke setAttribute on Android and pass through proper data when invoking setUserAttributes', function(done) { + it('should invoke setAttribute on Android and pass through proper data when invoking setUserAttributes', function (done) { mParticle.Identity.getCurrentUser().setUserAttributes({ gender: 'male', age: 21, }); window.mParticleAndroid.setUserAttributeCalled.should.equal(true); window.mParticleAndroid.userAttrData[0].should.equal( - JSON.stringify({ key: 'gender', value: 'male' }) + JSON.stringify({ key: 'gender', value: 'male' }), ); window.mParticleAndroid.userAttrData[1].should.equal( - JSON.stringify({ key: 'age', value: 21 }) + JSON.stringify({ key: 'age', value: 21 }), ); done(); }); - it('should invoke removeAttributes on native SDK', function(done) { + it('should invoke removeAttributes on native SDK', function (done) { mParticle.Identity.getCurrentUser().setUserAttribute( 'key', - 'value' + 'value', ); mParticle.Identity.getCurrentUser().removeUserAttribute('key'); window.mParticleAndroid.setUserAttributeCalled.should.equal(true); window.mParticleAndroid.removeUserAttributeCalled.should.equal( - true + true, ); done(); }); // TBD _ ask will/peter about add to cart array vs product? - it('should invoke native sdk method addToCart', function(done) { + it('should invoke native sdk method addToCart', function (done) { const product = mParticle.eCommerce.createProduct( 'name', 'sku', 10, - 1 + 1, ); const product2 = mParticle.eCommerce.createProduct( 'name', 'sku', 10, - 1 + 1, ); mParticle.eCommerce.Cart.add(product); window.mParticleAndroid.should.have.property( 'addToCartCalled', - true + true, ); window.mParticleAndroid.addedToCartItem.should.equal( - JSON.stringify([product]) + JSON.stringify([product]), ); window.mParticleAndroid.clearCart(); mParticle.eCommerce.Cart.add([product, product2]); window.mParticleAndroid.addedToCartItem.should.equal( - JSON.stringify([product, product2]) + JSON.stringify([product, product2]), ); done(); }); - it('should invoke native sdk method removeFromCart', function(done) { + it('should invoke native sdk method removeFromCart', function (done) { const product = mParticle.eCommerce.createProduct( 'name', 'sku', 10, - 1 + 1, ); mParticle.eCommerce.Cart.add(product); @@ -515,27 +515,27 @@ describe('native-sdk methods', function() { window.mParticleAndroid.should.have.property( 'removeFromCartCalled', - true + true, ); window.mParticleAndroid.removedFromCartItem.should.equal( - JSON.stringify(product) + JSON.stringify(product), ); done(); }); - it('should invoke native sdk method clearCart', function(done) { + it('should invoke native sdk method clearCart', function (done) { mParticle.eCommerce.Cart.clear(); window.mParticleAndroid.should.have.property( 'clearCartCalled', - true + true, ); done(); }); - it('should not sync cookies when in a mobile web view for Android', function(done) { + it('should not sync cookies when in a mobile web view for Android', function (done) { const pixelSettings = { name: 'AdobeEventForwarder', moduleId: 5, @@ -556,16 +556,16 @@ describe('native-sdk methods', function() { done(); }); - it('should send a JSON object to the native SDK\'s Identity methods', function(done) { - let result, - identityAPIRequest = { - userIdentities: { - customerid: '123', - email: 'test@gmail.com', - }, - }; + it("should send a JSON object to the native SDK's Identity methods", function (done) { + let result; + const identityAPIRequest = { + userIdentities: { + customerid: '123', + email: 'test@gmail.com', + }, + }; - const callback = function(resp) { + const callback = function (resp) { result = resp; }; @@ -592,8 +592,8 @@ describe('native-sdk methods', function() { mParticle .getInstance() ._Identity.IdentityRequest.convertToNative( - identityAPIRequest - ) + identityAPIRequest, + ), ); window.mParticleAndroid.loginData.should.equal(JSONData); @@ -603,24 +603,24 @@ describe('native-sdk methods', function() { done(); }); - it('should send events via the mParticle.ready method ', function(done) { - mParticle.ready(function() { + it('should send events via the mParticle.ready method ', function (done) { + mParticle.ready(function () { mParticle.logEvent('test'); }); window.mParticleAndroid.logEventCalled.should.equal(true); JSON.parse(window.mParticleAndroid.event).EventName.should.equal( - 'test' + 'test', ); done(); }); }); - describe('bridge version 2', function() { - describe('android', function() { + describe('bridge version 2', function () { + describe('android', function () { let mParticleAndroidV2Bridge; - beforeEach(function() { + beforeEach(function () { window.mParticleAndroid = null; window.mParticle.isIOS = null; mParticle._resetForTests(MPConfig); @@ -635,18 +635,18 @@ describe('native-sdk methods', function() { mParticle.config = {}; }); - afterEach(function() { + afterEach(function () { delete window.mParticle.config; delete window.mParticleAndroid_bridgeName_v2; }); - it('should invoke logEvent on Android and pass through proper event', function(done) { + it('should invoke logEvent on Android and pass through proper event', function (done) { mParticle.logEvent('testEvent'); mParticleAndroidV2Bridge.logEventCalled.should.equal(true); (typeof mParticleAndroidV2Bridge.event).should.equal('string'); JSON.parse( - mParticleAndroidV2Bridge.event + mParticleAndroidV2Bridge.event, ).should.have.properties([ 'EventName', 'EventCategory', @@ -658,93 +658,93 @@ describe('native-sdk methods', function() { done(); }); - it('should invoke setAttribute on Android and pass through proper data', function(done) { + it('should invoke setAttribute on Android and pass through proper data', function (done) { mParticle.Identity.getCurrentUser().setUserAttribute( 'key', - 'value' + 'value', ); mParticleAndroidV2Bridge.setUserAttributeCalled.should.equal( - true + true, ); mParticleAndroidV2Bridge.userAttrData[0].should.equal( - JSON.stringify({ key: 'key', value: 'value' }) + JSON.stringify({ key: 'key', value: 'value' }), ); mParticleAndroidV2Bridge.resetUserAttributes(); done(); }); - it('should invoke setAttribute on Android and pass through proper data when invoking setUserAttributes', function(done) { + it('should invoke setAttribute on Android and pass through proper data when invoking setUserAttributes', function (done) { mParticle.Identity.getCurrentUser().setUserAttributes({ gender: 'male', age: 21, }); mParticleAndroidV2Bridge.setUserAttributeCalled.should.equal( - true + true, ); mParticleAndroidV2Bridge.userAttrData[0].should.equal( - JSON.stringify({ key: 'gender', value: 'male' }) + JSON.stringify({ key: 'gender', value: 'male' }), ); mParticleAndroidV2Bridge.userAttrData[1].should.equal( - JSON.stringify({ key: 'age', value: 21 }) + JSON.stringify({ key: 'age', value: 21 }), ); mParticleAndroidV2Bridge.resetUserAttributes(); done(); }); - it('should invoke removeAttributes on Android', function(done) { + it('should invoke removeAttributes on Android', function (done) { mParticle.Identity.getCurrentUser().setUserAttribute( 'key', - 'value' + 'value', ); mParticle.Identity.getCurrentUser().removeUserAttribute('key'); mParticleAndroidV2Bridge.setUserAttributeCalled.should.equal( - true + true, ); mParticleAndroidV2Bridge.removeUserAttributeCalled.should.equal( - true + true, ); done(); }); - it('should invoke setSessionAttributes on Android and pass through proper data', function(done) { + it('should invoke setSessionAttributes on Android and pass through proper data', function (done) { mParticle.setSessionAttribute('key', 'value'); mParticleAndroidV2Bridge.setSessionAttributeCalled.should.equal( - true + true, ); mParticleAndroidV2Bridge.sessionAttrData[2].should.equal( - JSON.stringify({ key: 'key', value: 'value' }) + JSON.stringify({ key: 'key', value: 'value' }), ); done(); }); - it('should invoke Android method addToCart', function(done) { + it('should invoke Android method addToCart', function (done) { const product = mParticle.eCommerce.createProduct( 'name', 'sku', 10, - 1 + 1, ); const product2 = mParticle.eCommerce.createProduct( 'name', 'sku', 10, - 1 + 1, ); mParticle.eCommerce.Cart.add(product); mParticleAndroidV2Bridge.should.have.property( 'addToCartCalled', - true + true, ); mParticleAndroidV2Bridge.addedToCartItem.should.equal( - JSON.stringify([product]) + JSON.stringify([product]), ); mParticleAndroidV2Bridge.clearCart(); @@ -752,18 +752,18 @@ describe('native-sdk methods', function() { mParticle.eCommerce.Cart.add([product, product2]); mParticleAndroidV2Bridge.addedToCartItem.should.equal( - JSON.stringify([product, product2]) + JSON.stringify([product, product2]), ); done(); }); - it('should invoke Android method removeFromCart', function(done) { + it('should invoke Android method removeFromCart', function (done) { const product = mParticle.eCommerce.createProduct( 'name', 'sku', 10, - 1 + 1, ); mParticle.eCommerce.Cart.add(product); @@ -771,32 +771,32 @@ describe('native-sdk methods', function() { mParticleAndroidV2Bridge.should.have.property( 'removeFromCartCalled', - true + true, ); mParticleAndroidV2Bridge.removedFromCartItem.should.equal( - JSON.stringify(product) + JSON.stringify(product), ); mParticleAndroidV2Bridge.should.have.property( 'removeFromCartCalled', - true + true, ); done(); }); - it('should invoke Android method clearCart', function(done) { + it('should invoke Android method clearCart', function (done) { mParticle.eCommerce.Cart.clear(); mParticleAndroidV2Bridge.should.have.property( 'clearCartCalled', - true + true, ); done(); }); - it('should not sync cookies when in a mobile web view for Android', function(done) { + it('should not sync cookies when in a mobile web view for Android', function (done) { const pixelSettings = { name: 'AdobeEventForwarder', moduleId: 5, @@ -816,16 +816,16 @@ describe('native-sdk methods', function() { done(); }); - it('should send a JSON object to the Android\'s Identity methods', function(done) { - let result, - identityAPIRequest = { - userIdentities: { - customerid: '123', - email: 'test@gmail.com', - }, - }; + it("should send a JSON object to the Android's Identity methods", function (done) { + let result; + const identityAPIRequest = { + userIdentities: { + customerid: '123', + email: 'test@gmail.com', + }, + }; - const callback = function(resp) { + const callback = function (resp) { result = resp; }; @@ -852,8 +852,8 @@ describe('native-sdk methods', function() { mParticle .getInstance() ._Identity.IdentityRequest.convertToNative( - identityAPIRequest - ) + identityAPIRequest, + ), ); mParticleAndroidV2Bridge.loginData.should.equal(JSONData); @@ -863,7 +863,7 @@ describe('native-sdk methods', function() { done(); }); - it('should send a JSON object to the Android\'s Alias method', function(done) { + it("should send a JSON object to the Android's Alias method", function (done) { let callbackResult; const aliasRequest = { destinationMpid: '101', @@ -872,60 +872,64 @@ describe('native-sdk methods', function() { endTime: 400, }; - mParticle.Identity.aliasUsers(aliasRequest, function(callback) { - callbackResult = callback; - }); + mParticle.Identity.aliasUsers( + aliasRequest, + function (callback) { + callbackResult = callback; + }, + ); mParticleAndroidV2Bridge.aliasUsers.should.equal( - '{"DestinationMpid":"101","SourceMpid":"202","StartUnixtimeMs":300,"EndUnixtimeMs":400}' + '{"DestinationMpid":"101","SourceMpid":"202","StartUnixtimeMs":300,"EndUnixtimeMs":400}', ); callbackResult.httpCode.should.equal( - HTTPCodes.nativeIdentityRequest + HTTPCodes.nativeIdentityRequest, ); callbackResult.message.should.equal( - 'Alias request sent to native sdk' + 'Alias request sent to native sdk', ); done(); }); - it('should send events via the mParticle.ready method ', function(done) { - mParticle.ready(function() { + it('should send events via the mParticle.ready method ', function (done) { + mParticle.ready(function () { mParticle.logEvent('test'); }); mParticleAndroidV2Bridge.logEventCalled.should.equal(true); JSON.parse( - mParticleAndroidV2Bridge.event + mParticleAndroidV2Bridge.event, ).EventName.should.equal('test'); done(); }); - it('should send an event with a product list when calling logPurchase', function(done) { + it('should send an event with a product list when calling logPurchase', function (done) { const product = mParticle.eCommerce.createProduct( 'product1', 'sku', 10, - 1 + 1, ); const product2 = mParticle.eCommerce.createProduct( 'product2', 'sku', 10, - 1 + 1, ); mParticle.eCommerce.Cart.add([product, product2]); - const transactionAttributes = mParticle.eCommerce.createTransactionAttributes( - 'TAid1', - 'aff1', - 'coupon', - 1798, - 10, - 5 - ); + const transactionAttributes = + mParticle.eCommerce.createTransactionAttributes( + 'TAid1', + 'aff1', + 'coupon', + 1798, + 10, + 5, + ); const clearCartBoolean = true; const customAttributes = { value: 10 }; const customFlags = { foo: 'bar' }; @@ -935,20 +939,20 @@ describe('native-sdk methods', function() { [product, product2], clearCartBoolean, customAttributes, - customFlags + customFlags, ); JSON.parse( - mParticleAndroidV2Bridge.event + mParticleAndroidV2Bridge.event, ).ProductAction.ProductList[0].Name.should.equal('product1'); JSON.parse( - mParticleAndroidV2Bridge.event + mParticleAndroidV2Bridge.event, ).ProductAction.ProductList[1].Name.should.equal('product2'); done(); }); - it('should invoke upload on native SDK', function(done) { + it('should invoke upload on native SDK', function (done) { mParticle.upload(); mParticleAndroidV2Bridge.uploadCalled.should.equal(true); @@ -957,9 +961,9 @@ describe('native-sdk methods', function() { }); }); - describe('iOS', function() { + describe('iOS', function () { let mParticleIOSV2Bridge; - beforeEach(function() { + beforeEach(function () { window.mParticleAndroid = null; window.mParticle.isIOS = null; mParticle._resetForTests(MPConfig); @@ -980,23 +984,23 @@ describe('native-sdk methods', function() { mParticleIOSV2Bridge.reset(); }); - afterEach(function() { + afterEach(function () { delete window.webkit; delete mParticle.requiredWebviewBridgeName; delete mParticle.enableWebviewBridge; }); - it('should invoke logEvent on iOS SDK and pass through proper event', function(done) { + it('should invoke logEvent on iOS SDK and pass through proper event', function (done) { mParticle.logEvent('testEvent'); JSON.parse(mParticleIOSV2Bridge.data[0]).should.have.properties( - ['path', 'value'] + ['path', 'value'], ); JSON.parse(mParticleIOSV2Bridge.data[0]).path.should.equal( - 'logEvent' + 'logEvent', ); JSON.parse( - mParticleIOSV2Bridge.data[0] + mParticleIOSV2Bridge.data[0], ).value.should.have.properties([ 'EventName', 'EventCategory', @@ -1008,193 +1012,193 @@ describe('native-sdk methods', function() { done(); }); - it('should invoke setAttribute on iOS SDK and pass through proper data', function(done) { + it('should invoke setAttribute on iOS SDK and pass through proper data', function (done) { mParticle.Identity.getCurrentUser().setUserAttribute( 'key', - 'value' + 'value', ); JSON.parse(mParticleIOSV2Bridge.data[0]).should.have.properties( - ['path', 'value'] + ['path', 'value'], ); JSON.parse(mParticleIOSV2Bridge.data[0]).path.should.equal( - 'setUserAttribute' + 'setUserAttribute', ); JSON.parse( - mParticleIOSV2Bridge.data[0] + mParticleIOSV2Bridge.data[0], ).value.should.have.property('key', 'key'); JSON.parse( - mParticleIOSV2Bridge.data[0] + mParticleIOSV2Bridge.data[0], ).value.should.have.property('value', 'value'); done(); }); - it('should invoke setAttribute on iOS SDK and pass through proper data when invoking setUserAttributes', function(done) { + it('should invoke setAttribute on iOS SDK and pass through proper data when invoking setUserAttributes', function (done) { mParticle.Identity.getCurrentUser().setUserAttributes({ gender: 'male', age: 21, }); JSON.parse(mParticleIOSV2Bridge.data[0]).should.have.properties( - ['path', 'value'] + ['path', 'value'], ); JSON.parse(mParticleIOSV2Bridge.data[0]).path.should.equal( - 'setUserAttribute' + 'setUserAttribute', ); JSON.parse( - mParticleIOSV2Bridge.data[0] + mParticleIOSV2Bridge.data[0], ).value.should.have.property('key', 'gender'); JSON.parse( - mParticleIOSV2Bridge.data[0] + mParticleIOSV2Bridge.data[0], ).value.should.have.property('value', 'male'); JSON.parse(mParticleIOSV2Bridge.data[1]).should.have.properties( - ['path', 'value'] + ['path', 'value'], ); JSON.parse(mParticleIOSV2Bridge.data[1]).path.should.equal( - 'setUserAttribute' + 'setUserAttribute', ); JSON.parse( - mParticleIOSV2Bridge.data[1] + mParticleIOSV2Bridge.data[1], ).value.should.have.property('key', 'age'); JSON.parse( - mParticleIOSV2Bridge.data[1] + mParticleIOSV2Bridge.data[1], ).value.should.have.property('value', 21); done(); }); - it('should invoke removeAttributes on iOS SDK', function(done) { + it('should invoke removeAttributes on iOS SDK', function (done) { mParticle.Identity.getCurrentUser().setUserAttribute( 'key', - 'value' + 'value', ); mParticle.Identity.getCurrentUser().removeUserAttribute('key'); JSON.parse(mParticleIOSV2Bridge.data[0]).should.have.properties( - ['path', 'value'] + ['path', 'value'], ); JSON.parse(mParticleIOSV2Bridge.data[0]).path.should.equal( - 'setUserAttribute' + 'setUserAttribute', ); JSON.parse( - mParticleIOSV2Bridge.data[0] + mParticleIOSV2Bridge.data[0], ).value.should.have.property('key', 'key'); JSON.parse( - mParticleIOSV2Bridge.data[0] + mParticleIOSV2Bridge.data[0], ).value.should.have.property('value', 'value'); JSON.parse(mParticleIOSV2Bridge.data[1]).should.have.properties( - ['path', 'value'] + ['path', 'value'], ); JSON.parse(mParticleIOSV2Bridge.data[1]).path.should.equal( - 'removeUserAttribute' + 'removeUserAttribute', ); JSON.parse( - mParticleIOSV2Bridge.data[1] + mParticleIOSV2Bridge.data[1], ).value.should.have.property('key', 'key'); JSON.parse( - mParticleIOSV2Bridge.data[1] + mParticleIOSV2Bridge.data[1], ).value.should.have.property('value', null); done(); }); - it('should invoke setSessionAttributes on ios SDK and pass through proper data', function(done) { + it('should invoke setSessionAttributes on ios SDK and pass through proper data', function (done) { mParticle.setSessionAttribute('key', 'value'); JSON.parse(mParticleIOSV2Bridge.data[0]).should.have.properties( - ['path', 'value'] + ['path', 'value'], ); JSON.parse(mParticleIOSV2Bridge.data[0]).path.should.equal( - 'setSessionAttribute' + 'setSessionAttribute', ); JSON.parse( - mParticleIOSV2Bridge.data[0] + mParticleIOSV2Bridge.data[0], ).value.should.have.property('key', 'key'); JSON.parse( - mParticleIOSV2Bridge.data[0] + mParticleIOSV2Bridge.data[0], ).value.should.have.property('value', 'value'); done(); }); - it('should invoke ios sdk method addToCart', function(done) { + it('should invoke ios sdk method addToCart', function (done) { const product = mParticle.eCommerce.createProduct( 'name', 'sku', 10, - 1 + 1, ); const product2 = mParticle.eCommerce.createProduct( 'name', 'sku', 10, - 1 + 1, ); mParticle.eCommerce.Cart.add(product); JSON.parse(mParticleIOSV2Bridge.data[0]).should.have.properties( - ['path', 'value'] + ['path', 'value'], ); JSON.parse(mParticleIOSV2Bridge.data[0]).path.should.equal( - 'addToCart' + 'addToCart', ); JSON.stringify( - JSON.parse(mParticleIOSV2Bridge.data[0]).value + JSON.parse(mParticleIOSV2Bridge.data[0]).value, ).should.equal(JSON.stringify([product])); mParticleIOSV2Bridge.reset(); mParticle.eCommerce.Cart.add([product, product2]); JSON.parse(mParticleIOSV2Bridge.data[0]).should.have.properties( - ['path', 'value'] + ['path', 'value'], ); JSON.parse(mParticleIOSV2Bridge.data[0]).path.should.equal( - 'addToCart' + 'addToCart', ); JSON.stringify( - JSON.parse(mParticleIOSV2Bridge.data[0]).value + JSON.parse(mParticleIOSV2Bridge.data[0]).value, ).should.equal(JSON.stringify([product, product2])); done(); }); - it('should invoke ios sdk method removeFromCart', function(done) { + it('should invoke ios sdk method removeFromCart', function (done) { const product = mParticle.eCommerce.createProduct( 'name', 'sku', 10, - 1 + 1, ); mParticle.eCommerce.Cart.remove(product); JSON.parse(mParticleIOSV2Bridge.data[0]).should.have.properties( - ['path', 'value'] + ['path', 'value'], ); JSON.parse(mParticleIOSV2Bridge.data[0]).path.should.equal( - 'removeFromCart' + 'removeFromCart', ); JSON.stringify( - JSON.parse(mParticleIOSV2Bridge.data[0]).value + JSON.parse(mParticleIOSV2Bridge.data[0]).value, ).should.equal(JSON.stringify(product)); done(); }); - it('should invoke ios sdk method clearCart', function(done) { + it('should invoke ios sdk method clearCart', function (done) { mParticle.eCommerce.Cart.clear(); JSON.parse(mParticleIOSV2Bridge.data[0]).should.have.properties( - ['path', 'value'] + ['path', 'value'], ); JSON.parse(mParticleIOSV2Bridge.data[0]).path.should.equal( - 'clearCart' + 'clearCart', ); done(); }); - it('should not sync cookies when in a mobile web view', function(done) { + it('should not sync cookies when in a mobile web view', function (done) { const pixelSettings = { name: 'AdobeEventForwarder', moduleId: 5, @@ -1214,16 +1218,16 @@ describe('native-sdk methods', function() { done(); }); - it('should send a JSON object to the ios SDK\'s Identity methods', function(done) { - let result, - identityAPIRequest = { - userIdentities: { - customerid: '123', - email: 'test@gmail.com', - }, - }; + it("should send a JSON object to the ios SDK's Identity methods", function (done) { + let result; + const identityAPIRequest = { + userIdentities: { + customerid: '123', + email: 'test@gmail.com', + }, + }; - const callback = function(resp) { + const callback = function (resp) { result = resp; }; @@ -1231,8 +1235,8 @@ describe('native-sdk methods', function() { mParticle .getInstance() ._Identity.IdentityRequest.convertToNative( - identityAPIRequest - ) + identityAPIRequest, + ), ); mParticle.Identity.login(identityAPIRequest, callback); @@ -1240,7 +1244,7 @@ describe('native-sdk methods', function() { result.httpCode.should.equal(-5); result = null; JSON.stringify( - JSON.parse(mParticleIOSV2Bridge.data[0]).value + JSON.parse(mParticleIOSV2Bridge.data[0]).value, ).should.equal(JSONData); mParticleIOSV2Bridge.reset(); @@ -1249,7 +1253,7 @@ describe('native-sdk methods', function() { result.httpCode.should.equal(-5); result = null; JSON.stringify( - JSON.parse(mParticleIOSV2Bridge.data[0]).value + JSON.parse(mParticleIOSV2Bridge.data[0]).value, ).should.equal(JSONData); mParticleIOSV2Bridge.reset(); @@ -1258,7 +1262,7 @@ describe('native-sdk methods', function() { result.httpCode.should.equal(-5); result = null; JSON.stringify( - JSON.parse(mParticleIOSV2Bridge.data[0]).value + JSON.parse(mParticleIOSV2Bridge.data[0]).value, ).should.equal(JSONData); mParticleIOSV2Bridge.reset(); @@ -1266,14 +1270,14 @@ describe('native-sdk methods', function() { result.body.should.equal('Identify request sent to native sdk'); result.httpCode.should.equal(-5); JSON.stringify( - JSON.parse(mParticleIOSV2Bridge.data[0]).value + JSON.parse(mParticleIOSV2Bridge.data[0]).value, ).should.equal(JSONData); mParticleIOSV2Bridge.reset(); done(); }); - it('should send a JSON object to the iOS SDK\'s Alias method', function(done) { + it("should send a JSON object to the iOS SDK's Alias method", function (done) { let callbackResult; const aliasRequest = { destinationMpid: '101', @@ -1282,80 +1286,84 @@ describe('native-sdk methods', function() { endTime: 400, }; - mParticle.Identity.aliasUsers(aliasRequest, function(callback) { - callbackResult = callback; - }); + mParticle.Identity.aliasUsers( + aliasRequest, + function (callback) { + callbackResult = callback; + }, + ); JSON.parse(mParticleIOSV2Bridge.data[0]).should.have.properties( - ['path', 'value'] + ['path', 'value'], ); JSON.parse(mParticleIOSV2Bridge.data[0]).path.should.equal( - 'aliasUsers' + 'aliasUsers', ); JSON.stringify( - JSON.parse(mParticleIOSV2Bridge.data[0]).value + JSON.parse(mParticleIOSV2Bridge.data[0]).value, ).should.equal( - '{"DestinationMpid":"101","SourceMpid":"202","StartUnixtimeMs":300,"EndUnixtimeMs":400}' + '{"DestinationMpid":"101","SourceMpid":"202","StartUnixtimeMs":300,"EndUnixtimeMs":400}', ); mParticleIOSV2Bridge.reset(); callbackResult.httpCode.should.equal( - HTTPCodes.nativeIdentityRequest + HTTPCodes.nativeIdentityRequest, ); callbackResult.message.should.equal( - 'Alias request sent to native sdk' + 'Alias request sent to native sdk', ); done(); }); - it('should send events via the mParticle.ready method ', function(done) { - mParticle.ready(function() { + it('should send events via the mParticle.ready method ', function (done) { + mParticle.ready(function () { mParticle.logEvent('test'); }); JSON.parse(mParticleIOSV2Bridge.data[0]).should.have.properties( - ['path', 'value'] + ['path', 'value'], ); JSON.parse( - mParticleIOSV2Bridge.data[0] + mParticleIOSV2Bridge.data[0], ).value.should.have.property('EventName', 'test'); done(); }); - it('should send an event with a product list when calling logPurchase', function(done) { + it('should send an event with a product list when calling logPurchase', function (done) { const product = mParticle.eCommerce.createProduct( 'product1', 'sku', 10, - 1 + 1, ); const product2 = mParticle.eCommerce.createProduct( 'product2', 'sku', 10, - 1 + 1, ); mParticle.eCommerce.Cart.add([product, product2]); JSON.parse(mParticleIOSV2Bridge.data[0]).should.have.properties( - ['path', 'value'] + ['path', 'value'], ); JSON.parse(mParticleIOSV2Bridge.data[0]).path.should.equal( - 'addToCart' + 'addToCart', ); JSON.stringify( - JSON.parse(mParticleIOSV2Bridge.data[0]).value + JSON.parse(mParticleIOSV2Bridge.data[0]).value, ).should.equal(JSON.stringify([product, product2])); - const transactionAttributes = mParticle.eCommerce.createTransactionAttributes( - 'TAid1', - 'aff1', - 'coupon', - 1798, - 10, - 5 - ); + const transactionAttributes = + mParticle.eCommerce.createTransactionAttributes( + 'TAid1', + 'aff1', + 'coupon', + 1798, + 10, + 5, + ); const clearCartBoolean = true; const customAttributes = { value: 10 }; const customFlags = { foo: 'bar' }; @@ -1365,44 +1373,45 @@ describe('native-sdk methods', function() { [product, product2], clearCartBoolean, customAttributes, - customFlags + customFlags, ); JSON.parse(mParticleIOSV2Bridge.data[0]).path.should.equal( - 'logEvent' + 'logEvent', ); JSON.parse( - mParticleIOSV2Bridge.data[0] + mParticleIOSV2Bridge.data[0], ).value.ProductAction.ProductList.length.should.equal(2); JSON.parse( - mParticleIOSV2Bridge.data[0] + mParticleIOSV2Bridge.data[0], ).value.ProductAction.ProductList[0].Name.should.equal( - 'product1' + 'product1', ); JSON.parse( - mParticleIOSV2Bridge.data[0] + mParticleIOSV2Bridge.data[0], ).value.ProductAction.ProductList[1].Name.should.equal( - 'product2' + 'product2', ); done(); }); - it('should invoke upload on iOS SDK', function(done) { + it('should invoke upload on iOS SDK', function (done) { mParticle.upload(); - JSON.parse(mParticleIOSV2Bridge.data[0]).should.have.properties( - ['path', 'value'] + ['path', 'value'], ); JSON.parse(mParticleIOSV2Bridge.data[0]).path.should.equal( - 'upload' + 'upload', ); - - (JSON.parse(mParticleIOSV2Bridge.data[0]).value === null).should.equal(true); + + ( + JSON.parse(mParticleIOSV2Bridge.data[0]).value === null + ).should.equal(true); done(); }); }); }); -}); \ No newline at end of file +}); diff --git a/test/src/tests-persistence.ts b/test/src/tests-persistence.ts index 5408d6d74..8987429a7 100644 --- a/test/src/tests-persistence.ts +++ b/test/src/tests-persistence.ts @@ -11,7 +11,7 @@ import { localStorageProductsV4, LocalStorageProductsV4WithWorkSpaceName, workspaceCookieName, - v4LSKey + v4LSKey, } from './config/constants'; import { expect } from 'chai'; import { @@ -48,52 +48,56 @@ describe('persistence', () => { }); describe('#swapCurrentUser', () => { - it('should not swap a user if there is no MPID change', function(done) { + it('should not swap a user if there is no MPID change', function (done) { mParticle.init(apiKey, window.mParticle.config); waitForCondition(() => { return ( - window.mParticle.getInstance()?._Store?.identityCallInFlight === false + window.mParticle.getInstance()?._Store + ?.identityCallInFlight === false ); - }) - .then(() => { - const cookiesBefore = getLocalStorage(); - mParticle.getInstance()._Persistence.swapCurrentUser(testMPID, testMPID); - - const cookiesAfter = mParticle - .getInstance() - ._Persistence.getLocalStorage(); - - cookiesBefore.cu.should.equal(cookiesAfter.cu); - - done(); + }).then(() => { + const cookiesBefore = getLocalStorage(); + mParticle + .getInstance() + ._Persistence.swapCurrentUser(testMPID, testMPID); + + const cookiesAfter = mParticle + .getInstance() + ._Persistence.getLocalStorage(); + + cookiesBefore.cu.should.equal(cookiesAfter.cu); + + done(); }); }); - - it('should swap a user if there is an MPID change', function(done) { + + it('should swap a user if there is an MPID change', function (done) { mParticle.init(apiKey, window.mParticle.config); waitForCondition(() => { return ( - window.mParticle.getInstance()?._Store?.identityCallInFlight === false + window.mParticle.getInstance()?._Store + ?.identityCallInFlight === false ); - }) - .then(() => { - const cookiesBefore = getLocalStorage(); - - mParticle.getInstance()._Persistence.swapCurrentUser(testMPID, 'currentMPID'); - - const cookiesAfter = mParticle - .getInstance() - ._Persistence.getLocalStorage(); - cookiesBefore.cu.should.equal(testMPID); - - cookiesAfter.cu.should.equal('currentMPID'); - - done(); - }); + }).then(() => { + const cookiesBefore = getLocalStorage(); + + mParticle + .getInstance() + ._Persistence.swapCurrentUser(testMPID, 'currentMPID'); + + const cookiesAfter = mParticle + .getInstance() + ._Persistence.getLocalStorage(); + cookiesBefore.cu.should.equal(testMPID); + + cookiesAfter.cu.should.equal('currentMPID'); + + done(); + }); }); }); - it('should move new schema from cookies to localStorage with useCookieStorage = false', done => { + it('should move new schema from cookies to localStorage with useCookieStorage = false', (done) => { mParticle._resetForTests(MPConfig); const cookies = JSON.stringify({ @@ -127,7 +131,7 @@ describe('persistence', () => { done(); }); - it('should migrate localStorage to cookies with useCookieStorage = true', done => { + it('should migrate localStorage to cookies with useCookieStorage = true', (done) => { mParticle._resetForTests(MPConfig); setLocalStorage(); @@ -147,460 +151,457 @@ describe('persistence', () => { cookieData[testMPID].ua.should.have.property('gender', 'male'); cookieData[testMPID].ui.should.have.property( '1', - 'testuser@mparticle.com' + 'testuser@mparticle.com', ); done(); }); - it('localStorage - should key cookies on mpid on first run', done => { + it('localStorage - should key cookies on mpid on first run', (done) => { mParticle.config.useCookieStorage = false; mParticle.init(apiKey, mParticle.config); - waitForCondition(hasIdentifyReturned) - .then(() => { - const cookies1 = mParticle.getInstance()._Persistence.getLocalStorage(); - const props1 = [ - 'ie', - 'sa', - 'ua', - 'ui', - 'ss', - 'dt', - 'les', - 'av', - 'cgid', - 'das', - 'csd', - 'mpid', - 'cp', - 'sid', - 'c', - ]; - props1.forEach(function(prop) { - cookies1.should.not.have.property(prop); - }); - cookies1.should.have.property('cu', testMPID, 'gs'); - cookies1.should.have.property(testMPID); - - const props2 = [ - 'ie', - 'sa', - 'ss', - 'dt', - 'les', - 'av', - 'cgid', - 'das', - 'sid', - 'c', - 'mpid', - 'cp', - ]; - - fetchMockSuccess(urls.login, { - mpid: 'otherMPID', is_logged_in: false - }); + waitForCondition(hasIdentifyReturned).then(() => { + const cookies1 = mParticle + .getInstance() + ._Persistence.getLocalStorage(); + const props1 = [ + 'ie', + 'sa', + 'ua', + 'ui', + 'ss', + 'dt', + 'les', + 'av', + 'cgid', + 'das', + 'csd', + 'mpid', + 'cp', + 'sid', + 'c', + ]; + props1.forEach(function (prop) { + cookies1.should.not.have.property(prop); + }); + cookies1.should.have.property('cu', testMPID, 'gs'); + cookies1.should.have.property(testMPID); + + const props2 = [ + 'ie', + 'sa', + 'ss', + 'dt', + 'les', + 'av', + 'cgid', + 'das', + 'sid', + 'c', + 'mpid', + 'cp', + ]; - mParticle.Identity.login(); - waitForCondition(() => { - return ( - mParticle.Identity.getCurrentUser()?.getMPID() === 'otherMPID' - ); - }) - .then(() => { - const cookies2 = mParticle.getInstance()._Persistence.getLocalStorage(); - cookies2.should.have.property('cu', 'otherMPID', 'gs'); - props2.forEach(function(prop) { - cookies1[testMPID].should.not.have.property(prop); - cookies2[testMPID].should.not.have.property(prop); - cookies2['otherMPID'].should.not.have.property(prop); - }); + fetchMockSuccess(urls.login, { + mpid: 'otherMPID', + is_logged_in: false, + }); - done(); - }); + mParticle.Identity.login(); + waitForCondition(() => { + return ( + mParticle.Identity.getCurrentUser()?.getMPID() === + 'otherMPID' + ); + }).then(() => { + const cookies2 = mParticle + .getInstance() + ._Persistence.getLocalStorage(); + cookies2.should.have.property('cu', 'otherMPID', 'gs'); + props2.forEach(function (prop) { + cookies1[testMPID].should.not.have.property(prop); + cookies2[testMPID].should.not.have.property(prop); + cookies2['otherMPID'].should.not.have.property(prop); + }); + + done(); + }); }); }); - it('cookies - should key cookies on mpid when there are no cookies yet', done => { + it('cookies - should key cookies on mpid when there are no cookies yet', (done) => { mParticle.config.useCookieStorage = true; mParticle.init(apiKey, mParticle.config); - waitForCondition(hasIdentifyReturned) - .then(() => { - - const cookies1 = findCookie(); - - const props1 = [ - 'ie', - 'sa', - 'ua', - 'ui', - 'ss', - 'dt', - 'les', - 'av', - 'cgid', - 'das', - 'csd', - 'mpid', - 'cp', - 'sid', - 'c', - ]; - cookies1.should.have.property('cu', testMPID, 'gs'); - props1.forEach(function(prop) { - cookies1.should.not.have.property(prop); - }); + waitForCondition(hasIdentifyReturned).then(() => { + const cookies1 = findCookie(); + + const props1 = [ + 'ie', + 'sa', + 'ua', + 'ui', + 'ss', + 'dt', + 'les', + 'av', + 'cgid', + 'das', + 'csd', + 'mpid', + 'cp', + 'sid', + 'c', + ]; + cookies1.should.have.property('cu', testMPID, 'gs'); + props1.forEach(function (prop) { + cookies1.should.not.have.property(prop); + }); - const props2 = [ - 'ie', - 'sa', - 'ss', - 'dt', - 'les', - 'av', - 'cgid', - 'das', - 'sid', - 'c', - 'mpid', - 'cp', - ]; + const props2 = [ + 'ie', + 'sa', + 'ss', + 'dt', + 'les', + 'av', + 'cgid', + 'das', + 'sid', + 'c', + 'mpid', + 'cp', + ]; - fetchMockSuccess(urls.login, { - mpid: 'otherMPID', is_logged_in: false - }); + fetchMockSuccess(urls.login, { + mpid: 'otherMPID', + is_logged_in: false, + }); - mParticle.Identity.login(); - waitForCondition(() => { - return ( - mParticle.Identity.getCurrentUser()?.getMPID() === 'otherMPID' - ); - }) - .then(() => { - const cookies2 = findCookie(); + mParticle.Identity.login(); + waitForCondition(() => { + return ( + mParticle.Identity.getCurrentUser()?.getMPID() === + 'otherMPID' + ); + }).then(() => { + const cookies2 = findCookie(); - cookies2.should.have.property('cu', 'otherMPID', testMPID); + cookies2.should.have.property('cu', 'otherMPID', testMPID); - props2.forEach(function(prop) { - cookies1[testMPID].should.not.have.property(prop); - cookies2[testMPID].should.not.have.property(prop); - cookies2['otherMPID'].should.not.have.property(prop); - }); + props2.forEach(function (prop) { + cookies1[testMPID].should.not.have.property(prop); + cookies2[testMPID].should.not.have.property(prop); + cookies2['otherMPID'].should.not.have.property(prop); + }); - done(); - }); - }); + done(); + }); + }); }); - it('puts data into cookies when init-ing with useCookieStorage = true', done => { + it('puts data into cookies when init-ing with useCookieStorage = true', (done) => { mParticle.config.useCookieStorage = true; mParticle.init(apiKey, mParticle.config); - waitForCondition(hasIdentifyReturned) - .then(() => { + waitForCondition(hasIdentifyReturned).then(() => { + const cookieData = findCookie(); - const cookieData = findCookie(); - - const localStorageData = mParticle - .getInstance() - ._Persistence.getLocalStorage(); + const localStorageData = mParticle + .getInstance() + ._Persistence.getLocalStorage(); - cookieData.should.have.properties(['gs', 'cu', testMPID]); - - const props = [ - 'ie', - 'sa', - 'ss', - 'dt', - 'les', - 'av', - 'cgid', - 'das', - 'sid', - 'c', - 'mpid', - 'cp', - ]; - - props.forEach(function(prop) { - cookieData[testMPID].should.not.have.property(prop); - }); + cookieData.should.have.properties(['gs', 'cu', testMPID]); + + const props = [ + 'ie', + 'sa', + 'ss', + 'dt', + 'les', + 'av', + 'cgid', + 'das', + 'sid', + 'c', + 'mpid', + 'cp', + ]; + + props.forEach(function (prop) { + cookieData[testMPID].should.not.have.property(prop); + }); - expect(localStorageData).to.not.be.ok; + expect(localStorageData).to.not.be.ok; - done(); - }); + done(); + }); }); - it('puts data into localStorage when running initializeStorage with useCookieStorage = false', done => { + it('puts data into localStorage when running initializeStorage with useCookieStorage = false', (done) => { mParticle.init(apiKey, mParticle.config); - waitForCondition(hasIdentifyReturned) - .then(() => { - const cookieData = mParticle.getInstance()._Persistence.getCookie(); + waitForCondition(hasIdentifyReturned).then(() => { + const cookieData = mParticle.getInstance()._Persistence.getCookie(); - const localStorageData = mParticle - .getInstance() - ._Persistence.getLocalStorage(); + const localStorageData = mParticle + .getInstance() + ._Persistence.getLocalStorage(); - expect(localStorageData).to.include.keys(['gs', 'cu', testMPID]); - - const props = [ - 'ie', - 'sa', - 'ss', - 'dt', - 'les', - 'av', - 'cgid', - 'das', - 'sid', - 'c', - 'mpid', - 'cp', - ]; - - props.forEach(prop => { - expect(localStorageData[testMPID]).to.not.have.property(prop); - }); + expect(localStorageData).to.include.keys(['gs', 'cu', testMPID]); + + const props = [ + 'ie', + 'sa', + 'ss', + 'dt', + 'les', + 'av', + 'cgid', + 'das', + 'sid', + 'c', + 'mpid', + 'cp', + ]; + + props.forEach((prop) => { + expect(localStorageData[testMPID]).to.not.have.property(prop); + }); - expect(cookieData).to.not.be.ok; + expect(cookieData).to.not.be.ok; - done(); + done(); }); }); - it('puts data into cookies when updating persistence with useCookieStorage = true', done => { + it('puts data into cookies when updating persistence with useCookieStorage = true', (done) => { let cookieData: Partial; let localStorageData: Partial; mParticle.config.useCookieStorage = true; mParticle.init(apiKey, mParticle.config); - waitForCondition(hasIdentifyReturned) - .then(() => { - - cookieData = findCookie(); - expect(cookieData).to.include.keys('gs', 'cu', testMPID); - localStorageData = mParticle - .getInstance() - ._Persistence.getLocalStorage(); + waitForCondition(hasIdentifyReturned).then(() => { + cookieData = findCookie(); + expect(cookieData).to.include.keys('gs', 'cu', testMPID); + localStorageData = mParticle + .getInstance() + ._Persistence.getLocalStorage(); - const props = [ - 'ie', - 'sa', - 'ss', - 'dt', - 'les', - 'av', - 'cgid', - 'das', - 'sid', - 'c', - 'mpid', - 'cp', - ]; - props.forEach(function(prop) { - cookieData[testMPID].should.not.have.property(prop); - }); + const props = [ + 'ie', + 'sa', + 'ss', + 'dt', + 'les', + 'av', + 'cgid', + 'das', + 'sid', + 'c', + 'mpid', + 'cp', + ]; + props.forEach(function (prop) { + cookieData[testMPID].should.not.have.property(prop); + }); - expect(localStorageData).to.not.be.ok; + expect(localStorageData).to.not.be.ok; - done(); + done(); }); }); - it('puts data into localStorage when updating persistence with useCookieStorage = false', done => { + it('puts data into localStorage when updating persistence with useCookieStorage = false', (done) => { let cookieData: Partial; let localStorageData: Partial; // Flush out anything in expire before updating in order to silo testing persistence.update() // mParticle.config.useCookieStorage = false; mParticle.init(apiKey, mParticle.config); - waitForCondition(hasIdentifyReturned) - .then(() => { - - localStorageData = getLocalStorage(); - cookieData = findCookie(); - - expect(localStorageData).to.have.include.keys('gs', 'cu', testMPID); - - const props = [ - 'ie', - 'sa', - 'ss', - 'dt', - 'les', - 'av', - 'cgid', - 'das', - 'sid', - 'c', - 'mpid', - 'cp', - ]; - props.forEach(function(prop) { - localStorageData[testMPID].should.not.have.property(prop); - }); + waitForCondition(hasIdentifyReturned).then(() => { + localStorageData = getLocalStorage(); + cookieData = findCookie(); + + expect(localStorageData).to.have.include.keys('gs', 'cu', testMPID); + + const props = [ + 'ie', + 'sa', + 'ss', + 'dt', + 'les', + 'av', + 'cgid', + 'das', + 'sid', + 'c', + 'mpid', + 'cp', + ]; + props.forEach(function (prop) { + localStorageData[testMPID].should.not.have.property(prop); + }); - expect(cookieData).to.not.be.ok; + expect(cookieData).to.not.be.ok; - done(); + done(); }); }); - it('should revert to cookie storage if localStorage is not available and useCookieStorage is set to false', done => { + it('should revert to cookie storage if localStorage is not available and useCookieStorage is set to false', (done) => { mParticle._resetForTests(MPConfig); - mParticle.getInstance()._Persistence.determineLocalStorageAvailability = () => { - return false; - }; + mParticle.getInstance()._Persistence.determineLocalStorageAvailability = + () => { + return false; + }; mParticle.init(apiKey, mParticle.config); - waitForCondition(hasIdentifyReturned) - .then(() => { - - mParticle - .getInstance() - .Identity.getCurrentUser() - .setUserAttribute('gender', 'male'); + waitForCondition(hasIdentifyReturned).then(() => { + mParticle + .getInstance() + .Identity.getCurrentUser() + .setUserAttribute('gender', 'male'); - const cookieData = findCookie(); - cookieData[testMPID].ua.should.have.property('gender', 'male'); + const cookieData = findCookie(); + cookieData[testMPID].ua.should.have.property('gender', 'male'); - mParticle.getInstance()._Persistence.determineLocalStorageAvailability = () => { - return true; - }; + mParticle.getInstance()._Persistence.determineLocalStorageAvailability = + () => { + return true; + }; - done(); + done(); }); }); - it('should set certain attributes onto global localStorage, while setting user specific to the MPID', done => { + it('should set certain attributes onto global localStorage, while setting user specific to the MPID', (done) => { mParticle.config.useCookieStorage = false; mParticle.init(apiKey, mParticle.config); - waitForCondition(hasIdentifyReturned) - .then(() => { - mParticle - .getInstance() - .Identity.getCurrentUser() - .setUserAttribute('gender', 'male'); - mParticle.setIntegrationAttribute(128, { MCID: 'abcedfg' }); - const data = getLocalStorage(); - - data.cu.should.equal(testMPID); - data.gs.should.have.properties([ - 'sid', - 'ie', - 'dt', - 'cgid', - 'das', - 'les', - 'ia', - ]); - data.testMPID.ua.should.have.property('gender', 'male'); + waitForCondition(hasIdentifyReturned).then(() => { + mParticle + .getInstance() + .Identity.getCurrentUser() + .setUserAttribute('gender', 'male'); + mParticle.setIntegrationAttribute(128, { MCID: 'abcedfg' }); + const data = getLocalStorage(); + + data.cu.should.equal(testMPID); + data.gs.should.have.properties([ + 'sid', + 'ie', + 'dt', + 'cgid', + 'das', + 'les', + 'ia', + ]); + data.testMPID.ua.should.have.property('gender', 'male'); - done(); + done(); }); }); - it('should save integration attributes properly on a page refresh', done => { + it('should save integration attributes properly on a page refresh', (done) => { mParticle.setIntegrationAttribute(128, { MCID: 'abcedfg' }); mParticle.init(apiKey, mParticle.config); - waitForCondition(hasIdentifyReturned) - .then(() => { - - mParticle.logEvent('Test Event'); - const testEvent = findBatch(fetchMock.calls(), 'Test Event'); - testEvent.integration_attributes.should.have.property('128'); - testEvent.integration_attributes['128'].should.have.property('MCID', 'abcedfg'); + waitForCondition(hasIdentifyReturned).then(() => { + mParticle.logEvent('Test Event'); + const testEvent = findBatch(fetchMock.calls(), 'Test Event'); + testEvent.integration_attributes.should.have.property('128'); + testEvent.integration_attributes['128'].should.have.property( + 'MCID', + 'abcedfg', + ); - done(); + done(); }); }); - it('should set certain attributes onto global cookies, while setting user specific to the MPID', done => { + it('should set certain attributes onto global cookies, while setting user specific to the MPID', (done) => { mParticle.config.useCookieStorage = true; mParticle.init(apiKey, mParticle.config); - waitForCondition(hasIdentifyReturned) - .then(() => { - mParticle - .getInstance() - .Identity.getCurrentUser() - .setUserAttribute('gender', 'male'); - - const data = findCookie(); - data.cu.should.equal(testMPID); - - data.gs.should.have.properties([ - 'sid', - 'ie', - 'dt', - 'cgid', - 'das', - 'les', - ]); - data.testMPID.ua.should.have.property('gender', 'male'); + waitForCondition(hasIdentifyReturned).then(() => { + mParticle + .getInstance() + .Identity.getCurrentUser() + .setUserAttribute('gender', 'male'); + + const data = findCookie(); + data.cu.should.equal(testMPID); + + data.gs.should.have.properties([ + 'sid', + 'ie', + 'dt', + 'cgid', + 'das', + 'les', + ]); + data.testMPID.ua.should.have.property('gender', 'male'); - done(); + done(); }); }); - it('should add new MPID to cookies when returned MPID does not match anything in cookies, and have empty UI and UA', done => { + it('should add new MPID to cookies when returned MPID does not match anything in cookies, and have empty UI and UA', (done) => { mParticle._resetForTests(MPConfig); mParticle.init(apiKey, mParticle.config); - waitForCondition(hasIdentifyReturned) - .then(() => { - fetchMockSuccess(urls.login, { - mpid: 'mpid1', is_logged_in: false - }); - - const user1 = { userIdentities: { customerid: 'customerid1' } }; - - mParticle.Identity.login(user1); - waitForCondition(() => { - return ( - mParticle.Identity.getCurrentUser()?.getMPID() === 'mpid1' - ); - }) - .then(() => { - - const user1Result = mParticle - .getInstance() - .Identity.getCurrentUser() - .getUserIdentities(); - user1Result.userIdentities.customerid.should.equal('customerid1'); - - fetchMockSuccess(urls.logout, { - mpid: 'mpid2', is_logged_in: false - }); - - mParticle.Identity.logout(); - waitForCondition(() => { - return ( - mParticle.Identity.getCurrentUser()?.getMPID() === 'mpid2' - ); - }) - .then(() => { + waitForCondition(hasIdentifyReturned).then(() => { + fetchMockSuccess(urls.login, { + mpid: 'mpid1', + is_logged_in: false, + }); - const user2Result = mParticle.getInstance().Identity.getCurrentUser(); - Object.keys( - user2Result.getUserIdentities().userIdentities - ).length.should.equal(0); + const user1 = { userIdentities: { customerid: 'customerid1' } }; - const localStorageData = mParticle - .getInstance() - ._Persistence.getLocalStorage(); + mParticle.Identity.login(user1); + waitForCondition(() => { + return ( + mParticle.Identity.getCurrentUser()?.getMPID() === 'mpid1' + ); + }).then(() => { + const user1Result = mParticle + .getInstance() + .Identity.getCurrentUser() + .getUserIdentities(); + user1Result.userIdentities.customerid.should.equal( + 'customerid1', + ); - localStorageData.cu.should.equal('mpid2'); - localStorageData.testMPID.should.not.have.property('ui'); - localStorageData.mpid1.ui[1].should.equal('customerid1'); - localStorageData.mpid2.should.not.have.property('ui'); + fetchMockSuccess(urls.logout, { + mpid: 'mpid2', + is_logged_in: false, + }); - done(); - }); - }); - }); + mParticle.Identity.logout(); + waitForCondition(() => { + return ( + mParticle.Identity.getCurrentUser()?.getMPID() === + 'mpid2' + ); + }).then(() => { + const user2Result = mParticle + .getInstance() + .Identity.getCurrentUser(); + Object.keys( + user2Result.getUserIdentities().userIdentities, + ).length.should.equal(0); + + const localStorageData = mParticle + .getInstance() + ._Persistence.getLocalStorage(); + + localStorageData.cu.should.equal('mpid2'); + localStorageData.testMPID.should.not.have.property('ui'); + localStorageData.mpid1.ui[1].should.equal('customerid1'); + localStorageData.mpid2.should.not.have.property('ui'); + + done(); + }); + }); + }); }); - it('should have the same currentUserMPID as the last browser session when a reload occurs and no identityRequest is provided', done => { + it('should have the same currentUserMPID as the last browser session when a reload occurs and no identityRequest is provided', (done) => { const user1 = { userIdentities: { customerid: '1', @@ -621,483 +622,507 @@ describe('persistence', () => { mParticle.init(apiKey, mParticle.config); - waitForCondition(hasIdentifyReturned) - .then(() => { - - const data = mParticle.getInstance()._Persistence.getLocalStorage(); - data.cu.should.equal(testMPID); + waitForCondition(hasIdentifyReturned).then(() => { + const data = mParticle.getInstance()._Persistence.getLocalStorage(); + data.cu.should.equal(testMPID); - fetchMockSuccess(urls.login, { - mpid: 'mpid1', is_logged_in: false - }); - - mParticle.Identity.login(user1); - waitForCondition(() => { - return ( - mParticle.Identity.getCurrentUser()?.getMPID() === 'mpid1' - ); - }) - .then(() => { - - const user1Data = mParticle - .getInstance() - ._Persistence.getLocalStorage(); - - user1Data.cu.should.equal('mpid1'); + fetchMockSuccess(urls.login, { + mpid: 'mpid1', + is_logged_in: false, + }); - fetchMockSuccess(urls.login, { - mpid: 'mpid2', is_logged_in: false - }); + mParticle.Identity.login(user1); + waitForCondition(() => { + return ( + mParticle.Identity.getCurrentUser()?.getMPID() === 'mpid1' + ); + }).then(() => { + const user1Data = mParticle + .getInstance() + ._Persistence.getLocalStorage(); - mParticle.Identity.login(user2); + user1Data.cu.should.equal('mpid1'); - waitForCondition(() => { - return ( - mParticle.Identity.getCurrentUser()?.getMPID() === 'mpid2' - ); - }) - .then(() => { - - const user2Data = mParticle - .getInstance() - ._Persistence.getLocalStorage(); + fetchMockSuccess(urls.login, { + mpid: 'mpid2', + is_logged_in: false, + }); - user2Data.cu.should.equal('mpid2'); + mParticle.Identity.login(user2); - fetchMockSuccess(urls.login, { - mpid: 'mpid3', is_logged_in: false + waitForCondition(() => { + return ( + mParticle.Identity.getCurrentUser()?.getMPID() === + 'mpid2' + ); + }).then(() => { + const user2Data = mParticle + .getInstance() + ._Persistence.getLocalStorage(); + + user2Data.cu.should.equal('mpid2'); + + fetchMockSuccess(urls.login, { + mpid: 'mpid3', + is_logged_in: false, + }); + + mParticle.Identity.login(user3); + waitForCondition(() => { + return ( + mParticle.Identity.getCurrentUser()?.getMPID() === + 'mpid3' + ); + }).then(() => { + const user3data = mParticle + .getInstance() + ._Persistence.getLocalStorage(); + user3data.cu.should.equal('mpid3'); + + mParticle.init(apiKey, mParticle.config); + const data3 = mParticle + .getInstance() + ._Persistence.getLocalStorage(); + data3.cu.should.equal('mpid3'); + + done(); + }); + }); + }); }); - - mParticle.Identity.login(user3); - waitForCondition(() => { - return ( - mParticle.Identity.getCurrentUser()?.getMPID() === 'mpid3' - ); - }) - .then(() => { - - const user3data = mParticle - .getInstance() - ._Persistence.getLocalStorage(); - user3data.cu.should.equal('mpid3'); - - mParticle.init(apiKey, mParticle.config); - const data3 = mParticle.getInstance()._Persistence.getLocalStorage(); - data3.cu.should.equal('mpid3'); - - done(); - }) - }); - }); - }); }); - it('should transfer user attributes and revert to user identities properly', done => { + it('should transfer user attributes and revert to user identities properly', (done) => { const user1 = { userIdentities: { customerid: 'customerid1' } }; const user2 = { userIdentities: { customerid: 'customerid2' } }; mParticle.init(apiKey, mParticle.config); - waitForCondition(hasIdentifyReturned) - .then(() => { + waitForCondition(hasIdentifyReturned).then(() => { + // set user attributes on testMPID + mParticle + .getInstance() + .Identity.getCurrentUser() + .setUserAttribute('test1', 'test1'); - // set user attributes on testMPID - mParticle - .getInstance() - .Identity.getCurrentUser() - .setUserAttribute('test1', 'test1'); + const data = getLocalStorage(); - const data = getLocalStorage(); + data.cu.should.equal(testMPID); + data.testMPID.ua.should.have.property('test1', 'test1'); - data.cu.should.equal(testMPID); - data.testMPID.ua.should.have.property('test1', 'test1'); - - fetchMockSuccess(urls.login, { - mpid: 'mpid1', is_logged_in: false - }); + fetchMockSuccess(urls.login, { + mpid: 'mpid1', + is_logged_in: false, + }); - fetchMockSuccess('https://identity.mparticle.com/v1/mpid1/modify', { - mpid: 'mpid1', is_logged_in: false + fetchMockSuccess('https://identity.mparticle.com/v1/mpid1/modify', { + mpid: 'mpid1', + is_logged_in: false, + }); + + mParticle.Identity.login(user1); + waitForCondition(() => { + return ( + mParticle.Identity.getCurrentUser()?.getMPID() === 'mpid1' + ); + }).then(() => { + // modify user1's identities + mParticle.Identity.modify({ + userIdentities: { email: 'email@test.com' }, + }); + waitForCondition(() => { + return ( + window.mParticle.getInstance()?._Store + ?.identityCallInFlight === false + ); + }).then(() => { + // set user attributes on mpid1 + mParticle + .getInstance() + .Identity.getCurrentUser() + .setUserAttribute('test2', 'test2'); + const user1Data = mParticle + .getInstance() + ._Persistence.getLocalStorage(); + user1Data.cu.should.equal('mpid1'); + user1Data.mpid1.ua.should.have.property('test2', 'test2'); + user1Data.mpid1.ui.should.have.property( + '7', + 'email@test.com', + ); + user1Data.mpid1.ui.should.have.property('1', 'customerid1'); + + fetchMockSuccess(urls.login, { + mpid: 'mpid2', + is_logged_in: false, + }); + + mParticle.Identity.login(user2); + waitForCondition(() => { + return ( + mParticle.Identity.getCurrentUser()?.getMPID() === + 'mpid2' + ); + }).then(() => { + // set user attributes on user 2 + mParticle + .getInstance() + .Identity.getCurrentUser() + .setUserAttribute('test3', 'test3'); + const user2Data = mParticle + .getInstance() + ._Persistence.getLocalStorage(); + + user2Data.cu.should.equal('mpid2'); + user2Data.mpid2.ui.should.have.property( + '1', + 'customerid2', + ); + user2Data.mpid2.ua.should.have.property( + 'test3', + 'test3', + ); + + fetchMockSuccess(urls.login, { + mpid: 'mpid1', + is_logged_in: false, + }); + + mParticle.Identity.login(user1); + waitForCondition(() => { + return ( + mParticle.Identity.getCurrentUser()?.getMPID() === + 'mpid1' + ); + }).then(() => { + const user1RelogInData = mParticle + .getInstance() + ._Persistence.getLocalStorage(); + + user1RelogInData.cu.should.equal('mpid1'); + user1RelogInData.mpid1.ui.should.have.property( + '1', + 'customerid1', + ); + user1RelogInData.mpid1.ui.should.have.property( + '7', + 'email@test.com', + ); + + Object.keys( + user1RelogInData.mpid1.ui, + ).length.should.equal(2); + user1RelogInData.mpid1.ua.should.have.property( + 'test2', + 'test2', + ); + + done(); + }); + }); + }); + }); }); - + }); - mParticle.Identity.login(user1); - waitForCondition(() => { - return ( - mParticle.Identity.getCurrentUser()?.getMPID() === 'mpid1' + it('should remove MPID as keys if the cookie size is beyond the setting', (done) => { + mParticle.init(apiKey, window.mParticle.config); + waitForCondition(hasIdentifyReturned).then(() => { + mParticle.config.maxCookieSize = 700; + + const cookies: IPersistenceMinified = { + gs: { + csm: ['mpid1', 'mpid2', 'mpid3'], + sid: 'abcd', + ie: true, + dt: apiKey, + cgid: 'cgid1', + das: 'das1', + } as IGlobalStoreV2MinifiedKeys, + cu: 'mpid3', + l: false, + mpid1: { + ua: { + gender: 'female', + age: 29, + height: '65', + color: 'blue', + id: 'abcdefghijklmnopqrstuvwxyz', + }, + ui: { 1: 'customerid123', 2: 'facebookid123' }, + }, + mpid2: { + ua: { gender: 'male', age: 20, height: '68', color: 'red' }, + ui: { + 1: 'customerid234', + 2: 'facebookid234', + id: 'abcdefghijklmnopqrstuvwxyz', + }, + }, + mpid3: { + ua: { gender: 'male', age: 20, height: '68', color: 'red' }, + ui: { + 1: 'customerid234', + 2: 'facebookid234', + id: 'abcdefghijklmnopqrstuvwxyz', + }, + }, + }; + const expires = new Date( + new Date().getTime() + 365 * 24 * 60 * 60 * 1000, + ).toUTCString(); + const cookiesWithExpiration = mParticle + .getInstance() + ._Persistence.reduceAndEncodePersistence( + cookies, + expires, + 'testDomain', + mParticle.config.maxCookieSize, + ); + const cookiesWithoutExpiration = cookiesWithExpiration.slice( + 0, + cookiesWithExpiration.indexOf(';expires'), ); - }) - .then(() => { - - // modify user1's identities - mParticle.Identity.modify({ - userIdentities: { email: 'email@test.com' }, - }); - waitForCondition(() => { - return ( - window.mParticle.getInstance()?._Store?.identityCallInFlight === false + const cookiesResult = JSON.parse( + mParticle + .getInstance() + // TODO: Refactor or rename this to highlight that it is + // a string function + ._Persistence.decodePersistence(cookiesWithoutExpiration), ); - }) - .then(() => { - - // set user attributes on mpid1 - mParticle - .getInstance() - .Identity.getCurrentUser() - .setUserAttribute('test2', 'test2'); - const user1Data = mParticle - .getInstance() - ._Persistence.getLocalStorage(); - user1Data.cu.should.equal('mpid1'); - user1Data.mpid1.ua.should.have.property('test2', 'test2'); - user1Data.mpid1.ui.should.have.property('7', 'email@test.com'); - user1Data.mpid1.ui.should.have.property('1', 'customerid1'); + expect(cookiesResult['mpid1']).to.not.be.ok; + expect(cookiesResult['mpid2']).be.ok; + expect(cookiesResult['mpid3']).be.ok; + cookiesResult.gs.csm.length.should.equal(3); + cookiesResult.gs.csm[0].should.equal('mpid1'); + cookiesResult.gs.csm[1].should.equal('mpid2'); + cookiesResult.gs.csm[2].should.equal('mpid3'); - fetchMockSuccess(urls.login, { - mpid: 'mpid2', is_logged_in: false + done(); }); + }); - mParticle.Identity.login(user2); - waitForCondition(() => { - return ( - mParticle.Identity.getCurrentUser()?.getMPID() === 'mpid2' - ); - }) - .then(() => { - - // set user attributes on user 2 - mParticle - .getInstance() - .Identity.getCurrentUser() - .setUserAttribute('test3', 'test3'); - const user2Data = mParticle - .getInstance() - ._Persistence.getLocalStorage(); + it('integration test - will change the order of the CSM when a previous MPID logs in again', (done) => { + mParticle.config.useCookieStorage = true; + mParticle.config.maxCookieSize = 1000; + mParticle.init(apiKey, mParticle.config); + waitForCondition(hasIdentifyReturned).then(() => { + const userIdentities1 = { + userIdentities: { + customerid: 'foo1', + }, + }; - user2Data.cu.should.equal('mpid2'); - user2Data.mpid2.ui.should.have.property('1', 'customerid2'); - user2Data.mpid2.ua.should.have.property('test3', 'test3'); + fetchMockSuccess(urls.login, { + mpid: 'MPID1', + is_logged_in: false, + }); - fetchMockSuccess(urls.login, { - mpid: 'mpid1', is_logged_in: false - }); - - mParticle.Identity.login(user1); - waitForCondition(() => { - return ( - mParticle.Identity.getCurrentUser()?.getMPID() === 'mpid1' - ); - }) - .then(() => { - const user1RelogInData = mParticle - .getInstance() - ._Persistence.getLocalStorage(); - - user1RelogInData.cu.should.equal('mpid1'); - user1RelogInData.mpid1.ui.should.have.property('1', 'customerid1'); - user1RelogInData.mpid1.ui.should.have.property('7', 'email@test.com'); - - Object.keys(user1RelogInData.mpid1.ui).length.should.equal(2); - user1RelogInData.mpid1.ua.should.have.property('test2', 'test2'); - - done(); - }); - }); - }); - }); - }); - }); - - it('should remove MPID as keys if the cookie size is beyond the setting', done => { - mParticle.init(apiKey, window.mParticle.config); - waitForCondition(hasIdentifyReturned) - .then(() => { - mParticle.config.maxCookieSize = 700; - - const cookies: IPersistenceMinified = { - gs: { - csm: ['mpid1', 'mpid2', 'mpid3'], - sid: 'abcd', - ie: true, - dt: apiKey, - cgid: 'cgid1', - das: 'das1', - } as IGlobalStoreV2MinifiedKeys, - cu: 'mpid3', - l: false, - mpid1: { - ua: { - gender: 'female', - age: 29, - height: '65', - color: 'blue', - id: 'abcdefghijklmnopqrstuvwxyz', - }, - ui: { 1: 'customerid123', 2: 'facebookid123' }, - }, - mpid2: { - ua: { gender: 'male', age: 20, height: '68', color: 'red' }, - ui: { - 1: 'customerid234', - 2: 'facebookid234', - id: 'abcdefghijklmnopqrstuvwxyz', - }, - }, - mpid3: { - ua: { gender: 'male', age: 20, height: '68', color: 'red' }, - ui: { - 1: 'customerid234', - 2: 'facebookid234', - id: 'abcdefghijklmnopqrstuvwxyz', - }, - }, - }; - const expires = new Date( - new Date().getTime() + 365 * 24 * 60 * 60 * 1000 - ).toUTCString(); - const cookiesWithExpiration = mParticle - .getInstance() - ._Persistence.reduceAndEncodePersistence( - cookies, - expires, - 'testDomain', - mParticle.config.maxCookieSize - ); - const cookiesWithoutExpiration = cookiesWithExpiration.slice( - 0, - cookiesWithExpiration.indexOf(';expires') - ); - const cookiesResult = JSON.parse( - mParticle - .getInstance() - // TODO: Refactor or rename this to highlight that it is - // a string function - ._Persistence.decodePersistence(cookiesWithoutExpiration) - ); - expect(cookiesResult['mpid1']).to.not.be.ok; - expect(cookiesResult['mpid2']).be.ok; - expect(cookiesResult['mpid3']).be.ok; - cookiesResult.gs.csm.length.should.equal(3); - cookiesResult.gs.csm[0].should.equal('mpid1'); - cookiesResult.gs.csm[1].should.equal('mpid2'); - cookiesResult.gs.csm[2].should.equal('mpid3'); - - done(); - }); - }); - - it('integration test - will change the order of the CSM when a previous MPID logs in again', done => { - mParticle.config.useCookieStorage = true; - mParticle.config.maxCookieSize = 1000; - mParticle.init(apiKey, mParticle.config); - waitForCondition(hasIdentifyReturned) - .then(() => { - const userIdentities1 = { - userIdentities: { - customerid: 'foo1' - } - } - - fetchMockSuccess(urls.login, { - mpid: 'MPID1', is_logged_in: false - }); - - mParticle.Identity.login(userIdentities1); - waitForCondition(() => { - return ( - mParticle.Identity.getCurrentUser()?.getMPID() === 'MPID1' - ); - }) - .then(() => { - let cookieData: Partial = findCookie(); - cookieData.gs.csm[0].should.be.equal('testMPID'); - cookieData.gs.csm[1].should.be.equal('MPID1'); - - fetchMockSuccess(urls.login, { - mpid: 'MPID2', is_logged_in: false - }); - - const userIdentities2 = { - userIdentities: { - customerid: 'foo2', - }, - }; - - mParticle.Identity.login(userIdentities2); - waitForCondition(() => { - return ( - mParticle.Identity.getCurrentUser()?.getMPID() === 'MPID2' - ); - }) - .then(() => { - cookieData = findCookie(); - cookieData.gs.csm[0].should.be.equal('testMPID'); - cookieData.gs.csm[1].should.be.equal('MPID1'); - cookieData.gs.csm[2].should.be.equal('MPID2'); - - fetchMockSuccess(urls.login, { - mpid: 'testMPID', is_logged_in: true - }); - - const userIdentities3 = { - userIdentities: { - customerid: 'foo3', - }, - }; - - mParticle.Identity.login(userIdentities3); + mParticle.Identity.login(userIdentities1); + waitForCondition(() => { + return ( + mParticle.Identity.getCurrentUser()?.getMPID() === 'MPID1' + ); + }).then(() => { + let cookieData: Partial = findCookie(); + cookieData.gs.csm[0].should.be.equal('testMPID'); + cookieData.gs.csm[1].should.be.equal('MPID1'); + + fetchMockSuccess(urls.login, { + mpid: 'MPID2', + is_logged_in: false, + }); + + const userIdentities2 = { + userIdentities: { + customerid: 'foo2', + }, + }; + + mParticle.Identity.login(userIdentities2); waitForCondition(() => { - return ( - mParticle.Identity.getCurrentUser()?.getMPID() === 'testMPID' - ); - }) - .then(() => { - - cookieData = findCookie(); - cookieData.gs.csm[0].should.be.equal('MPID1'); - cookieData.gs.csm[1].should.be.equal('MPID2'); - cookieData.gs.csm[2].should.be.equal('testMPID'); - - done(); - }); - }); - }); - }); + return ( + mParticle.Identity.getCurrentUser()?.getMPID() === + 'MPID2' + ); + }).then(() => { + cookieData = findCookie(); + cookieData.gs.csm[0].should.be.equal('testMPID'); + cookieData.gs.csm[1].should.be.equal('MPID1'); + cookieData.gs.csm[2].should.be.equal('MPID2'); + + fetchMockSuccess(urls.login, { + mpid: 'testMPID', + is_logged_in: true, + }); + + const userIdentities3 = { + userIdentities: { + customerid: 'foo3', + }, + }; + + mParticle.Identity.login(userIdentities3); + waitForCondition(() => { + return ( + mParticle.Identity.getCurrentUser()?.getMPID() === + 'testMPID' + ); + }).then(() => { + cookieData = findCookie(); + cookieData.gs.csm[0].should.be.equal('MPID1'); + cookieData.gs.csm[1].should.be.equal('MPID2'); + cookieData.gs.csm[2].should.be.equal('testMPID'); + + done(); + }); + }); + }); + }); }); - it('integration test - should remove a previous MPID as a key from cookies if new user attribute added and exceeds the size of the max cookie size', done => { + it('integration test - should remove a previous MPID as a key from cookies if new user attribute added and exceeds the size of the max cookie size', (done) => { mParticle.config.useCookieStorage = true; mParticle.config.maxCookieSize = 700; mParticle.init(apiKey, mParticle.config); - waitForCondition(hasIdentifyReturned) - .then(() => { - - mParticle - .getInstance() - .Identity.getCurrentUser() - .setUserAttribute('gender', 'female'); - mParticle - .getInstance() - .Identity.getCurrentUser() - .setUserAttribute('age', 30); - mParticle - .getInstance() - .Identity.getCurrentUser() - .setUserAttribute('height', '68'); - mParticle - .getInstance() - .Identity.getCurrentUser() - .setUserAttribute('color', 'blue'); - mParticle - .getInstance() - .Identity.getCurrentUser() - .setUserAttribute('id', 'id1'); + waitForCondition(hasIdentifyReturned).then(() => { + mParticle + .getInstance() + .Identity.getCurrentUser() + .setUserAttribute('gender', 'female'); + mParticle + .getInstance() + .Identity.getCurrentUser() + .setUserAttribute('age', 30); + mParticle + .getInstance() + .Identity.getCurrentUser() + .setUserAttribute('height', '68'); + mParticle + .getInstance() + .Identity.getCurrentUser() + .setUserAttribute('color', 'blue'); + mParticle + .getInstance() + .Identity.getCurrentUser() + .setUserAttribute('id', 'id1'); - fetchMockSuccess(urls.login, { - mpid: 'MPID1', is_logged_in: false - }); + fetchMockSuccess(urls.login, { + mpid: 'MPID1', + is_logged_in: false, + }); - const userIdentities1 = { - userIdentities: { - customerid: 'foo1', - }, - }; + const userIdentities1 = { + userIdentities: { + customerid: 'foo1', + }, + }; - mParticle.Identity.login(userIdentities1); + mParticle.Identity.login(userIdentities1); + waitForCondition(() => { + return ( + mParticle.Identity.getCurrentUser()?.getMPID() === 'MPID1' + ); + }).then(() => { + mParticle + .getInstance() + .Identity.getCurrentUser() + .setUserAttribute('gender', 'male'); + mParticle + .getInstance() + .Identity.getCurrentUser() + .setUserAttribute('age', 30); + mParticle + .getInstance() + .Identity.getCurrentUser() + .setUserAttribute('height', '60'); + mParticle + .getInstance() + .Identity.getCurrentUser() + .setUserAttribute('color', 'green'); + mParticle + .getInstance() + .Identity.getCurrentUser() + .setUserAttribute('id', 'id2'); + + let cookieData: Partial = findCookie(); + cookieData.gs.csm[0].should.equal('testMPID'); + cookieData.gs.csm[1].should.equal('MPID1'); + + fetchMockSuccess(urls.login, { + mpid: 'MPID2', + is_logged_in: false, + }); + + const userIdentities2 = { + userIdentities: { + customerid: 'foo2', + }, + }; + + mParticle.Identity.login(userIdentities2); waitForCondition(() => { - return ( - mParticle.Identity.getCurrentUser()?.getMPID() === 'MPID1' - ); - }) - .then(() => { - - mParticle - .getInstance() - .Identity.getCurrentUser() - .setUserAttribute('gender', 'male'); - mParticle - .getInstance() - .Identity.getCurrentUser() - .setUserAttribute('age', 30); - mParticle - .getInstance() - .Identity.getCurrentUser() - .setUserAttribute('height', '60'); - mParticle - .getInstance() - .Identity.getCurrentUser() - .setUserAttribute('color', 'green'); - mParticle - .getInstance() - .Identity.getCurrentUser() - .setUserAttribute('id', 'id2'); - - let cookieData: Partial = findCookie(); - cookieData.gs.csm[0].should.equal('testMPID'); - cookieData.gs.csm[1].should.equal('MPID1'); + return ( + mParticle.Identity.getCurrentUser()?.getMPID() === + 'MPID2' + ); + }).then(() => { + mParticle + .getInstance() + .Identity.getCurrentUser() + .setUserAttribute('gender', 'female'); + mParticle + .getInstance() + .Identity.getCurrentUser() + .setUserAttribute('age', 45); + mParticle + .getInstance() + .Identity.getCurrentUser() + .setUserAttribute('height', '80'); + mParticle + .getInstance() + .Identity.getCurrentUser() + .setUserAttribute('color', 'green'); + + //this last one puts us over the maxcookiesize threshold and removes 'testMPID' from cookie + mParticle + .getInstance() + .Identity.getCurrentUser() + .setUserAttribute('id', 'id3'); + + cookieData = findCookie(); + + expect(cookieData['testMPID']).to.not.be.ok; + cookieData['MPID1'].ua.should.have.property('id', 'id2'); + cookieData['MPID1'].ua.should.have.property( + 'gender', + 'male', + ); + cookieData['MPID1'].ua.should.have.property('age', 30); + cookieData['MPID1'].ua.should.have.property('height', '60'); + cookieData['MPID1'].ua.should.have.property( + 'color', + 'green', + ); + cookieData['MPID2'].ua.should.have.property('id', 'id3'); + cookieData['MPID2'].ua.should.have.property( + 'gender', + 'female', + ); + cookieData['MPID2'].ua.should.have.property('age', 45); + cookieData['MPID2'].ua.should.have.property('height', '80'); + cookieData['MPID2'].ua.should.have.property( + 'color', + 'green', + ); - fetchMockSuccess(urls.login, { - mpid: 'MPID2', is_logged_in: false + done(); + }); + }); }); - - const userIdentities2 = { - userIdentities: { - customerid: 'foo2', - }, - }; - - mParticle.Identity.login(userIdentities2); - waitForCondition(() => { - return ( - mParticle.Identity.getCurrentUser()?.getMPID() === 'MPID2' - ); - }) - .then(() => { - - mParticle - .getInstance() - .Identity.getCurrentUser() - .setUserAttribute('gender', 'female'); - mParticle - .getInstance() - .Identity.getCurrentUser() - .setUserAttribute('age', 45); - mParticle - .getInstance() - .Identity.getCurrentUser() - .setUserAttribute('height', '80'); - mParticle - .getInstance() - .Identity.getCurrentUser() - .setUserAttribute('color', 'green'); - - //this last one puts us over the maxcookiesize threshold and removes 'testMPID' from cookie - mParticle - .getInstance() - .Identity.getCurrentUser() - .setUserAttribute('id', 'id3'); - - cookieData = findCookie(); - - expect(cookieData['testMPID']).to.not.be.ok; - cookieData['MPID1'].ua.should.have.property('id', 'id2'); - cookieData['MPID1'].ua.should.have.property('gender', 'male'); - cookieData['MPID1'].ua.should.have.property('age', 30); - cookieData['MPID1'].ua.should.have.property('height', '60'); - cookieData['MPID1'].ua.should.have.property('color', 'green'); - cookieData['MPID2'].ua.should.have.property('id', 'id3'); - cookieData['MPID2'].ua.should.have.property('gender', 'female'); - cookieData['MPID2'].ua.should.have.property('age', 45); - cookieData['MPID2'].ua.should.have.property('height', '80'); - cookieData['MPID2'].ua.should.have.property('color', 'green'); - - done(); - }); - }); - }); }); - it('should remove a random MPID from storage if there is a new session and there are no other MPIDs in currentSessionMPIDs except for the currentUser mpid', done => { + it('should remove a random MPID from storage if there is a new session and there are no other MPIDs in currentSessionMPIDs except for the currentUser mpid', (done) => { mParticle.config.maxCookieSize = 400; mParticle.init(apiKey, window.mParticle.config); @@ -1142,7 +1167,7 @@ describe('persistence', () => { }; const expires = new Date( - new Date().getTime() + 365 * 24 * 60 * 60 * 1000 + new Date().getTime() + 365 * 24 * 60 * 60 * 1000, ).toString(); const cookiesWithExpiration = mParticle @@ -1151,16 +1176,16 @@ describe('persistence', () => { cookies, expires, 'testDomain', - mParticle.config.maxCookieSize + mParticle.config.maxCookieSize, ); const cookiesWithoutExpiration = cookiesWithExpiration.slice( 0, - cookiesWithExpiration.indexOf(';expires') + cookiesWithExpiration.indexOf(';expires'), ); const cookiesResult = JSON.parse( mParticle .getInstance() - ._Persistence.decodePersistence(cookiesWithoutExpiration) + ._Persistence.decodePersistence(cookiesWithoutExpiration), ); expect(cookiesResult['mpid1']).to.not.be.ok; @@ -1175,552 +1200,557 @@ describe('persistence', () => { done(); }); - it('integration test - should remove a random MPID from storage if there is a new session and there are no MPIDs in currentSessionMPIDs', done => { + it('integration test - should remove a random MPID from storage if there is a new session and there are no MPIDs in currentSessionMPIDs', (done) => { mParticle.config.useCookieStorage = true; mParticle.config.maxCookieSize = 600; mParticle.init(apiKey, mParticle.config); - waitForCondition(hasIdentifyReturned) - .then(() => { - - mParticle - .getInstance() - .Identity.getCurrentUser() - .setUserAttribute('gender', 'female'); - mParticle - .getInstance() - .Identity.getCurrentUser() - .setUserAttribute('age', 30); - mParticle - .getInstance() - .Identity.getCurrentUser() - .setUserAttribute('height', '68'); - mParticle - .getInstance() - .Identity.getCurrentUser() - .setUserAttribute('color', 'blue'); - mParticle - .getInstance() - .Identity.getCurrentUser() - .setUserAttribute('id', 'id1'); - - fetchMockSuccess(urls.login, { - mpid: 'MPID1', is_logged_in: false - }); - - mParticle.Identity.login(); - waitForCondition(() => { - return ( - mParticle.Identity.getCurrentUser()?.getMPID() === 'MPID1' - ); - }) - .then(() => { - - mParticle - .getInstance() - .Identity.getCurrentUser() - .setUserAttribute('gender', 'male'); - mParticle - .getInstance() - .Identity.getCurrentUser() - .setUserAttribute('age', 30); - mParticle - .getInstance() - .Identity.getCurrentUser() - .setUserAttribute('height', '60'); - mParticle - .getInstance() - .Identity.getCurrentUser() - .setUserAttribute('color', 'green'); - mParticle - .getInstance() - .Identity.getCurrentUser() - .setUserAttribute('id', 'id2'); - - let cookieData: Partial = findCookie(); - - cookieData.gs.csm[0].should.equal('testMPID'); - cookieData.gs.csm[1].should.equal('MPID1'); - - fetchMockSuccess(urls.login, { - mpid: 'MPID2', is_logged_in: false - }); - - mParticle.endSession(); - mParticle.Identity.login(); - waitForCondition(() => { - return ( - mParticle.Identity.getCurrentUser()?.getMPID() === 'MPID2' - ); - }) - .then(() => { - - mParticle - .getInstance() - .Identity.getCurrentUser() - .setUserAttribute('gender', 'female'); - mParticle - .getInstance() - .Identity.getCurrentUser() - .setUserAttribute('age', 45); - mParticle - .getInstance() - .Identity.getCurrentUser() - .setUserAttribute('height', '80'); - mParticle - .getInstance() - .Identity.getCurrentUser() - .setUserAttribute('color', 'green'); - mParticle - .getInstance() - .Identity.getCurrentUser() - .setUserAttribute('id', 'id3'); - - cookieData = findCookie(); - - expect(cookieData['testMPID']).to.not.be.ok; - cookieData['MPID1'].ua.should.have.property('id', 'id2'); - cookieData['MPID1'].ua.should.have.property('gender', 'male'); - cookieData['MPID1'].ua.should.have.property('age', 30); - cookieData['MPID1'].ua.should.have.property('height', '60'); - cookieData['MPID1'].ua.should.have.property('color', 'green'); - cookieData['MPID2'].ua.should.have.property('id', 'id3'); - cookieData['MPID2'].ua.should.have.property('gender', 'female'); - cookieData['MPID2'].ua.should.have.property('age', 45); - cookieData['MPID2'].ua.should.have.property('height', '80'); - cookieData['MPID2'].ua.should.have.property('color', 'green'); - - done(); - }); - }); - }); - }); - - it('integration test - migrates a large localStorage cookie to cookies and properly remove MPIDs', done => { - mParticle._resetForTests(MPConfig); - mParticle.config.useCookieStorage = false; - mParticle.config.maxCookieSize = 700; - - mParticle.init(apiKey, mParticle.config); - - waitForCondition(hasIdentifyReturned) - .then(() => { - mParticle - .getInstance() - .Identity.getCurrentUser() - .setUserAttribute('gender', 'female'); - mParticle - .getInstance() - .Identity.getCurrentUser() - .setUserAttribute('age', 30); - mParticle - .getInstance() - .Identity.getCurrentUser() - .setUserAttribute('height', '68'); - mParticle - .getInstance() - .Identity.getCurrentUser() - .setUserAttribute('color', 'blue'); - mParticle - .getInstance() - .Identity.getCurrentUser() - .setUserAttribute('id', 'id1'); - - fetchMockSuccess(urls.login, { - mpid: 'MPID1', is_logged_in: false - }); - - mParticle.Identity.login(); - waitForCondition(() => { - return ( - mParticle.Identity.getCurrentUser()?.getMPID() === 'MPID1' - ); - }) - .then(() => { - - mParticle - .getInstance() - .Identity.getCurrentUser() - .setUserAttribute('gender', 'male'); - mParticle - .getInstance() - .Identity.getCurrentUser() - .setUserAttribute('age', 30); - mParticle - .getInstance() - .Identity.getCurrentUser() - .setUserAttribute('height', '60'); - mParticle - .getInstance() - .Identity.getCurrentUser() - .setUserAttribute('color', 'green'); - mParticle - .getInstance() - .Identity.getCurrentUser() - .setUserAttribute('id', 'id2'); - - fetchMockSuccess(urls.login, { - mpid: 'MPID2', is_logged_in: false - }); - - mParticle.Identity.login(); - waitForCondition(() => { - return ( - mParticle.Identity.getCurrentUser()?.getMPID() === 'MPID2' - ); - }) - .then(() => { - - mParticle - .getInstance() - .Identity.getCurrentUser() - .setUserAttribute('gender', 'female'); - mParticle - .getInstance() - .Identity.getCurrentUser() - .setUserAttribute('age', 45); - mParticle - .getInstance() - .Identity.getCurrentUser() - .setUserAttribute('height', '80'); - mParticle - .getInstance() - .Identity.getCurrentUser() - .setUserAttribute('color', 'green'); - mParticle - .getInstance() - .Identity.getCurrentUser() - .setUserAttribute('id', 'id3'); - - mParticle.config.useCookieStorage = true; - - mParticle.init(apiKey, mParticle.config); - waitForCondition(() => { - return ( - window.mParticle.getInstance()?._Store?.identityCallInFlight === false - ); - }) - .then(() => { - const cookieData = findCookie(); - - expect(cookieData['testMPID']).to.not.be.ok; - cookieData['MPID1'].ua.should.have.property('id', 'id2'); - cookieData['MPID2'].ua.should.have.property('id'); - - done(); - }); - }); - }); - }); - }); - - it('integration test - migrates all cookie MPIDs to localStorage', done => { - mParticle.config.useCookieStorage = true; - - mParticle.init(apiKey, mParticle.config); - waitForCondition(hasIdentifyReturned) - .then(() => { - mParticle - .getInstance() - .Identity.getCurrentUser() - .setUserAttribute('gender', 'female'); - mParticle - .getInstance() - .Identity.getCurrentUser() - .setUserAttribute('age', 30); - mParticle - .getInstance() - .Identity.getCurrentUser() - .setUserAttribute('height', '68'); - mParticle - .getInstance() - .Identity.getCurrentUser() - .setUserAttribute('color', 'blue'); - mParticle - .getInstance() - .Identity.getCurrentUser() - .setUserAttribute('id', 'id1'); + waitForCondition(hasIdentifyReturned).then(() => { + mParticle + .getInstance() + .Identity.getCurrentUser() + .setUserAttribute('gender', 'female'); + mParticle + .getInstance() + .Identity.getCurrentUser() + .setUserAttribute('age', 30); + mParticle + .getInstance() + .Identity.getCurrentUser() + .setUserAttribute('height', '68'); + mParticle + .getInstance() + .Identity.getCurrentUser() + .setUserAttribute('color', 'blue'); + mParticle + .getInstance() + .Identity.getCurrentUser() + .setUserAttribute('id', 'id1'); fetchMockSuccess(urls.login, { - mpid: 'MPID1', is_logged_in: false + mpid: 'MPID1', + is_logged_in: false, }); - const userIdentities1 = { - userIdentities: { - customerid: 'foo1', - }, - }; - mParticle.Identity.login(userIdentities1); - waitForCondition(() => { - return ( - mParticle.Identity.getCurrentUser()?.getMPID() === 'MPID1' - ); - }) - .then(() => { - - mParticle - .getInstance() - .Identity.getCurrentUser() - .setUserAttribute('gender', 'male'); - mParticle - .getInstance() - .Identity.getCurrentUser() - .setUserAttribute('age', 30); - mParticle - .getInstance() - .Identity.getCurrentUser() - .setUserAttribute('height', '60'); - mParticle - .getInstance() - .Identity.getCurrentUser() - .setUserAttribute('color', 'green'); - mParticle - .getInstance() - .Identity.getCurrentUser() - .setUserAttribute('id', 'id2'); - - fetchMockSuccess(urls.login, { - mpid: 'MPID2', is_logged_in: false - }); - - const userIdentities2 = { - userIdentities: { - customerid: 'foo2', - }, - }; - mParticle.Identity.login(userIdentities2); - waitForCondition(() => { - return ( - mParticle.Identity.getCurrentUser()?.getMPID() === 'MPID2' - ); - }) - .then(() => { - - mParticle - .getInstance() - .Identity.getCurrentUser() - .setUserAttribute('gender', 'female'); - mParticle - .getInstance() - .Identity.getCurrentUser() - .setUserAttribute('age', 45); - mParticle - .getInstance() - .Identity.getCurrentUser() - .setUserAttribute('height', '80'); - mParticle - .getInstance() - .Identity.getCurrentUser() - .setUserAttribute('color', 'green'); - mParticle - .getInstance() - .Identity.getCurrentUser() - .setUserAttribute('id', 'id3'); - - mParticle.config.useCookieStorage = false; - - mParticle.init(apiKey, mParticle.config); - waitForCondition(() => { - return ( - window.mParticle.getInstance()?._Store?.identityCallInFlight === false - ); - }) - .then(() => { - const lsData = getLocalStorage(v4LSKey); - - lsData.should.have.properties([ - 'gs', - 'cu', - 'testMPID', - 'MPID1', - 'MPID2', - ]); - lsData['testMPID'].ua.should.have.properties([ - 'gender', - 'age', - 'height', - 'color', - 'id', - ]); - lsData['MPID1'].ua.should.have.properties([ - 'gender', - 'age', - 'height', - 'color', - 'id', - ]); - lsData['MPID2'].ua.should.have.properties([ - 'gender', - 'age', - 'height', - 'color', - 'id', - ]); + mParticle.Identity.login(); + waitForCondition(() => { + return ( + mParticle.Identity.getCurrentUser()?.getMPID() === 'MPID1' + ); + }).then(() => { + mParticle + .getInstance() + .Identity.getCurrentUser() + .setUserAttribute('gender', 'male'); + mParticle + .getInstance() + .Identity.getCurrentUser() + .setUserAttribute('age', 30); + mParticle + .getInstance() + .Identity.getCurrentUser() + .setUserAttribute('height', '60'); + mParticle + .getInstance() + .Identity.getCurrentUser() + .setUserAttribute('color', 'green'); + mParticle + .getInstance() + .Identity.getCurrentUser() + .setUserAttribute('id', 'id2'); + + let cookieData: Partial = findCookie(); + + cookieData.gs.csm[0].should.equal('testMPID'); + cookieData.gs.csm[1].should.equal('MPID1'); + + fetchMockSuccess(urls.login, { + mpid: 'MPID2', + is_logged_in: false, + }); + + mParticle.endSession(); + mParticle.Identity.login(); + waitForCondition(() => { + return ( + mParticle.Identity.getCurrentUser()?.getMPID() === + 'MPID2' + ); + }).then(() => { + mParticle + .getInstance() + .Identity.getCurrentUser() + .setUserAttribute('gender', 'female'); + mParticle + .getInstance() + .Identity.getCurrentUser() + .setUserAttribute('age', 45); + mParticle + .getInstance() + .Identity.getCurrentUser() + .setUserAttribute('height', '80'); + mParticle + .getInstance() + .Identity.getCurrentUser() + .setUserAttribute('color', 'green'); + mParticle + .getInstance() + .Identity.getCurrentUser() + .setUserAttribute('id', 'id3'); + + cookieData = findCookie(); + + expect(cookieData['testMPID']).to.not.be.ok; + cookieData['MPID1'].ua.should.have.property('id', 'id2'); + cookieData['MPID1'].ua.should.have.property( + 'gender', + 'male', + ); + cookieData['MPID1'].ua.should.have.property('age', 30); + cookieData['MPID1'].ua.should.have.property('height', '60'); + cookieData['MPID1'].ua.should.have.property( + 'color', + 'green', + ); + cookieData['MPID2'].ua.should.have.property('id', 'id3'); + cookieData['MPID2'].ua.should.have.property( + 'gender', + 'female', + ); + cookieData['MPID2'].ua.should.have.property('age', 45); + cookieData['MPID2'].ua.should.have.property('height', '80'); + cookieData['MPID2'].ua.should.have.property( + 'color', + 'green', + ); - done(); - }); - }); - }); - }); + done(); + }); + }); + }); }); - it('integration test - migrates all LS MPIDs to cookies', done => { + it('integration test - migrates a large localStorage cookie to cookies and properly remove MPIDs', (done) => { + mParticle._resetForTests(MPConfig); mParticle.config.useCookieStorage = false; + mParticle.config.maxCookieSize = 700; mParticle.init(apiKey, mParticle.config); - waitForCondition(hasIdentifyReturned) - .then(() => { - // testMPID - mParticle - .getInstance() - .Identity.getCurrentUser() - .setUserAttribute('gender', 'female'); - mParticle - .getInstance() - .Identity.getCurrentUser() - .setUserAttribute('age', 30); - mParticle - .getInstance() - .Identity.getCurrentUser() - .setUserAttribute('height', '68'); - mParticle - .getInstance() - .Identity.getCurrentUser() - .setUserAttribute('color', 'blue'); - mParticle - .getInstance() - .Identity.getCurrentUser() - .setUserAttribute('id', 'id1'); + waitForCondition(hasIdentifyReturned).then(() => { + mParticle + .getInstance() + .Identity.getCurrentUser() + .setUserAttribute('gender', 'female'); + mParticle + .getInstance() + .Identity.getCurrentUser() + .setUserAttribute('age', 30); + mParticle + .getInstance() + .Identity.getCurrentUser() + .setUserAttribute('height', '68'); + mParticle + .getInstance() + .Identity.getCurrentUser() + .setUserAttribute('color', 'blue'); + mParticle + .getInstance() + .Identity.getCurrentUser() + .setUserAttribute('id', 'id1'); - fetchMockSuccess(urls.login, { - mpid: 'MPID1', is_logged_in: false + fetchMockSuccess(urls.login, { + mpid: 'MPID1', + is_logged_in: false, + }); + + mParticle.Identity.login(); + waitForCondition(() => { + return ( + mParticle.Identity.getCurrentUser()?.getMPID() === 'MPID1' + ); + }).then(() => { + mParticle + .getInstance() + .Identity.getCurrentUser() + .setUserAttribute('gender', 'male'); + mParticle + .getInstance() + .Identity.getCurrentUser() + .setUserAttribute('age', 30); + mParticle + .getInstance() + .Identity.getCurrentUser() + .setUserAttribute('height', '60'); + mParticle + .getInstance() + .Identity.getCurrentUser() + .setUserAttribute('color', 'green'); + mParticle + .getInstance() + .Identity.getCurrentUser() + .setUserAttribute('id', 'id2'); + + fetchMockSuccess(urls.login, { + mpid: 'MPID2', + is_logged_in: false, + }); + + mParticle.Identity.login(); + waitForCondition(() => { + return ( + mParticle.Identity.getCurrentUser()?.getMPID() === + 'MPID2' + ); + }).then(() => { + mParticle + .getInstance() + .Identity.getCurrentUser() + .setUserAttribute('gender', 'female'); + mParticle + .getInstance() + .Identity.getCurrentUser() + .setUserAttribute('age', 45); + mParticle + .getInstance() + .Identity.getCurrentUser() + .setUserAttribute('height', '80'); + mParticle + .getInstance() + .Identity.getCurrentUser() + .setUserAttribute('color', 'green'); + mParticle + .getInstance() + .Identity.getCurrentUser() + .setUserAttribute('id', 'id3'); + + mParticle.config.useCookieStorage = true; + + mParticle.init(apiKey, mParticle.config); + waitForCondition(() => { + return ( + window.mParticle.getInstance()?._Store + ?.identityCallInFlight === false + ); + }).then(() => { + const cookieData = findCookie(); + + expect(cookieData['testMPID']).to.not.be.ok; + cookieData['MPID1'].ua.should.have.property( + 'id', + 'id2', + ); + cookieData['MPID2'].ua.should.have.property('id'); + + done(); + }); + }); + }); }); + }); - const userIdentities1 = { - userIdentities: { - customerid: 'foo1', - }, - }; + it('integration test - migrates all cookie MPIDs to localStorage', (done) => { + mParticle.config.useCookieStorage = true; - mParticle.Identity.login(userIdentities1); - waitForCondition(() => { - return ( - mParticle.Identity.getCurrentUser()?.getMPID() === 'MPID1' - ); - }) - .then(() => { + mParticle.init(apiKey, mParticle.config); + waitForCondition(hasIdentifyReturned).then(() => { + mParticle + .getInstance() + .Identity.getCurrentUser() + .setUserAttribute('gender', 'female'); + mParticle + .getInstance() + .Identity.getCurrentUser() + .setUserAttribute('age', 30); + mParticle + .getInstance() + .Identity.getCurrentUser() + .setUserAttribute('height', '68'); + mParticle + .getInstance() + .Identity.getCurrentUser() + .setUserAttribute('color', 'blue'); + mParticle + .getInstance() + .Identity.getCurrentUser() + .setUserAttribute('id', 'id1'); - // MPID1 - mParticle - .getInstance() - .Identity.getCurrentUser() - .setUserAttribute('gender', 'male'); - mParticle - .getInstance() - .Identity.getCurrentUser() - .setUserAttribute('age', 30); - mParticle - .getInstance() - .Identity.getCurrentUser() - .setUserAttribute('height', '60'); - mParticle - .getInstance() - .Identity.getCurrentUser() - .setUserAttribute('color', 'green'); - mParticle - .getInstance() - .Identity.getCurrentUser() - .setUserAttribute('id', 'id2'); + fetchMockSuccess(urls.login, { + mpid: 'MPID1', + is_logged_in: false, + }); - fetchMockSuccess(urls.login, { - mpid: 'MPID2', is_logged_in: false + const userIdentities1 = { + userIdentities: { + customerid: 'foo1', + }, + }; + mParticle.Identity.login(userIdentities1); + waitForCondition(() => { + return ( + mParticle.Identity.getCurrentUser()?.getMPID() === 'MPID1' + ); + }).then(() => { + mParticle + .getInstance() + .Identity.getCurrentUser() + .setUserAttribute('gender', 'male'); + mParticle + .getInstance() + .Identity.getCurrentUser() + .setUserAttribute('age', 30); + mParticle + .getInstance() + .Identity.getCurrentUser() + .setUserAttribute('height', '60'); + mParticle + .getInstance() + .Identity.getCurrentUser() + .setUserAttribute('color', 'green'); + mParticle + .getInstance() + .Identity.getCurrentUser() + .setUserAttribute('id', 'id2'); + + fetchMockSuccess(urls.login, { + mpid: 'MPID2', + is_logged_in: false, + }); + + const userIdentities2 = { + userIdentities: { + customerid: 'foo2', + }, + }; + mParticle.Identity.login(userIdentities2); + waitForCondition(() => { + return ( + mParticle.Identity.getCurrentUser()?.getMPID() === + 'MPID2' + ); + }).then(() => { + mParticle + .getInstance() + .Identity.getCurrentUser() + .setUserAttribute('gender', 'female'); + mParticle + .getInstance() + .Identity.getCurrentUser() + .setUserAttribute('age', 45); + mParticle + .getInstance() + .Identity.getCurrentUser() + .setUserAttribute('height', '80'); + mParticle + .getInstance() + .Identity.getCurrentUser() + .setUserAttribute('color', 'green'); + mParticle + .getInstance() + .Identity.getCurrentUser() + .setUserAttribute('id', 'id3'); + + mParticle.config.useCookieStorage = false; + + mParticle.init(apiKey, mParticle.config); + waitForCondition(() => { + return ( + window.mParticle.getInstance()?._Store + ?.identityCallInFlight === false + ); + }).then(() => { + const lsData = getLocalStorage(v4LSKey); + + lsData.should.have.properties([ + 'gs', + 'cu', + 'testMPID', + 'MPID1', + 'MPID2', + ]); + lsData['testMPID'].ua.should.have.properties([ + 'gender', + 'age', + 'height', + 'color', + 'id', + ]); + lsData['MPID1'].ua.should.have.properties([ + 'gender', + 'age', + 'height', + 'color', + 'id', + ]); + lsData['MPID2'].ua.should.have.properties([ + 'gender', + 'age', + 'height', + 'color', + 'id', + ]); + + done(); + }); + }); + }); }); + }); - const userIdentities2 = { - userIdentities: { - customerid: 'foo2', - }, - }; + it('integration test - migrates all LS MPIDs to cookies', (done) => { + mParticle.config.useCookieStorage = false; - mParticle.Identity.login(userIdentities2); - waitForCondition(() => { - return ( - mParticle.Identity.getCurrentUser()?.getMPID() === 'MPID2' - ); - }) - .then(() => { + mParticle.init(apiKey, mParticle.config); + waitForCondition(hasIdentifyReturned).then(() => { + // testMPID + mParticle + .getInstance() + .Identity.getCurrentUser() + .setUserAttribute('gender', 'female'); + mParticle + .getInstance() + .Identity.getCurrentUser() + .setUserAttribute('age', 30); + mParticle + .getInstance() + .Identity.getCurrentUser() + .setUserAttribute('height', '68'); + mParticle + .getInstance() + .Identity.getCurrentUser() + .setUserAttribute('color', 'blue'); + mParticle + .getInstance() + .Identity.getCurrentUser() + .setUserAttribute('id', 'id1'); - // MPID2 - mParticle - .getInstance() - .Identity.getCurrentUser() - .setUserAttribute('gender', 'female'); - mParticle - .getInstance() - .Identity.getCurrentUser() - .setUserAttribute('age', 45); - mParticle - .getInstance() - .Identity.getCurrentUser() - .setUserAttribute('height', '80'); - mParticle - .getInstance() - .Identity.getCurrentUser() - .setUserAttribute('color', 'green'); - mParticle - .getInstance() - .Identity.getCurrentUser() - .setUserAttribute('id', 'id3'); + fetchMockSuccess(urls.login, { + mpid: 'MPID1', + is_logged_in: false, + }); - mParticle.config.useCookieStorage = true; + const userIdentities1 = { + userIdentities: { + customerid: 'foo1', + }, + }; - mParticle.init(apiKey, mParticle.config); - waitForCondition(() => { + mParticle.Identity.login(userIdentities1); + waitForCondition(() => { + return ( + mParticle.Identity.getCurrentUser()?.getMPID() === 'MPID1' + ); + }).then(() => { + // MPID1 + mParticle + .getInstance() + .Identity.getCurrentUser() + .setUserAttribute('gender', 'male'); + mParticle + .getInstance() + .Identity.getCurrentUser() + .setUserAttribute('age', 30); + mParticle + .getInstance() + .Identity.getCurrentUser() + .setUserAttribute('height', '60'); + mParticle + .getInstance() + .Identity.getCurrentUser() + .setUserAttribute('color', 'green'); + mParticle + .getInstance() + .Identity.getCurrentUser() + .setUserAttribute('id', 'id2'); + + fetchMockSuccess(urls.login, { + mpid: 'MPID2', + is_logged_in: false, + }); + + const userIdentities2 = { + userIdentities: { + customerid: 'foo2', + }, + }; + + mParticle.Identity.login(userIdentities2); + waitForCondition(() => { return ( - window.mParticle.getInstance()?._Store?.identityCallInFlight === false + mParticle.Identity.getCurrentUser()?.getMPID() === + 'MPID2' ); - }) - .then(() => { - const cookieData = findCookie(); - - cookieData.should.have.properties([ - 'gs', - 'cu', - 'testMPID', - 'MPID1', - 'MPID2', - ]); - cookieData['testMPID'].ua.should.have.properties([ - 'gender', - 'age', - 'height', - 'color', - 'id', - ]); - cookieData['MPID1'].ua.should.have.properties([ - 'gender', - 'age', - 'height', - 'color', - 'id', - ]); - cookieData['MPID2'].ua.should.have.properties([ - 'gender', - 'age', - 'height', - 'color', - 'id', - ]); - - done(); - }); - }); - }); - }); + }).then(() => { + // MPID2 + mParticle + .getInstance() + .Identity.getCurrentUser() + .setUserAttribute('gender', 'female'); + mParticle + .getInstance() + .Identity.getCurrentUser() + .setUserAttribute('age', 45); + mParticle + .getInstance() + .Identity.getCurrentUser() + .setUserAttribute('height', '80'); + mParticle + .getInstance() + .Identity.getCurrentUser() + .setUserAttribute('color', 'green'); + mParticle + .getInstance() + .Identity.getCurrentUser() + .setUserAttribute('id', 'id3'); + + mParticle.config.useCookieStorage = true; + + mParticle.init(apiKey, mParticle.config); + waitForCondition(() => { + return ( + window.mParticle.getInstance()?._Store + ?.identityCallInFlight === false + ); + }).then(() => { + const cookieData = findCookie(); + + cookieData.should.have.properties([ + 'gs', + 'cu', + 'testMPID', + 'MPID1', + 'MPID2', + ]); + cookieData['testMPID'].ua.should.have.properties([ + 'gender', + 'age', + 'height', + 'color', + 'id', + ]); + cookieData['MPID1'].ua.should.have.properties([ + 'gender', + 'age', + 'height', + 'color', + 'id', + ]); + cookieData['MPID2'].ua.should.have.properties([ + 'gender', + 'age', + 'height', + 'color', + 'id', + ]); + + done(); + }); + }); + }); + }); }); - it('integration test - clears and creates new LS on reload if LS is corrupt', done => { + it('integration test - clears and creates new LS on reload if LS is corrupt', (done) => { const les = new Date().getTime(); //an extra apostrophe is added to ua here to force a corrupt cookie. On init, cookies will clear and there will be a new cgid, sid, and das to exist @@ -1731,22 +1761,20 @@ describe('persistence', () => { setLocalStorage(v4LSKey, LS, true); mParticle.init(apiKey, mParticle.config); - waitForCondition(hasIdentifyReturned) - .then(() => { - - const sessionId = mParticle.sessionManager.getSession(); - const das = mParticle.getDeviceId(); - const cgid = mParticle.getInstance()._Persistence.getLocalStorage().gs - .cgid; - sessionId.should.not.equal('1992BDBB-AD74-49DB-9B20-5EC8037E72DE'); - das.should.not.equal('68c2ba39-c869-416a-a82c-8789caf5f1e7'); - cgid.should.not.equal('4ebad5b4-8ed1-4275-8455-838a2e3aa5c0'); + waitForCondition(hasIdentifyReturned).then(() => { + const sessionId = mParticle.sessionManager.getSession(); + const das = mParticle.getDeviceId(); + const cgid = mParticle.getInstance()._Persistence.getLocalStorage() + .gs.cgid; + sessionId.should.not.equal('1992BDBB-AD74-49DB-9B20-5EC8037E72DE'); + das.should.not.equal('68c2ba39-c869-416a-a82c-8789caf5f1e7'); + cgid.should.not.equal('4ebad5b4-8ed1-4275-8455-838a2e3aa5c0'); - done(); - }); + done(); + }); }); - it('integration test - clears and creates new cookies on reload if cookies is corrupt', done => { + it('integration test - clears and creates new cookies on reload if cookies is corrupt', (done) => { const les = new Date().getTime(); //an extra apostrophe is added to ua here to force a corrupt cookie. On init, cookies will clear and there will be a new cgid, sid, and das to exist @@ -1759,76 +1787,73 @@ describe('persistence', () => { mParticle.config.useCookieStorage = true; mParticle.init(apiKey, mParticle.config); - waitForCondition(hasIdentifyReturned) - .then(() => { + waitForCondition(hasIdentifyReturned).then(() => { + const sessionId = mParticle.sessionManager.getSession(); + const das = mParticle.getDeviceId(); + const cgid = mParticle.getInstance()._Persistence.getCookie() + .gs.cgid; + sessionId.should.not.equal('1992BDBB-AD74-49DB-9B20-5EC8037E72DE'); + das.should.not.equal('68c2ba39-c869-416a-a82c-8789caf5f1e7'); + cgid.should.not.equal('4ebad5b4-8ed1-4275-8455-838a2e3aa5c0'); - const sessionId = mParticle.sessionManager.getSession(); - const das = mParticle.getDeviceId(); - const cgid = mParticle.getInstance()._Persistence.getCookie().gs.cgid; - sessionId.should.not.equal('1992BDBB-AD74-49DB-9B20-5EC8037E72DE'); - das.should.not.equal('68c2ba39-c869-416a-a82c-8789caf5f1e7'); - cgid.should.not.equal('4ebad5b4-8ed1-4275-8455-838a2e3aa5c0'); - - done(); - }); + done(); + }); }); - it('integration test - clears LS products on reload if LS products are corrupt', done => { + it('integration test - clears LS products on reload if LS products are corrupt', (done) => { // randomly added gibberish to a Base64 encoded cart product array to force a corrupt product array const products = 'eyItOTE4MjY2NTAzNTA1ODg1NjAwMyI6eyasdjfiojasdifojfsdfJjcCI6W3siTmFtZSI6ImFuZHJvaWQiLCJTa3UiOiI1MTg3MDkiLCJQcmljZSI6MjM0LCJRdWFudGl0eSI6MSwiQnJhbmQiOm51bGwsIlZhcmlhbnQiOm51bGwsIkNhdGVnb3J5IjpudWxsLCJQb3NpdGlvbiI6bnVsbCwiQ291cG9uQ29kZSI6bnVsbCwiVG90YWxBbW91bnQiOjIzNCwiQXR0cmlidXRlcyI6eyJwcm9kYXR0cjEiOiJoaSJ9fSx7Ik5hbWUiOiJ3aW5kb3dzIiwiU2t1IjoiODMzODYwIiwiUHJpY2UiOjM0NSwiUXVhbnRpdHkiOjEsIlRvdGFsQW1vdW50IjozNDUsIkF0dHJpYnV0ZXMiOm51bGx9XX19'; localStorage.setItem(localStorageProductsV4, products); mParticle.init(apiKey, mParticle.config); - waitForCondition(hasIdentifyReturned) - .then(() => { - - const productsAfterInit = getLocalStorageProducts().testMPID; - expect(productsAfterInit.length).to.not.be.ok; + waitForCondition(hasIdentifyReturned).then(() => { + const productsAfterInit = getLocalStorageProducts().testMPID; + expect(productsAfterInit.length).to.not.be.ok; - done(); - }); + done(); + }); }); - it('should save products to persistence correctly when adding and removing products', done => { + it('should save products to persistence correctly when adding and removing products', (done) => { mParticle.init(apiKey, mParticle.config); - waitForCondition(hasIdentifyReturned) - .then(() => { - - const iphone = mParticle.eCommerce.createProduct( - 'iphone', - 'iphonesku', - 599, - 1, - 'iphone variant', - 'iphonecategory', - 'iphonebrand', - null, - 'iphonecoupon', - { iphoneattr1: 'value1', iphoneattr2: 'value2' } - ); - mParticle.eCommerce.Cart.add(iphone, true); - - let ls = localStorage.getItem(LocalStorageProductsV4WithWorkSpaceName); - const parsedProducts = JSON.parse(atob(ls)); - // parsedProducts should just have key of testMPID with value of cp with a single product - Object.keys(parsedProducts).length.should.equal(1); - parsedProducts['testMPID'].should.have.property('cp'); - parsedProducts['testMPID'].cp.length.should.equal(1); - - mParticle.eCommerce.Cart.remove(iphone, true); - ls = localStorage.getItem(LocalStorageProductsV4WithWorkSpaceName); - const parsedProductsAfter = JSON.parse(atob(ls)); - // parsedProducts should just have key of testMPID with value of cp with no products - - Object.keys(parsedProductsAfter).length.should.equal(1); - parsedProductsAfter['testMPID'].should.have.property('cp'); - parsedProductsAfter['testMPID'].cp.length.should.equal(0); - done(); - }); + waitForCondition(hasIdentifyReturned).then(() => { + const iphone = mParticle.eCommerce.createProduct( + 'iphone', + 'iphonesku', + 599, + 1, + 'iphone variant', + 'iphonecategory', + 'iphonebrand', + null, + 'iphonecoupon', + { iphoneattr1: 'value1', iphoneattr2: 'value2' }, + ); + mParticle.eCommerce.Cart.add(iphone, true); + + let ls = localStorage.getItem( + LocalStorageProductsV4WithWorkSpaceName, + ); + const parsedProducts = JSON.parse(atob(ls)); + // parsedProducts should just have key of testMPID with value of cp with a single product + Object.keys(parsedProducts).length.should.equal(1); + parsedProducts['testMPID'].should.have.property('cp'); + parsedProducts['testMPID'].cp.length.should.equal(1); + + mParticle.eCommerce.Cart.remove(iphone, true); + ls = localStorage.getItem(LocalStorageProductsV4WithWorkSpaceName); + const parsedProductsAfter = JSON.parse(atob(ls)); + // parsedProducts should just have key of testMPID with value of cp with no products + + Object.keys(parsedProductsAfter).length.should.equal(1); + parsedProductsAfter['testMPID'].should.have.property('cp'); + parsedProductsAfter['testMPID'].cp.length.should.equal(0); + done(); + }); }); - it('should only set setFirstSeenTime() once', done => { + it('should only set setFirstSeenTime() once', (done) => { const cookies = JSON.stringify({ gs: { sid: 'fst Test', @@ -1849,48 +1874,53 @@ describe('persistence', () => { mParticle.init(apiKey, mParticle.config); waitForCondition(() => { return ( - window.mParticle.getInstance()?._Store?.identityCallInFlight === false + window.mParticle.getInstance()?._Store?.identityCallInFlight === + false ); - }) - .then(() => { - - mParticle.getInstance()._Persistence.setFirstSeenTime('current', 10000); - const currentFirstSeenTime = mParticle - .getInstance() - ._Persistence.getFirstSeenTime('current'); - mParticle.getInstance()._Persistence.setFirstSeenTime('current', 2); - mParticle - .getInstance() - ._Persistence.getFirstSeenTime('current') - .should.equal(currentFirstSeenTime); + }).then(() => { + mParticle + .getInstance() + ._Persistence.setFirstSeenTime('current', 10000); + const currentFirstSeenTime = mParticle + .getInstance() + ._Persistence.getFirstSeenTime('current'); + mParticle.getInstance()._Persistence.setFirstSeenTime('current', 2); + mParticle + .getInstance() + ._Persistence.getFirstSeenTime('current') + .should.equal(currentFirstSeenTime); - mParticle.getInstance()._Persistence.setFirstSeenTime('previous', 10); - mParticle - .getInstance() - ._Persistence.getFirstSeenTime('previous') - .should.equal(10); - mParticle.getInstance()._Persistence.setFirstSeenTime('previous', 20); - mParticle - .getInstance() - ._Persistence.getFirstSeenTime('previous') - .should.equal(10); + mParticle + .getInstance() + ._Persistence.setFirstSeenTime('previous', 10); + mParticle + .getInstance() + ._Persistence.getFirstSeenTime('previous') + .should.equal(10); + mParticle + .getInstance() + ._Persistence.setFirstSeenTime('previous', 20); + mParticle + .getInstance() + ._Persistence.getFirstSeenTime('previous') + .should.equal(10); - mParticle - .getInstance() - ._Persistence.getFirstSeenTime('previous_set') - .should.equal(100); - mParticle - .getInstance() - ._Persistence.setFirstSeenTime('previous_set', 200); - mParticle - .getInstance() - ._Persistence.getFirstSeenTime('previous_set') - .should.equal(100); - done(); - }); + mParticle + .getInstance() + ._Persistence.getFirstSeenTime('previous_set') + .should.equal(100); + mParticle + .getInstance() + ._Persistence.setFirstSeenTime('previous_set', 200); + mParticle + .getInstance() + ._Persistence.getFirstSeenTime('previous_set') + .should.equal(100); + done(); + }); }); - it('should properly set setLastSeenTime()', done => { + it('should properly set setLastSeenTime()', (done) => { mParticle._resetForTests(MPConfig); const cookies = JSON.stringify({ @@ -1910,40 +1940,40 @@ describe('persistence', () => { mParticle.init(apiKey, mParticle.config); waitForCondition(() => { return ( - window.mParticle.getInstance()?._Store?.identityCallInFlight === false + window.mParticle.getInstance()?._Store?.identityCallInFlight === + false ); - }) - .then(() => { - - const clock = sinon.useFakeTimers(); - clock.tick(100); + }).then(() => { + const clock = sinon.useFakeTimers(); + clock.tick(100); - const persistence: IPersistence = mParticle.getInstance()._Persistence; + const persistence: IPersistence = + mParticle.getInstance()._Persistence; - persistence.setLastSeenTime('previous', 1); - expect(persistence.getLastSeenTime('previous')).to.equal(1); + persistence.setLastSeenTime('previous', 1); + expect(persistence.getLastSeenTime('previous')).to.equal(1); - persistence.setLastSeenTime('previous', 2); - expect(persistence.getLastSeenTime('previous')).to.equal(2); + persistence.setLastSeenTime('previous', 2); + expect(persistence.getLastSeenTime('previous')).to.equal(2); - expect(persistence.getLastSeenTime('previous_set')).to.equal(10); - persistence.setLastSeenTime('previous_set', 20); - expect(persistence.getLastSeenTime('previous_set')).to.equal(20); + expect(persistence.getLastSeenTime('previous_set')).to.equal(10); + persistence.setLastSeenTime('previous_set', 20); + expect(persistence.getLastSeenTime('previous_set')).to.equal(20); - expect(persistence.getLastSeenTime('current')).to.equal(100); - persistence.setLastSeenTime('current', 200); - //lastSeenTime for the current user should always reflect the current time, - //even if was set - expect(persistence.getLastSeenTime('current')).to.equal(100); - clock.tick(50); - expect(persistence.getLastSeenTime('current')).to.equal(150); + expect(persistence.getLastSeenTime('current')).to.equal(100); + persistence.setLastSeenTime('current', 200); + //lastSeenTime for the current user should always reflect the current time, + //even if was set + expect(persistence.getLastSeenTime('current')).to.equal(100); + clock.tick(50); + expect(persistence.getLastSeenTime('current')).to.equal(150); - clock.restore(); - done(); - }); + clock.restore(); + done(); + }); }); - it("should set firstSeenTime() for a user that doesn't have storage yet", done => { + it("should set firstSeenTime() for a user that doesn't have storage yet", (done) => { const cookies = JSON.stringify({ gs: { sid: 'fst Test', @@ -1973,7 +2003,7 @@ describe('persistence', () => { done(); }); - it('fst should be set when the user does not change, after an identify request', done => { + it('fst should be set when the user does not change, after an identify request', (done) => { const cookies = JSON.stringify({ gs: { sid: 'fst Test', @@ -1988,7 +2018,6 @@ describe('persistence', () => { is_logged_in: false, }); - setCookie(workspaceCookieName, cookies, true); // FIXME: Should this be in configs or global? mParticle.config.useCookieStorage = true; @@ -1996,32 +2025,35 @@ describe('persistence', () => { mParticle.init(apiKey, mParticle.config); waitForCondition(() => { return ( - window.mParticle.getInstance()?._Store?.identityCallInFlight === false - ); - }) - .then(() => { - expect( - mParticle.getInstance()._Persistence.getFirstSeenTime('current') - ).to.equal(null); - - mParticle.Identity.identify(); - waitForCondition(() => { - return ( - window.mParticle.getInstance()?._Store?.identityCallInFlight === false + window.mParticle.getInstance()?._Store?.identityCallInFlight === + false ); - }) - .then(() => { - - expect( - mParticle.getInstance()._Persistence.getFirstSeenTime('current') - ).to.not.equal(null); - - done(); - }); - }); + }).then(() => { + expect( + mParticle + .getInstance() + ._Persistence.getFirstSeenTime('current'), + ).to.equal(null); + + mParticle.Identity.identify(); + waitForCondition(() => { + return ( + window.mParticle.getInstance()?._Store + ?.identityCallInFlight === false + ); + }).then(() => { + expect( + mParticle + .getInstance() + ._Persistence.getFirstSeenTime('current'), + ).to.not.equal(null); + + done(); + }); + }); }); - it('lastSeenTime should be null for users in storage without an lst value', done => { + it('lastSeenTime should be null for users in storage without an lst value', (done) => { const cookies = JSON.stringify({ gs: { sid: 'lst Test', @@ -2037,16 +2069,18 @@ describe('persistence', () => { mParticle.init(apiKey, mParticle.config); waitForCondition(() => { return ( - window.mParticle.getInstance()?._Store?.identityCallInFlight === false + window.mParticle.getInstance()?._Store?.identityCallInFlight === + false ); - }) - .then(() => { - expect( - mParticle.getInstance()._Persistence.getFirstSeenTime('previous') - ).to.equal(null); + }).then(() => { + expect( + mParticle + .getInstance() + ._Persistence.getFirstSeenTime('previous'), + ).to.equal(null); - done(); - }); + done(); + }); }); it('should save to persistence a device id set with setDeviceId', async () => { @@ -2062,7 +2096,7 @@ describe('persistence', () => { .gs.das.should.equal('foo-guid'); }); - it('should save to persistence a device id set via mParticle.config', done => { + it('should save to persistence a device id set via mParticle.config', (done) => { mParticle._resetForTests(MPConfig); mParticle.config.deviceId = 'foo-guid'; mParticle.init(apiKey, mParticle.config); @@ -2075,7 +2109,7 @@ describe('persistence', () => { done(); }); - it('should prioritize device id set via mParticle.config instead of local storage', done => { + it('should prioritize device id set via mParticle.config instead of local storage', (done) => { mParticle._resetForTests(MPConfig); mParticle.init(apiKey, mParticle.config); @@ -2092,17 +2126,17 @@ describe('persistence', () => { expect( mParticle.getInstance().getDeviceId(), - 'Device ID should match guid passed in via config' + 'Device ID should match guid passed in via config', ).to.equal(expectedDeviceId); expect( initialDeviceId, - 'New Device ID should not match Old Device Id' + 'New Device ID should not match Old Device Id', ).to.not.equal(expectedDeviceId); expect( mParticle.getInstance()._Persistence.getLocalStorage().gs.das, - 'Device ID stored in Local Storage should be the new Device ID' + 'Device ID stored in Local Storage should be the new Device ID', ).to.equal(expectedDeviceId); done(); @@ -2111,7 +2145,7 @@ describe('persistence', () => { // this test confirms a bug has been fixed where setting a user attribute, then user attribute list // with a special character in it results in a cookie decode error, which only happened // when config.useCookieStorage was true - it('should save special characters to persistence when on cookies or local storage', done => { + it('should save special characters to persistence when on cookies or local storage', (done) => { fetchMockSuccess(urls.login, { mpid: testMPID, is_logged_in: false, @@ -2124,44 +2158,42 @@ describe('persistence', () => { mParticle.init(apiKey, mParticle.config); waitForCondition(() => { return ( - window.mParticle.getInstance()?._Store?.identityCallInFlight === false + window.mParticle.getInstance()?._Store?.identityCallInFlight === + false ); - }) - .then(() => { + }).then(() => { + const user = mParticle.Identity.getCurrentUser(); - const user = mParticle.Identity.getCurrentUser(); + user.setUserAttribute('ua-1', 'a'); + user.setUserAttributeList('ua-list', ['a\\', '']); - user.setUserAttribute('ua-1', 'a'); - user.setUserAttributeList('ua-list', ['a\\', '']); + user.getAllUserAttributes()['ua-list'][0].should.equal('a\\'); + user.getAllUserAttributes()['ua-list'][1].should.equal(''); + user.getAllUserAttributes()['ua-1'].should.equal('a'); - user.getAllUserAttributes()['ua-list'][0].should.equal('a\\'); - user.getAllUserAttributes()['ua-list'][1].should.equal(''); - user.getAllUserAttributes()['ua-1'].should.equal('a'); + mParticle._resetForTests(MPConfig); - mParticle._resetForTests(MPConfig); - - // then test cookie storage - mParticle.config.useCookieStorage = true; - - mParticle.init(apiKey, mParticle.config); - waitForCondition(() => { - return ( - window.mParticle.getInstance()?._Store?.identityCallInFlight === false - ); - }) - .then(() => { + // then test cookie storage + mParticle.config.useCookieStorage = true; - const user2 = mParticle.Identity.getCurrentUser(); + mParticle.init(apiKey, mParticle.config); + waitForCondition(() => { + return ( + window.mParticle.getInstance()?._Store + ?.identityCallInFlight === false + ); + }).then(() => { + const user2 = mParticle.Identity.getCurrentUser(); - user2.setUserAttribute('ua-1', 'a'); - user2.setUserAttributeList('ua-list', ['a\\', '']); + user2.setUserAttribute('ua-1', 'a'); + user2.setUserAttributeList('ua-list', ['a\\', '']); - user2.getAllUserAttributes()['ua-list'][0].should.equal('a\\'); - user2.getAllUserAttributes()['ua-list'][1].should.equal(''); - user2.getAllUserAttributes()['ua-1'].should.equal('a'); + user2.getAllUserAttributes()['ua-list'][0].should.equal('a\\'); + user2.getAllUserAttributes()['ua-list'][1].should.equal(''); + user2.getAllUserAttributes()['ua-1'].should.equal('a'); - done(); - }); - }); + done(); + }); + }); }); -}); \ No newline at end of file +}); diff --git a/test/src/tests-queue-public-methods.js b/test/src/tests-queue-public-methods.js index c798fc6a9..12f3edb5a 100644 --- a/test/src/tests-queue-public-methods.js +++ b/test/src/tests-queue-public-methods.js @@ -1,11 +1,11 @@ import { apiKey, MPConfig, testMPID, urls } from './config/constants'; -import { SDKProductActionType } from '../../src/sdkRuntimeModels'; +import { SDKProductActionType } from '../../src/sdkRuntimeModels'; import Utils from './config/utils'; -const { waitForCondition, fetchMockSuccess, hasIdentityCallInflightReturned } = Utils; +const { waitForCondition, fetchMockSuccess, hasIdentityCallInflightReturned } = + Utils; describe('Queue Public Methods', function () { - beforeEach(function () { fetchMockSuccess(urls.events); fetchMockSuccess(urls.identify, { @@ -13,13 +13,12 @@ describe('Queue Public Methods', function () { is_logged_in: false, }); }); - + afterEach(function () { mParticle._resetForTests(MPConfig); }); describe('mParticle Core', function () { - describe('#isInitialized', function () { it('should be a valid method on both mParticle and mParticle.getInstance() objects', function () { mParticle.should.have.property('isInitialized'); @@ -30,81 +29,121 @@ describe('Queue Public Methods', function () { mParticle.isInitialized().should.equal(false); mParticle.getInstance().isInitialized().should.equal(false); window.mParticle.init(apiKey, window.mParticle.config); - await waitForCondition(hasIdentityCallInflightReturned) + await waitForCondition(hasIdentityCallInflightReturned); mParticle.isInitialized().should.equal(true); mParticle.getInstance().isInitialized().should.equal(true); }); - }); + }); describe('#setAppVersion', function () { it('should queue if not initialized', function () { - mParticle.getInstance()._preInit.readyQueue.length.should.equal(0); + mParticle + .getInstance() + ._preInit.readyQueue.length.should.equal(0); mParticle.setAppVersion('1.2.3'); - mParticle.getInstance()._preInit.readyQueue.length.should.equal(1); + mParticle + .getInstance() + ._preInit.readyQueue.length.should.equal(1); }); it('should process queue after initialization', async function () { - mParticle.getInstance()._preInit.readyQueue.length.should.equal(0); + mParticle + .getInstance() + ._preInit.readyQueue.length.should.equal(0); mParticle.setAppVersion('1.2.3'); - mParticle.getInstance()._preInit.readyQueue.length.should.equal(1); + mParticle + .getInstance() + ._preInit.readyQueue.length.should.equal(1); mParticle.init(apiKey, window.mParticle.config); - await waitForCondition(hasIdentityCallInflightReturned) - mParticle.getInstance()._preInit.readyQueue.length.should.equal(0); + await waitForCondition(hasIdentityCallInflightReturned); + mParticle + .getInstance() + ._preInit.readyQueue.length.should.equal(0); }); - }); + }); describe('#setAppName', function () { it('should queue if not initialized', function () { - mParticle.getInstance()._preInit.readyQueue.length.should.equal(0); + mParticle + .getInstance() + ._preInit.readyQueue.length.should.equal(0); mParticle.setAppName('Timmy'); - mParticle.getInstance()._preInit.readyQueue.length.should.equal(1); + mParticle + .getInstance() + ._preInit.readyQueue.length.should.equal(1); }); it('should process queue after initialization', async function () { - mParticle.getInstance()._preInit.readyQueue.length.should.equal(0); + mParticle + .getInstance() + ._preInit.readyQueue.length.should.equal(0); mParticle.setAppName('Timmy'); - mParticle.getInstance()._preInit.readyQueue.length.should.equal(1); + mParticle + .getInstance() + ._preInit.readyQueue.length.should.equal(1); mParticle.init(apiKey, window.mParticle.config); - await waitForCondition(hasIdentityCallInflightReturned) - mParticle.getInstance()._preInit.readyQueue.length.should.equal(0); + await waitForCondition(hasIdentityCallInflightReturned); + mParticle + .getInstance() + ._preInit.readyQueue.length.should.equal(0); }); - }); + }); describe('#ready', function () { it('should queue if not initialized', function () { - mParticle.getInstance()._preInit.readyQueue.length.should.equal(0); + mParticle + .getInstance() + ._preInit.readyQueue.length.should.equal(0); mParticle.ready(function () { console.log('fired ready function'); }); - mParticle.getInstance()._preInit.readyQueue.length.should.equal(1); + mParticle + .getInstance() + ._preInit.readyQueue.length.should.equal(1); }); it('should process queue after initialization', async function () { - mParticle.getInstance()._preInit.readyQueue.length.should.equal(0); + mParticle + .getInstance() + ._preInit.readyQueue.length.should.equal(0); mParticle.ready(function () { console.log('fired ready function'); }); - mParticle.getInstance()._preInit.readyQueue.length.should.equal(1); + mParticle + .getInstance() + ._preInit.readyQueue.length.should.equal(1); mParticle.init(apiKey, window.mParticle.config); - await waitForCondition(hasIdentityCallInflightReturned) - mParticle.getInstance()._preInit.readyQueue.length.should.equal(0); + await waitForCondition(hasIdentityCallInflightReturned); + mParticle + .getInstance() + ._preInit.readyQueue.length.should.equal(0); }); - }); + }); describe('#setPosition', function () { it('should queue if not initialized', function () { - mParticle.getInstance()._preInit.readyQueue.length.should.equal(0); + mParticle + .getInstance() + ._preInit.readyQueue.length.should.equal(0); mParticle.setPosition(10, 4); - mParticle.getInstance()._preInit.readyQueue.length.should.equal(1); + mParticle + .getInstance() + ._preInit.readyQueue.length.should.equal(1); }); it('should process queue after initialization', async function () { - mParticle.getInstance()._preInit.readyQueue.length.should.equal(0); + mParticle + .getInstance() + ._preInit.readyQueue.length.should.equal(0); mParticle.setPosition(10, 4); - mParticle.getInstance()._preInit.readyQueue.length.should.equal(1); + mParticle + .getInstance() + ._preInit.readyQueue.length.should.equal(1); mParticle.init(apiKey, window.mParticle.config); - await waitForCondition(hasIdentityCallInflightReturned) - mParticle.getInstance()._preInit.readyQueue.length.should.equal(0); + await waitForCondition(hasIdentityCallInflightReturned); + mParticle + .getInstance() + ._preInit.readyQueue.length.should.equal(0); }); }); @@ -114,9 +153,13 @@ describe('Queue Public Methods', function () { name: 'test event', }; - mParticle.getInstance()._preInit.readyQueue.length.should.equal(0); + mParticle + .getInstance() + ._preInit.readyQueue.length.should.equal(0); mParticle.logBaseEvent(event); - mParticle.getInstance()._preInit.readyQueue.length.should.equal(1); + mParticle + .getInstance() + ._preInit.readyQueue.length.should.equal(1); }); it('should process queue after initialization', async function () { @@ -124,200 +167,334 @@ describe('Queue Public Methods', function () { name: 'test event', }; - mParticle.getInstance()._preInit.readyQueue.length.should.equal(0); + mParticle + .getInstance() + ._preInit.readyQueue.length.should.equal(0); mParticle.logBaseEvent(event); - mParticle.getInstance()._preInit.readyQueue.length.should.equal(1); + mParticle + .getInstance() + ._preInit.readyQueue.length.should.equal(1); mParticle.init(apiKey, window.mParticle.config); - await waitForCondition(hasIdentityCallInflightReturned) - mParticle.getInstance()._preInit.readyQueue.length.should.equal(0); + await waitForCondition(hasIdentityCallInflightReturned); + mParticle + .getInstance() + ._preInit.readyQueue.length.should.equal(0); }); - }); + }); describe('#logEvent', function () { it('should queue if not initialized', function () { - mParticle.getInstance()._preInit.readyQueue.length.should.equal(0); + mParticle + .getInstance() + ._preInit.readyQueue.length.should.equal(0); mParticle.logEvent('Test Event'); - mParticle.getInstance()._preInit.readyQueue.length.should.equal(1); + mParticle + .getInstance() + ._preInit.readyQueue.length.should.equal(1); }); it('should process queue after initialization', async function () { - mParticle.getInstance()._preInit.readyQueue.length.should.equal(0); + mParticle + .getInstance() + ._preInit.readyQueue.length.should.equal(0); mParticle.logEvent('Test Event'); - mParticle.getInstance()._preInit.readyQueue.length.should.equal(1); + mParticle + .getInstance() + ._preInit.readyQueue.length.should.equal(1); mParticle.init(apiKey, window.mParticle.config); - await waitForCondition(hasIdentityCallInflightReturned) - mParticle.getInstance()._preInit.readyQueue.length.should.equal(0); + await waitForCondition(hasIdentityCallInflightReturned); + mParticle + .getInstance() + ._preInit.readyQueue.length.should.equal(0); }); - }); + }); describe('#logError', function () { it('should queue if not initialized', function () { - mParticle.getInstance()._preInit.readyQueue.length.should.equal(0); + mParticle + .getInstance() + ._preInit.readyQueue.length.should.equal(0); mParticle.logError('test error', {}); - mParticle.getInstance()._preInit.readyQueue.length.should.equal(1); + mParticle + .getInstance() + ._preInit.readyQueue.length.should.equal(1); }); it('should process queue after initialization', async function () { - mParticle.getInstance()._preInit.readyQueue.length.should.equal(0); + mParticle + .getInstance() + ._preInit.readyQueue.length.should.equal(0); mParticle.logError('test error', {}); - mParticle.getInstance()._preInit.readyQueue.length.should.equal(1); + mParticle + .getInstance() + ._preInit.readyQueue.length.should.equal(1); mParticle.init(apiKey, window.mParticle.config); - await waitForCondition(hasIdentityCallInflightReturned) - mParticle.getInstance()._preInit.readyQueue.length.should.equal(0); + await waitForCondition(hasIdentityCallInflightReturned); + mParticle + .getInstance() + ._preInit.readyQueue.length.should.equal(0); }); - }); + }); describe('#logPageView', function () { it('should queue if not initialized', function () { - mParticle.getInstance()._preInit.readyQueue.length.should.equal(0); + mParticle + .getInstance() + ._preInit.readyQueue.length.should.equal(0); mParticle.logPageView('test page view', {}); - mParticle.getInstance()._preInit.readyQueue.length.should.equal(1); + mParticle + .getInstance() + ._preInit.readyQueue.length.should.equal(1); }); it('should process queue after initialization', async function () { - mParticle.getInstance()._preInit.readyQueue.length.should.equal(0); + mParticle + .getInstance() + ._preInit.readyQueue.length.should.equal(0); mParticle.logPageView('test page view', {}); - mParticle.getInstance()._preInit.readyQueue.length.should.equal(1); + mParticle + .getInstance() + ._preInit.readyQueue.length.should.equal(1); mParticle.init(apiKey, window.mParticle.config); - await waitForCondition(hasIdentityCallInflightReturned) - mParticle.getInstance()._preInit.readyQueue.length.should.equal(0); + await waitForCondition(hasIdentityCallInflightReturned); + mParticle + .getInstance() + ._preInit.readyQueue.length.should.equal(0); }); - }); + }); describe('#setOptOut', function () { it('should queue if not initialized', function () { - mParticle.getInstance()._preInit.readyQueue.length.should.equal(0); + mParticle + .getInstance() + ._preInit.readyQueue.length.should.equal(0); mParticle.setOptOut(true); - mParticle.getInstance()._preInit.readyQueue.length.should.equal(1); + mParticle + .getInstance() + ._preInit.readyQueue.length.should.equal(1); }); it('should process queue after initialization', async function () { - mParticle.getInstance()._preInit.readyQueue.length.should.equal(0); + mParticle + .getInstance() + ._preInit.readyQueue.length.should.equal(0); mParticle.setOptOut(true); - mParticle.getInstance()._preInit.readyQueue.length.should.equal(1); + mParticle + .getInstance() + ._preInit.readyQueue.length.should.equal(1); mParticle.init(apiKey, window.mParticle.config); - await waitForCondition(hasIdentityCallInflightReturned) - mParticle.getInstance()._preInit.readyQueue.length.should.equal(0); + await waitForCondition(hasIdentityCallInflightReturned); + mParticle + .getInstance() + ._preInit.readyQueue.length.should.equal(0); }); - }); + }); describe('#setIntegrationAttribute', function () { it('should queue if not initialized', function () { - mParticle.getInstance()._preInit.readyQueue.length.should.equal(0); + mParticle + .getInstance() + ._preInit.readyQueue.length.should.equal(0); mParticle.setIntegrationAttribute('12345', {}); - mParticle.getInstance()._preInit.readyQueue.length.should.equal(1); + mParticle + .getInstance() + ._preInit.readyQueue.length.should.equal(1); }); it('should process queue after initialization', async function () { - mParticle.getInstance()._preInit.readyQueue.length.should.equal(0); + mParticle + .getInstance() + ._preInit.readyQueue.length.should.equal(0); mParticle.setIntegrationAttribute('12345', {}); - mParticle.getInstance()._preInit.readyQueue.length.should.equal(1); + mParticle + .getInstance() + ._preInit.readyQueue.length.should.equal(1); mParticle.init(apiKey, window.mParticle.config); - await waitForCondition(hasIdentityCallInflightReturned) - mParticle.getInstance()._preInit.readyQueue.length.should.equal(0); + await waitForCondition(hasIdentityCallInflightReturned); + mParticle + .getInstance() + ._preInit.readyQueue.length.should.equal(0); }); - }); + }); describe('#setSessionAttribute', function () { it('should queue if not initialized', function () { - mParticle.getInstance()._preInit.readyQueue.length.should.equal(0); + mParticle + .getInstance() + ._preInit.readyQueue.length.should.equal(0); mParticle.setSessionAttribute('foo', 'bar'); - mParticle.getInstance()._preInit.readyQueue.length.should.equal(1); + mParticle + .getInstance() + ._preInit.readyQueue.length.should.equal(1); }); it('should process queue after initialization', async function () { - mParticle.getInstance()._preInit.readyQueue.length.should.equal(0); + mParticle + .getInstance() + ._preInit.readyQueue.length.should.equal(0); mParticle.setSessionAttribute('foo', 'bar'); - mParticle.getInstance()._preInit.readyQueue.length.should.equal(1); + mParticle + .getInstance() + ._preInit.readyQueue.length.should.equal(1); mParticle.init(apiKey, window.mParticle.config); - await waitForCondition(hasIdentityCallInflightReturned) - mParticle.getInstance()._preInit.readyQueue.length.should.equal(0); + await waitForCondition(hasIdentityCallInflightReturned); + mParticle + .getInstance() + ._preInit.readyQueue.length.should.equal(0); }); - }); + }); describe('#isInitialized', function () { it('returns true when Store is initialized', async function () { mParticle.getInstance().isInitialized().should.be.false(); mParticle.init(apiKey, window.mParticle.config); - await waitForCondition(hasIdentityCallInflightReturned) + await waitForCondition(hasIdentityCallInflightReturned); mParticle.getInstance().isInitialized().should.be.true(); }); }); - }); + }); describe('mParticle.eCommerce', function () { describe('#setCurrencyCode', function () { it('should queue if not initialized', function () { - mParticle.getInstance()._preInit.readyQueue.length.should.equal(0); + mParticle + .getInstance() + ._preInit.readyQueue.length.should.equal(0); mParticle.eCommerce.setCurrencyCode('USD'); - mParticle.getInstance()._preInit.readyQueue.length.should.equal(1); + mParticle + .getInstance() + ._preInit.readyQueue.length.should.equal(1); }); it('should process queue after initialization', async function () { - mParticle.getInstance()._preInit.readyQueue.length.should.equal(0); + mParticle + .getInstance() + ._preInit.readyQueue.length.should.equal(0); mParticle.eCommerce.setCurrencyCode('USD'); - mParticle.getInstance()._preInit.readyQueue.length.should.equal(1); + mParticle + .getInstance() + ._preInit.readyQueue.length.should.equal(1); mParticle.init(apiKey, window.mParticle.config); - await waitForCondition(hasIdentityCallInflightReturned) - mParticle.getInstance()._preInit.readyQueue.length.should.equal(0); + await waitForCondition(hasIdentityCallInflightReturned); + mParticle + .getInstance() + ._preInit.readyQueue.length.should.equal(0); }); - }); + }); describe('#logProductAction', function () { it('should queue if not initialized', function () { - const product = window.mParticle.eCommerce.createProduct('iphone', 'iphoneSKU', 999); - mParticle.getInstance()._preInit.readyQueue.length.should.equal(0); - mParticle.eCommerce.logProductAction(SDKProductActionType.Purchase, product); - mParticle.getInstance()._preInit.readyQueue.length.should.equal(1); + const product = window.mParticle.eCommerce.createProduct( + 'iphone', + 'iphoneSKU', + 999, + ); + mParticle + .getInstance() + ._preInit.readyQueue.length.should.equal(0); + mParticle.eCommerce.logProductAction( + SDKProductActionType.Purchase, + product, + ); + mParticle + .getInstance() + ._preInit.readyQueue.length.should.equal(1); }); it('should process queue after initialization', async function () { - const product = window.mParticle.eCommerce.createProduct('iphone', 'iphoneSKU', 999); - mParticle.getInstance()._preInit.readyQueue.length.should.equal(0); - mParticle.eCommerce.logProductAction(SDKProductActionType.Purchase, product); - mParticle.getInstance()._preInit.readyQueue.length.should.equal(1); + const product = window.mParticle.eCommerce.createProduct( + 'iphone', + 'iphoneSKU', + 999, + ); + mParticle + .getInstance() + ._preInit.readyQueue.length.should.equal(0); + mParticle.eCommerce.logProductAction( + SDKProductActionType.Purchase, + product, + ); + mParticle + .getInstance() + ._preInit.readyQueue.length.should.equal(1); mParticle.init(apiKey, window.mParticle.config); - await waitForCondition(hasIdentityCallInflightReturned) - mParticle.getInstance()._preInit.readyQueue.length.should.equal(0); + await waitForCondition(hasIdentityCallInflightReturned); + mParticle + .getInstance() + ._preInit.readyQueue.length.should.equal(0); }); - }); + }); describe('#logPromotion', function () { it('should queue if not initialized', function () { - mParticle.getInstance()._preInit.readyQueue.length.should.equal(0); + mParticle + .getInstance() + ._preInit.readyQueue.length.should.equal(0); mParticle.eCommerce.logPromotion('Test'); - mParticle.getInstance()._preInit.readyQueue.length.should.equal(1); + mParticle + .getInstance() + ._preInit.readyQueue.length.should.equal(1); }); it('should process queue after initialization', async function () { - mParticle.getInstance()._preInit.readyQueue.length.should.equal(0); + mParticle + .getInstance() + ._preInit.readyQueue.length.should.equal(0); mParticle.eCommerce.logPromotion('Test'); - mParticle.getInstance()._preInit.readyQueue.length.should.equal(1); + mParticle + .getInstance() + ._preInit.readyQueue.length.should.equal(1); mParticle.init(apiKey, window.mParticle.config); - await waitForCondition(hasIdentityCallInflightReturned) - mParticle.getInstance()._preInit.readyQueue.length.should.equal(0); + await waitForCondition(hasIdentityCallInflightReturned); + mParticle + .getInstance() + ._preInit.readyQueue.length.should.equal(0); }); - }); + }); describe('#logImpression', function () { it('should queue if not initialized', function () { - const product = window.mParticle.eCommerce.createProduct('iphone', 'iphoneSKU', 999); - const impression = window.mParticle.eCommerce.createImpression('iphone impression', product); - mParticle.getInstance()._preInit.readyQueue.length.should.equal(0); + const product = window.mParticle.eCommerce.createProduct( + 'iphone', + 'iphoneSKU', + 999, + ); + const impression = window.mParticle.eCommerce.createImpression( + 'iphone impression', + product, + ); + mParticle + .getInstance() + ._preInit.readyQueue.length.should.equal(0); mParticle.eCommerce.logImpression(impression); - mParticle.getInstance()._preInit.readyQueue.length.should.equal(1); + mParticle + .getInstance() + ._preInit.readyQueue.length.should.equal(1); }); it('should process queue after initialization', async function () { - const product = window.mParticle.eCommerce.createProduct('iphone', 'iphoneSKU', 999); - const impression = window.mParticle.eCommerce.createImpression('iphone impression', product); - mParticle.getInstance()._preInit.readyQueue.length.should.equal(0); + const product = window.mParticle.eCommerce.createProduct( + 'iphone', + 'iphoneSKU', + 999, + ); + const impression = window.mParticle.eCommerce.createImpression( + 'iphone impression', + product, + ); + mParticle + .getInstance() + ._preInit.readyQueue.length.should.equal(0); mParticle.eCommerce.logImpression(impression); - mParticle.getInstance()._preInit.readyQueue.length.should.equal(1); + mParticle + .getInstance() + ._preInit.readyQueue.length.should.equal(1); mParticle.init(apiKey, window.mParticle.config); - await waitForCondition(hasIdentityCallInflightReturned) - mParticle.getInstance()._preInit.readyQueue.length.should.equal(0); + await waitForCondition(hasIdentityCallInflightReturned); + mParticle + .getInstance() + ._preInit.readyQueue.length.should.equal(0); }); - }); + }); }); -}); \ No newline at end of file +}); diff --git a/test/src/tests-runtimeToBatchEventsDTO.ts b/test/src/tests-runtimeToBatchEventsDTO.ts index fb4522209..3371bd51a 100644 --- a/test/src/tests-runtimeToBatchEventsDTO.ts +++ b/test/src/tests-runtimeToBatchEventsDTO.ts @@ -1,7 +1,10 @@ import * as Converter from '../../src/sdkToEventsApiConverter'; import { expect } from 'chai'; import Types from '../../src/types'; -import { IMParticleInstanceManager, SDKEvent } from '../../src/sdkRuntimeModels'; +import { + IMParticleInstanceManager, + SDKEvent, +} from '../../src/sdkRuntimeModels'; import * as EventsApi from '@mparticle/event-models'; import { MPConfig, apiKey } from './config/constants'; import { IMParticleUser } from '../../src/identity-user-interfaces'; @@ -13,33 +16,42 @@ declare global { } describe('Old model to batch model conversion', () => { - beforeEach(function() { + beforeEach(function () { window.mParticle.init(apiKey, window.mParticle.config); }); - afterEach(function() { + afterEach(function () { window.mParticle._resetForTests(MPConfig); }); const batchDataTests = [{ devmode: false }, { devmode: true }]; - batchDataTests.forEach(params => { - it('Batch level conversion ' + params, done => { + batchDataTests.forEach((params) => { + it('Batch level conversion ' + params, (done) => { window.mParticle._resetForTests(MPConfig); window.mParticle.config.appVersion = 'a version'; window.mParticle.config.appName = 'a name'; window.mParticle.init(apiKey, window.mParticle.config); - let batch = Converter.convertEvents(null, null, window.mParticle.getInstance()); + let batch = Converter.convertEvents( + null, + null, + window.mParticle.getInstance(), + ); expect(batch).to.be.null; - batch = Converter.convertEvents(null, [], window.mParticle.getInstance()); + batch = Converter.convertEvents( + null, + [], + window.mParticle.getInstance(), + ); expect(batch).to.be.null; - + window.mParticle.getInstance()._Store.sessionId = 'foo-session-id'; window.mParticle.getInstance()._Store.isFirstRun = false; window.mParticle.getInstance()._Store.devToken = 'foo token'; window.mParticle.getInstance()._Store.deviceId = 'a device id'; - window.mParticle.getInstance()._Store.SDKConfig.isDevelopmentMode = params.devmode; + window.mParticle.getInstance()._Store.SDKConfig.isDevelopmentMode = + params.devmode; window.mParticle.getInstance().Identity.getCurrentUser = () => { return { getUserIdentities: () => { @@ -77,28 +89,26 @@ describe('Old model to batch model conversion', () => { customFlags: { 'foo-flag': 'foo-flag-val' }, }; - const sdkEvent = window.mParticle.getInstance()._ServerModel.createEventObject( - publicEvent - ) as SDKEvent; - console.log(sdkEvent); - expect(sdkEvent).to.be.ok; + const sdkEvent = window.mParticle + .getInstance() + ._ServerModel.createEventObject(publicEvent) as SDKEvent; + console.log(sdkEvent); + expect(sdkEvent).to.be.ok; batch = Converter.convertEvents( '123', [sdkEvent, sdkEvent], - window.mParticle.getInstance() + window.mParticle.getInstance(), ); expect(batch).to.be.ok; expect(batch.mpid).to.equal('123'); expect(batch.environment).to.equal( - params.devmode ? 'development' : 'production' + params.devmode ? 'development' : 'production', ); expect(batch.application_info).to.be.ok; expect(batch.application_info.application_version).to.equal( - 'a version' - ); - expect(batch.application_info.application_name).to.equal( - 'a name' + 'a version', ); + expect(batch.application_info.application_name).to.equal('a name'); expect(batch.mp_deviceid).to.equal('a device id'); expect(batch.user_attributes).to.be.ok; @@ -123,7 +133,7 @@ describe('Old model to batch model conversion', () => { }); }); - it('User attribute conversion ', done => { + it('User attribute conversion ', (done) => { window.mParticle.getInstance().Identity.getCurrentUser = () => { return { getUserIdentities: () => { @@ -152,12 +162,16 @@ describe('Old model to batch model conversion', () => { eventType: Types.EventType.Navigation, customFlags: { 'foo-flag': 'foo-flag-val' }, }; - const sdkEvent = window.mParticle.getInstance()._ServerModel.createEventObject( - publicEvent - ) as SDKEvent; + const sdkEvent = window.mParticle + .getInstance() + ._ServerModel.createEventObject(publicEvent) as SDKEvent; expect(sdkEvent).to.be.ok; - const batch = Converter.convertEvents('123', [sdkEvent], window.mParticle.getInstance()); + const batch = Converter.convertEvents( + '123', + [sdkEvent], + window.mParticle.getInstance(), + ); expect(batch.user_attributes).to.be.ok; expect(batch.user_attributes).to.deep.equal({ @@ -168,51 +182,74 @@ describe('Old model to batch model conversion', () => { done(); }); - it('Data Plan Context conversion', done => { + it('Data Plan Context conversion', (done) => { const publicEvent = { messageType: Types.MessageType.PageEvent, name: 'foo page', data: { 'foo-attr': 'foo-val' }, eventType: Types.EventType.Navigation, - }; - const sdkEvent = window.mParticle.getInstance()._ServerModel.createEventObject( - publicEvent - ) as SDKEvent; + const sdkEvent = window.mParticle + .getInstance() + ._ServerModel.createEventObject(publicEvent) as SDKEvent; sdkEvent.DataPlan = null; - let batch = Converter.convertEvents('123', [sdkEvent], window.mParticle.getInstance()); + let batch = Converter.convertEvents( + '123', + [sdkEvent], + window.mParticle.getInstance(), + ); expect(batch.context).to.be.undefined; sdkEvent.DataPlan = {}; - batch = Converter.convertEvents('123', [sdkEvent], window.mParticle.getInstance()); + batch = Converter.convertEvents( + '123', + [sdkEvent], + window.mParticle.getInstance(), + ); expect(batch.context).to.be.undefined; - sdkEvent.DataPlan = {PlanId: null}; - batch = Converter.convertEvents('123', [sdkEvent], window.mParticle.getInstance()); + sdkEvent.DataPlan = { PlanId: null }; + batch = Converter.convertEvents( + '123', + [sdkEvent], + window.mParticle.getInstance(), + ); expect(batch.context).to.be.undefined; - sdkEvent.DataPlan = {PlanId: null, PlanVersion: 2}; - batch = Converter.convertEvents('123', [sdkEvent], window.mParticle.getInstance()); + sdkEvent.DataPlan = { PlanId: null, PlanVersion: 2 }; + batch = Converter.convertEvents( + '123', + [sdkEvent], + window.mParticle.getInstance(), + ); expect(batch.context).to.be.undefined; - sdkEvent.DataPlan = {PlanId: "foo", PlanVersion: null }; - batch = Converter.convertEvents('123', [sdkEvent], window.mParticle.getInstance()); + sdkEvent.DataPlan = { PlanId: 'foo', PlanVersion: null }; + batch = Converter.convertEvents( + '123', + [sdkEvent], + window.mParticle.getInstance(), + ); expect(batch.context).to.be.ok; expect(batch.context.data_plan).to.be.ok; - expect(batch.context.data_plan.plan_id).to.equal("foo"); + expect(batch.context.data_plan.plan_id).to.equal('foo'); expect(batch.context.data_plan.plan_version).be.undefined; - sdkEvent.DataPlan = {PlanId: "foo", PlanVersion: 4}; - batch = Converter.convertEvents('123', [sdkEvent], window.mParticle.getInstance()); + sdkEvent.DataPlan = { PlanId: 'foo', PlanVersion: 4 }; + batch = Converter.convertEvents( + '123', + [sdkEvent], + window.mParticle.getInstance(), + ); expect(batch.context).to.be.ok; expect(batch.context.data_plan).to.be.ok; - expect(batch.context.data_plan.plan_id).to.equal("foo"); + expect(batch.context.data_plan.plan_id).to.equal('foo'); expect(batch.context.data_plan.plan_version).be.equal(4); done(); }); - it('User identity conversion ', done => { + it('User identity conversion ', (done) => { window.mParticle.getInstance().Identity.getCurrentUser = () => { return { getUserIdentities: () => { @@ -245,15 +282,15 @@ describe('Old model to batch model conversion', () => { eventType: Types.EventType.Navigation, customFlags: { 'foo-flag': 'foo-flag-val' }, }; - const sdkEvent = window.mParticle.getInstance()._ServerModel.createEventObject( - publicEvent - ) as SDKEvent; + const sdkEvent = window.mParticle + .getInstance() + ._ServerModel.createEventObject(publicEvent) as SDKEvent; expect(sdkEvent).to.be.ok; const batch = Converter.convertEvents( '123', [sdkEvent, sdkEvent], - window.mParticle.getInstance() + window.mParticle.getInstance(), ); expect(batch.user_identities).to.be.ok; @@ -269,17 +306,17 @@ describe('Old model to batch model conversion', () => { const baseEventConversion: { [key: number]: EventsApi.EventType } = { 1: EventsApi.EventTypeEnum.sessionStart, - 2: EventsApi.EventTypeEnum.sessionEnd, - 3: EventsApi.EventTypeEnum.screenView, - 4: EventsApi.EventTypeEnum.customEvent, - 5: EventsApi.EventTypeEnum.crashReport, - 6: EventsApi.EventTypeEnum.optOut, + 2: EventsApi.EventTypeEnum.sessionEnd, + 3: EventsApi.EventTypeEnum.screenView, + 4: EventsApi.EventTypeEnum.customEvent, + 5: EventsApi.EventTypeEnum.crashReport, + 6: EventsApi.EventTypeEnum.optOut, 10: EventsApi.EventTypeEnum.applicationStateTransition, 16: EventsApi.EventTypeEnum.commerceEvent, }; - Object.keys(baseEventConversion).forEach(key => { - it('Base Event Conversion ' + baseEventConversion[key], done => { + Object.keys(baseEventConversion).forEach((key) => { + it('Base Event Conversion ' + baseEventConversion[key], (done) => { let event = Converter.convertEvent(null); expect(event).to.be.null; @@ -290,9 +327,9 @@ describe('Old model to batch model conversion', () => { eventType: Types.EventType.Navigation, customFlags: { 'foo-flag': 'foo-flag-val' }, }; - let sdkEvent = window.mParticle.getInstance()._ServerModel.createEventObject( - publicEvent - ) as SDKEvent; + let sdkEvent = window.mParticle + .getInstance() + ._ServerModel.createEventObject(publicEvent) as SDKEvent; event = Converter.convertEvent(sdkEvent); expect(event).to.be.null; @@ -304,9 +341,9 @@ describe('Old model to batch model conversion', () => { eventType: Types.EventType.Navigation, customFlags: { 'foo-flag': 'foo-flag-val' }, }; - sdkEvent = window.mParticle.getInstance()._ServerModel.createEventObject( - publicEvent - ) as SDKEvent; + sdkEvent = window.mParticle + .getInstance() + ._ServerModel.createEventObject(publicEvent) as SDKEvent; expect(sdkEvent).to.be.ok; event = Converter.convertEvent(sdkEvent); @@ -316,7 +353,7 @@ describe('Old model to batch model conversion', () => { }); }); - it('Commerce Event Product Action convertion', done => { + it('Commerce Event Product Action convertion', (done) => { const sdkEvent: SDKEvent = { EventName: 'eCommerce - Purchase', EventCategory: 16, @@ -378,27 +415,27 @@ describe('Old model to batch model conversion', () => { }, IsFirstRun: false, }; - let batch = Converter.convertEvents( + const batch = Converter.convertEvents( '1053073459916128825', [sdkEvent], - window.mParticle.getInstance() + window.mParticle.getInstance(), ); expect(batch).to.be.ok; expect(batch.mpid).to.equal(sdkEvent.MPID); expect(batch.events.length).to.equal(1); - let event = batch.events[0] as EventsApi.CommerceEvent; + const event = batch.events[0] as EventsApi.CommerceEvent; expect(event).to.be.ok; expect(event.event_type).to.equal('commerce_event'); expect(event.data.timestamp_unixtime_ms).to.equal(sdkEvent.Timestamp); expect(event.data.session_start_unixtime_ms).to.equal( - sdkEvent.SessionStartDate + sdkEvent.SessionStartDate, ); expect(event.data.product_action.action).to.equal('purchase'); expect(event.data.product_action.products.length).to.equal(2); for (let i = 0; i < event.data.product_action.products.length; i++) { - let product = event.data.product_action.products[i]; - let sdkProduct = sdkEvent.ProductAction.ProductList[i]; + const product = event.data.product_action.products[i]; + const sdkProduct = sdkEvent.ProductAction.ProductList[i]; expect(product.name).to.equal(sdkProduct.Name); expect(product.id).to.equal(sdkProduct.Sku); expect(product.price).to.equal(sdkProduct.Price); @@ -409,54 +446,54 @@ describe('Old model to batch model conversion', () => { expect(product.position).to.equal(sdkProduct.Position); expect(product.coupon_code).to.equal(sdkProduct.CouponCode); expect(product.total_product_amount).to.equal( - sdkProduct.TotalAmount + sdkProduct.TotalAmount, ); expect(product.custom_attributes).to.deep.equal( - sdkProduct.Attributes + sdkProduct.Attributes, ); } done(); }); - it ('Media Event Conversion', done => { + it('Media Event Conversion', (done) => { const sdkEvent: SDKEvent = { - EventName: "Pause Event", + EventName: 'Pause Event', EventCategory: 9, ExpandedEventCount: 0, EventDataType: 4, EventAttributes: { content_duration: '120000', - content_id: "1234567", - content_title: "My sweet sweet media", - content_type: "Video", - media_session_id: "07be2e14-7e05-4053-bcb5-94950365822d", + content_id: '1234567', + content_title: 'My sweet sweet media', + content_type: 'Video', + media_session_id: '07be2e14-7e05-4053-bcb5-94950365822d', playhead_position: '7023.335999999999', - stream_type: "OnDemand", + stream_type: 'OnDemand', }, ConsentState: null, CurrencyCode: null, CustomFlags: {}, DataPlan: {}, Debug: true, - DeviceId: "0edd580e-d887-44e4-89ae-cd65aa0ee933", + DeviceId: '0edd580e-d887-44e4-89ae-cd65aa0ee933', Location: null, - MPID: "-8433569646818451201", + MPID: '-8433569646818451201', OptOut: null, - SDKVersion: "2.11.15", + SDKVersion: '2.11.15', SourceMessageId: 'testSMID', - SessionId: "64102C03-592F-440D-8BCC-1D27AAA6B188", + SessionId: '64102C03-592F-440D-8BCC-1D27AAA6B188', SessionStartDate: 1603211322698, Timestamp: 1603212299414, ActiveTimeOnSite: 10, UserAttributes: {}, UserIdentities: [], IsFirstRun: true, - } + }; const batch = Converter.convertEvents( '-8433569646818451201', [sdkEvent], - window.mParticle.getInstance() + window.mParticle.getInstance(), ); expect(batch).to.be.ok; @@ -464,53 +501,53 @@ describe('Old model to batch model conversion', () => { const event = batch.events[0] as EventsApi.CustomEvent; expect(event).to.be.ok; expect(event.event_type).to.equal('custom_event'); - expect(event.data.custom_event_type).to.equal('media') + expect(event.data.custom_event_type).to.equal('media'); done(); }); - it('Set width and height to 0 when window is defined but screen is not defined', done => { + it('Set width and height to 0 when window is defined but screen is not defined', (done) => { const originalScreen = window.screen; delete window.screen; const sdkEvent: SDKEvent = { - EventName: "Pause Event", + EventName: 'Pause Event', EventCategory: 8, ExpandedEventCount: 0, EventDataType: 4, EventAttributes: { content_duration: '120000', - content_id: "1234567", - content_title: "My sweet sweet media", - content_type: "Video", - media_session_id: "07be2e14-7e05-4053-bcb5-94950365822d", + content_id: '1234567', + content_title: 'My sweet sweet media', + content_type: 'Video', + media_session_id: '07be2e14-7e05-4053-bcb5-94950365822d', playhead_position: '7023.335999999999', - stream_type: "OnDemand", + stream_type: 'OnDemand', }, ConsentState: null, CurrencyCode: null, CustomFlags: {}, DataPlan: {}, Debug: true, - DeviceId: "0edd580e-d887-44e4-89ae-cd65aa0ee933", + DeviceId: '0edd580e-d887-44e4-89ae-cd65aa0ee933', Location: null, - MPID: "-8433569646818451201", + MPID: '-8433569646818451201', OptOut: null, - SDKVersion: "2.11.15", + SDKVersion: '2.11.15', SourceMessageId: 'testSMID', - SessionId: "64102C03-592F-440D-8BCC-1D27AAA6B188", + SessionId: '64102C03-592F-440D-8BCC-1D27AAA6B188', SessionStartDate: 1603211322698, Timestamp: 1603212299414, ActiveTimeOnSite: 10, UserAttributes: {}, UserIdentities: [], IsFirstRun: true, - } + }; const batch = Converter.convertEvents( '-8433569646818451201', [sdkEvent], - window.mParticle.getInstance() + window.mParticle.getInstance(), ); expect(batch).to.be.ok; @@ -521,4 +558,4 @@ describe('Old model to batch model conversion', () => { window.screen = originalScreen; done(); }); -}); \ No newline at end of file +}); diff --git a/test/src/tests-self-hosting-specific.js b/test/src/tests-self-hosting-specific.js index 45c0fbf10..a3ad20949 100644 --- a/test/src/tests-self-hosting-specific.js +++ b/test/src/tests-self-hosting-specific.js @@ -8,20 +8,20 @@ const { findBatch, waitForCondition, fetchMockSuccess, - hasConfigurationReturned + hasConfigurationReturned, } = Utils; // Calls to /config are specific to only the self hosting environment -describe('/config self-hosting integration tests', function() { - beforeEach(function() { +describe('/config self-hosting integration tests', function () { + beforeEach(function () { fetchMock.post(urls.events, 200); }); - afterEach(function() { + afterEach(function () { fetchMock.restore(); sinon.restore(); window.mParticle.config.requestConfig = false; - }) + }); // https://go.mparticle.com/work/SQDSDKS-7160 it.skip('queues events in the eventQueue while /config is in flight, then processes them afterwards with correct MPID', async () => { @@ -36,10 +36,11 @@ describe('/config self-hosting integration tests', function() { }; fetchMockSuccess(urls.identify, { - mpid: 'identifyMPID', is_logged_in: false + mpid: 'identifyMPID', + is_logged_in: false, }); - // https://go.mparticle.com/work/SQDSDKS-6651 + // https://go.mparticle.com/work/SQDSDKS-6651 fetchMock.mock(urls.config, () => { return new Promise((resolve) => { setTimeout(() => { @@ -48,12 +49,12 @@ describe('/config self-hosting integration tests', function() { body: JSON.stringify({ success: true, appName: 'Test App', - kitCOnfigs: [] + kitCOnfigs: [], }), headers: { 'Content-Type': 'application/json' }, }); }, 50); // 100ms delay - }) + }); }); mParticle.init(apiKey, window.mParticle.config); @@ -65,15 +66,15 @@ describe('/config self-hosting integration tests', function() { await waitForCondition(hasConfigurationReturned); event = findBatch(fetchMock.calls(), 'Test'); - + event.should.be.ok(); event.mpid.should.equal('identifyMPID'); - + window.mParticle.config.requestConfig = false; }); // https://go.mparticle.com/work/SQDSDKS-6852 - it.skip('queued events contain login mpid instead of identify mpid when calling login immediately after mParticle initializes', function(done) { + it.skip('queued events contain login mpid instead of identify mpid when calling login immediately after mParticle initializes', function (done) { const messages = []; mParticle._resetForTests(MPConfig); window.mParticle.config.requestConfig = true; @@ -82,12 +83,12 @@ describe('/config self-hosting integration tests', function() { window.mParticle.config.logLevel = 'verbose'; delete window.mParticle.config.workspaceToken; mParticle.config.logger = { - verbose: function(msg) { + verbose: function (msg) { messages.push(msg); }, }; - window.mParticle.config.identityCallback = function() { + window.mParticle.config.identityCallback = function () { mParticle.logEvent('identify callback event'); }; @@ -99,12 +100,12 @@ describe('/config self-hosting integration tests', function() { body: JSON.stringify({ success: true, appName: 'Test App', - kitCOnfigs: [] + kitCOnfigs: [], }), headers: { 'Content-Type': 'application/json' }, }); }, 200); // 100ms delay - }) + }); }); fetchMock.mock(urls.identify, () => { @@ -113,62 +114,65 @@ describe('/config self-hosting integration tests', function() { resolve({ status: 200, body: JSON.stringify({ - mpid: 'identifyMPID', is_logged_in: false + mpid: 'identifyMPID', + is_logged_in: false, }), headers: { 'Content-Type': 'application/json' }, }); }, 5000); // 100ms delay - }) + }); }); fetchMockSuccess(urls.login, { - mpid: 'loginMPID', is_logged_in: false + mpid: 'loginMPID', + is_logged_in: false, }); mParticle.init(apiKey, window.mParticle.config); mParticle.Identity.login({ userIdentities: { customerid: 'abc123' } }); mParticle.getInstance()._Store.isInitialized = true; mParticle.logEvent('Test'); - - waitForCondition(() => { - return ( - mParticle.Identity.getCurrentUser()?.getMPID() === 'loginMPID' - ); - }) - .then(() => { - // call login before mParticle.identify is triggered, which happens after config returns - // mParticle.Identity.login({ userIdentities: { customerid: 'abc123' } }); + waitForCondition(() => { return ( - mParticle.getInstance()._Store.configurationLoaded === true + mParticle.Identity.getCurrentUser()?.getMPID() === 'loginMPID' ); - }) - .then(() => { - // config triggers, login triggers immediately before identify - const event1 = findBatch(fetchMock.calls(), 'Test'); - event1.mpid.should.equal('loginMPID'); - messages - .indexOf('Parsing "login" identity response from server') - .should.be.above(0); - - // when login is in flight, identify will not run, but callback still will - messages - .indexOf('Parsing "identify" identity response from server') - .should.equal(-1); - - // const event2 = findBatch(fetchMock.calls(), 'identify callback event', false, mockServer); - // event2.mpid.should.equal('loginMPID'); - - - localStorage.removeItem('mprtcl-v4_workspaceTokenTest'); - window.mParticle.config.requestConfig = false; - - done(); - }) - .catch((err) => { - console.log(err); + }).then(() => { + // call login before mParticle.identify is triggered, which happens after config returns + // mParticle.Identity.login({ userIdentities: { customerid: 'abc123' } }); + waitForCondition(() => { + return ( + mParticle.getInstance()._Store.configurationLoaded === true + ); }) - + .then(() => { + // config triggers, login triggers immediately before identify + const event1 = findBatch(fetchMock.calls(), 'Test'); + event1.mpid.should.equal('loginMPID'); + messages + .indexOf( + 'Parsing "login" identity response from server', + ) + .should.be.above(0); + + // when login is in flight, identify will not run, but callback still will + messages + .indexOf( + 'Parsing "identify" identity response from server', + ) + .should.equal(-1); + + // const event2 = findBatch(fetchMock.calls(), 'identify callback event', false, mockServer); + // event2.mpid.should.equal('loginMPID'); + + localStorage.removeItem('mprtcl-v4_workspaceTokenTest'); + window.mParticle.config.requestConfig = false; + + done(); + }) + .catch((err) => { + console.log(err); + }); }); }); @@ -181,7 +185,7 @@ describe('/config self-hosting integration tests', function() { fetchMock.get(urls.config, { status: 200, body: JSON.stringify({ - workspaceToken: 'wtTest' + workspaceToken: 'wtTest', }), }); @@ -200,19 +204,19 @@ describe('/config self-hosting integration tests', function() { window.mParticle.config.requestConfig = true; delete window.mParticle.config.workspaceToken; - fetchMock.get(urls.config, { status: 200, body: JSON.stringify({ - workspaceToken: 'wtTest', - flags: { + workspaceToken: 'wtTest', + flags: { directURLRouting: 'True', }, }), }); fetchMockSuccess(urls.identify, { - mpid: 'identifyMPID', is_logged_in: false + mpid: 'identifyMPID', + is_logged_in: false, }); mParticle.init(apiKey, window.mParticle.config); @@ -232,7 +236,7 @@ describe('/config self-hosting integration tests', function() { v1SecureServiceUrl.should.equal('jssdks.us1.mparticle.com/v1/JS/'); v3SecureServiceUrl.should.equal('jssdks.us1.mparticle.com/v3/JS/'); }); - + it('should prioritize passed in baseUrls over direct urls', async () => { mParticle._resetForTests(MPConfig); window.mParticle.config.requestConfig = true; @@ -248,15 +252,16 @@ describe('/config self-hosting integration tests', function() { fetchMock.get(urls.config, { status: 200, body: JSON.stringify({ - workspaceToken: 'wtTest', - flags: { + workspaceToken: 'wtTest', + flags: { directURLRouting: 'True', }, }), }); fetchMockSuccess(urls.identify, { - mpid: 'identifyMPID', is_logged_in: false + mpid: 'identifyMPID', + is_logged_in: false, }); mParticle.init(apiKey, window.mParticle.config); @@ -277,4 +282,4 @@ describe('/config self-hosting integration tests', function() { v3SecureServiceUrl.should.equal('jssdks.foo.mparticle.com/v3/JS/'); }); }); -}); \ No newline at end of file +}); diff --git a/test/src/tests-serverModel.ts b/test/src/tests-serverModel.ts index 3e96e630f..882d15738 100644 --- a/test/src/tests-serverModel.ts +++ b/test/src/tests-serverModel.ts @@ -3,37 +3,28 @@ import { urls, testMPID, apiKey } from './config/constants'; import { expect } from 'chai'; import { IUploadObject } from '../../src/serverModel'; import { IdentityApiData } from '@mparticle/web-sdk'; -import { BaseEvent, SDKEvent } from '../../src/sdkRuntimeModels'; +import { BaseEvent } from '../../src/sdkRuntimeModels'; import Constants from '../../src/constants'; import { SDKConsentState, SDKCCPAConsentState, SDKGDPRConsentState, } from '../../src/consent'; -import { IMParticleUser, ISDKUserAttributes } from '../../src/identity-user-interfaces'; +import { + IMParticleUser, + ISDKUserAttributes, +} from '../../src/identity-user-interfaces'; import Utils from './config/utils'; import { appendUserInfo } from '../../src/user-utils'; const { hasIdentifyReturned, waitForCondition, fetchMockSuccess } = Utils; -let initialEvent = {}; - const mParticle = window.mParticle; const ServerModel = mParticle.getInstance()._ServerModel; describe('ServerModel', () => { - beforeEach(() => { - initialEvent = { - messageType: Types.MessageType.PageEvent, - name: 'foo page', - data: { 'foo-attr': 'foo-val' }, - eventType: Types.EventType.Navigation, - customFlags: { 'foo-flag': 'foo-flag-val' }, - }; - }); - describe('#convertToConsentStateDTO', () => { it('should convert Consent State with GDPR to a DTO', () => { - const consentState = ({ + const consentState = { getGDPRConsentState: () => { return { 'test-gdpr-purpose': { @@ -46,7 +37,7 @@ describe('ServerModel', () => { }; }, getCCPAConsentState: () => {}, - } as unknown) as SDKConsentState; + } as unknown as SDKConsentState; const expectedDTO = { gdpr: { 'test-gdpr-purpose': { @@ -60,12 +51,12 @@ describe('ServerModel', () => { }; expect(ServerModel.convertToConsentStateV2DTO(consentState)).to.eql( - expectedDTO + expectedDTO, ); }); it('should convert Consent State with CCPA to a DTO', () => { - const consentState = ({ + const consentState = { getGDPRConsentState: () => {}, getCCPAConsentState: () => { return { @@ -76,7 +67,7 @@ describe('ServerModel', () => { HardwareId: 'test-ccpa-hardware-id', }; }, - } as unknown) as SDKConsentState; + } as unknown as SDKConsentState; const expectedDTO = { ccpa: { data_sale_opt_out: { @@ -90,12 +81,12 @@ describe('ServerModel', () => { }; expect(ServerModel.convertToConsentStateV2DTO(consentState)).to.eql( - expectedDTO + expectedDTO, ); }); it('should convert Consent State with both GDPR and CCPA to a DTO', () => { - const consentState = ({ + const consentState = { getGDPRConsentState: () => { return { 'test-gdpr-purpose': { @@ -116,7 +107,7 @@ describe('ServerModel', () => { HardwareId: 'test-ccpa-hardware-id', }; }, - } as unknown) as SDKConsentState; + } as unknown as SDKConsentState; const expectedDTO = { gdpr: { 'test-gdpr-purpose': { @@ -139,7 +130,7 @@ describe('ServerModel', () => { }; expect(ServerModel.convertToConsentStateV2DTO(consentState)).to.eql( - expectedDTO + expectedDTO, ); }); @@ -153,14 +144,14 @@ describe('ServerModel', () => { // TODO: Create Event Object is tightly coupled with mp Init and Store // This should be refactored to make the function more pure fetchMockSuccess(urls.identify, { - mpid: testMPID, is_logged_in: false + mpid: testMPID, + is_logged_in: false, }); mParticle.init(apiKey, mParticle.config); }); - afterEach(function() { - }); + afterEach(function () {}); it('should create an event object without a user', () => { const mPStore = mParticle.getInstance()._Store; @@ -205,24 +196,24 @@ describe('ServerModel', () => { ._ServerModel.createEventObject(event) as IUploadObject; expect(actualEventObject.EventName, 'EventName').to.equal( - 'Test Event' + 'Test Event', ); expect(actualEventObject.EventCategory, 'EventCategory').to.equal( - Types.EventType.Navigation + Types.EventType.Navigation, ); expect(actualEventObject.EventAttributes, 'EventCategory').to.eql({ foo: 'bar', bizz: 'bazz', }); expect(actualEventObject.EventDataType, 'EventDataType').to.equal( - Types.MessageType.PageEvent + Types.MessageType.PageEvent, ); expect(actualEventObject.CustomFlags, 'CustomFlags').to.eql({ custom: 'flag', }); expect( actualEventObject.UserAttributeChanges, - 'UserAttributeChanges' + 'UserAttributeChanges', ).to.eql({ UserAttributeName: '$Age', New: '42', @@ -233,7 +224,7 @@ describe('ServerModel', () => { expect( actualEventObject.UserIdentityChanges, - 'UserrIdentityChanges' + 'UserrIdentityChanges', ).to.eql({ New: { IdentityType: Types.IdentityType.Other2, @@ -250,46 +241,46 @@ describe('ServerModel', () => { }); expect(actualEventObject.Store, 'Store').to.eql({}); expect(actualEventObject.SDKVersion, 'SDKVersion').to.equal( - Constants.sdkVersion + Constants.sdkVersion, ); expect(actualEventObject.SessionId, 'SessionId').to.equal( - mPStore.sessionId + mPStore.sessionId, ); expect( actualEventObject.SessionStartDate, - 'SessionStartDate' + 'SessionStartDate', ).to.equal(mPStore.sessionStartDate.getTime()); expect(actualEventObject.Debug, 'Debug').to.equal(false); expect(actualEventObject.Location, 'Location').to.equal(null); expect(actualEventObject.OptOut, 'OptOut').to.equal(null); expect( actualEventObject.ExpandedEventCount, - 'ExpandedEventCount' + 'ExpandedEventCount', ).to.equal(0); expect(actualEventObject.AppVersion, 'AppVersion').to.equal( - undefined + undefined, ); expect(actualEventObject.AppName, 'AppName').to.equal(undefined); expect(actualEventObject.Package, 'Package').to.equal(undefined); expect( actualEventObject.ClientGeneratedId, - 'ClientGeneratedId' + 'ClientGeneratedId', ).to.equal(mPStore.clientId); expect(actualEventObject.DeviceId, 'DeviceId').to.equal( - mPStore.deviceId + mPStore.deviceId, ); expect( actualEventObject.IntegrationAttributes, - 'IntegrationAttributes' + 'IntegrationAttributes', ).to.eql({}); // TODO: Should this default to USD? expect(actualEventObject.CurrencyCode, 'CurrencyCode').to.equal( - null + null, ); expect(actualEventObject.DataPlan, 'DataPlan').to.eql({}); expect(actualEventObject.Timestamp, 'Timestamp').to.equal( - mPStore.dateLastEventSent.getTime() + mPStore.dateLastEventSent.getTime(), ); }); @@ -329,7 +320,7 @@ describe('ServerModel', () => { }, }; - const user = ({ + const user = { getUserIdentities: () => { return { userIdentities: { @@ -373,7 +364,7 @@ describe('ServerModel', () => { }, }; }, - } as unknown) as IMParticleUser; + } as unknown as IMParticleUser; const actualEventObject = mParticle .getInstance() @@ -414,56 +405,58 @@ describe('ServerModel', () => { ]); }); - it('should set necessary attributes if MessageType is SessionEnd', () => { - waitForCondition(hasIdentifyReturned) - .then(() => { - - const mPStore = mParticle.getInstance()._Store; - - mPStore.sessionAttributes = { - fooSessionAttr: 'session-foo', - barSessionAttr: 'session-bar', - }; - - const event: BaseEvent = { - name: 'Test Event', - messageType: Types.MessageType.SessionEnd, - eventType: Types.EventType.Other, - data: { - fooEventAttr: 'bar', - barEventAttr: 'bazz', - }, - }; - - const actualEventObject = mParticle - .getInstance() - ._ServerModel.createEventObject(event) as IUploadObject; - - expect( - actualEventObject.currentSessionMPIDs, - 'currentSessionMPIDs' - ).to.eql(['testMPID']); - - // A SessionEnd event appends SessionLength - expect(actualEventObject).to.have.property('SessionLength'); + it('should set necessary attributes if MessageType is SessionEnd', () => { + waitForCondition(hasIdentifyReturned).then(() => { + const mPStore = mParticle.getInstance()._Store; + + mPStore.sessionAttributes = { + fooSessionAttr: 'session-foo', + barSessionAttr: 'session-bar', + }; + + const event: BaseEvent = { + name: 'Test Event', + messageType: Types.MessageType.SessionEnd, + eventType: Types.EventType.Other, + data: { + fooEventAttr: 'bar', + barEventAttr: 'bazz', + }, + }; - // A SessionEnd event should ignore Event Attributes and use Session Attributes instead - expect(actualEventObject.EventAttributes, 'EventAttributes').to.eql( - { fooSessionAttr: 'session-foo', barSessionAttr: 'session-bar' } - ); - expect( - actualEventObject.EventAttributes, - 'EventAttributes' - ).to.not.have.property('fooEventAttr'); - expect( - actualEventObject.EventAttributes, - 'EventAttributes' - ).to.not.have.property('barEventAttr'); - - // A SessionEnd event resets currentSessionMPIDs and sessionStartDate. When a new session starts, these are filled again - expect(mPStore.currentSessionMPIDs).to.eql([]); - expect(mPStore.sessionStartDate).to.eql(null); - }) + const actualEventObject = mParticle + .getInstance() + ._ServerModel.createEventObject(event) as IUploadObject; + + expect( + actualEventObject.currentSessionMPIDs, + 'currentSessionMPIDs', + ).to.eql(['testMPID']); + + // A SessionEnd event appends SessionLength + expect(actualEventObject).to.have.property('SessionLength'); + + // A SessionEnd event should ignore Event Attributes and use Session Attributes instead + expect( + actualEventObject.EventAttributes, + 'EventAttributes', + ).to.eql({ + fooSessionAttr: 'session-foo', + barSessionAttr: 'session-bar', + }); + expect( + actualEventObject.EventAttributes, + 'EventAttributes', + ).to.not.have.property('fooEventAttr'); + expect( + actualEventObject.EventAttributes, + 'EventAttributes', + ).to.not.have.property('barEventAttr'); + + // A SessionEnd event resets currentSessionMPIDs and sessionStartDate. When a new session starts, these are filled again + expect(mPStore.currentSessionMPIDs).to.eql([]); + expect(mPStore.sessionStartDate).to.eql(null); + }); }); it('should set necessary attributes if MessageType is AppStateTransition', () => { @@ -479,7 +472,7 @@ describe('ServerModel', () => { expect(actualEventObject.IsFirstRun, 'IsFirstRun').to.eql(false); expect(actualEventObject.LaunchReferral, 'LaunchRefferral').to.eql( - window.location.href + window.location.href, ); }); @@ -497,7 +490,7 @@ describe('ServerModel', () => { expect( actualEventObject.SourceMessageId, - 'SourceMessageId' + 'SourceMessageId', ).to.not.equal(null); }); @@ -536,7 +529,7 @@ describe('ServerModel', () => { }); it('returns null if event is invalid', () => { - const event: BaseEvent = ({} as unknown) as BaseEvent; + const event: BaseEvent = {} as unknown as BaseEvent; expect(ServerModel.createEventObject(event)).to.eql(null); }); @@ -560,20 +553,20 @@ describe('ServerModel', () => { ._ServerModel.createEventObject(event); expect(actualEventObject.EventName, 'EventName').to.equal( - 'Test Event Object Override' + 'Test Event Object Override', ); expect(actualEventObject.EventCategory, 'EventCategory').to.equal( - Types.EventType.Media + Types.EventType.Media, ); expect(actualEventObject.EventDataType, 'EventDataType').to.equal( - Types.MessageType.Media + Types.MessageType.Media, ); }); }); describe('#convertEventToDTO', () => { it('should convert an event to a DTO', () => { - const uploadObject = ({ + const uploadObject = { EventName: 'test-name', EventCategory: Types.EventType.Navigation, EventAttributes: {}, @@ -599,13 +592,13 @@ describe('ServerModel', () => { MPID: 'test-mpid', ExpandedEventCount: 0, currentSessionMPIDs: ['test-mpids'], - } as unknown) as IUploadObject; + } as unknown as IUploadObject; const actualDTO = ServerModel.convertEventToV2DTO(uploadObject); expect(actualDTO.n, 'event.EventName (n)').to.equal('test-name'); expect(actualDTO.et, 'event.EventType (et)').to.equal( - Types.EventType.Navigation + Types.EventType.Navigation, ); expect(actualDTO.ua, 'event.UserAttributes (ua)').to.eql({}); expect(actualDTO.ui, 'event.UserIdentities (ui)').to.eql([]); @@ -614,14 +607,14 @@ describe('ServerModel', () => { expect(actualDTO.attrs, 'event.EventAttributes (attrs)').to.eql({}); expect(actualDTO.sdk, 'event.SDKVersion (sdk)').to.equal('1.2.3'); expect(actualDTO.sid, 'event.SessionId (sid)').to.equal( - 'test-session-id' + 'test-session-id', ); expect(actualDTO.sl, 'event.SessionLength (sl)').to.equal(33000); expect(actualDTO.ssd, 'event.SessionStartDate (ssd)').to.equal( - 11111 + 11111, ); expect(actualDTO.dt, 'event.EventDataType (dt)').to.equal( - Types.MessageType.PageEvent + Types.MessageType.PageEvent, ); expect(actualDTO.dbg, 'event.Debug (dbg)').to.equal(true); expect(actualDTO.ct, 'event.TimeStamp (ct)').to.equal(22222); @@ -632,18 +625,18 @@ describe('ServerModel', () => { expect(actualDTO.o, 'event.OptOut (o)').to.equal(false); expect(actualDTO.eec, 'event.ExpandedEventCount (eec)').to.equal(0); expect(actualDTO.av, 'event.AppVersion (av)').to.equal( - 'test-app.1235' + 'test-app.1235', ); expect(actualDTO.cgid, 'event.ClientGeneratedId (cgid)').to.equal( - 'test-client-id' + 'test-client-id', ); expect(actualDTO.das, 'event.DeviceId (das)').to.equal( - 'test-device' + 'test-device', ); expect(actualDTO.mpid, 'event.MPID (mpid)').to.equal('test-mpid'); expect( actualDTO.smpids, - 'event.currentSessionMPIDs (smpids)' + 'event.currentSessionMPIDs (smpids)', ).to.eql(['test-mpids']); }); @@ -658,11 +651,11 @@ describe('ServerModel', () => { const actualDTO = ServerModel.convertEventToV2DTO(uploadObject); expect(actualDTO.dp_id, 'event.DataPlan.PlanId (dp_id)').to.equal( - 'test-data-plan' + 'test-data-plan', ); expect( actualDTO.dp_v, - 'event.DataPlan.PlanVersion (dp_v)' + 'event.DataPlan.PlanVersion (dp_v)', ).to.equal(3); }); @@ -717,14 +710,14 @@ describe('ServerModel', () => { }); it('should add AST data to DTO', () => { - const uploadObject = ({ + const uploadObject = { EventDataType: Types.MessageType.AppStateTransition, IsFirstRun: true, LaunchReferral: 'https://mparticle.com/test-referral', EventAttributes: { foo: 'bar', // TODO: test will nullify these }, - } as unknown) as IUploadObject; + } as unknown as IUploadObject; const actualDTO = ServerModel.convertEventToV2DTO(uploadObject); @@ -733,26 +726,26 @@ describe('ServerModel', () => { expect(actualDTO.iu, 'event.isUpgrade').to.equal(false); expect( actualDTO.at, - 'event.ApplicationTransitionType.AppInit (at)' + 'event.ApplicationTransitionType.AppInit (at)', ).to.equal(Types.ApplicationTransitionType.AppInit); expect(actualDTO.lr, 'event.LaunchReferral (lr)').to.equal( - 'https://mparticle.com/test-referral' + 'https://mparticle.com/test-referral', ); expect(actualDTO.attrs, 'event.EventAttributes (attrs)').to.eql( - null + null, ); }); it('should add custom flags to DTO', () => { - const uploadObject = ({ + const uploadObject = { CustomFlags: { foo: 'bar', fizz: ['bizz', 'buzz', 37, true], answer: 42, isCustom: false, }, - } as unknown) as IUploadObject; + } as unknown as IUploadObject; const expectedFlags = { foo: ['bar'], @@ -767,7 +760,7 @@ describe('ServerModel', () => { }); it('should add shopping cart to DTO', () => { - const uploadObject = ({ + const uploadObject = { CurrencyCode: 'USD', EventDataType: Types.MessageType.Commerce, ShoppingCart: { @@ -805,7 +798,7 @@ describe('ServerModel', () => { }, ], }, - } as unknown) as IUploadObject; + } as unknown as IUploadObject; const expectedShoppingCart = { pl: [ @@ -849,11 +842,11 @@ describe('ServerModel', () => { }); it('should add empty array to DTO if shopping cart is empty', () => { - const uploadObject = ({ + const uploadObject = { CurrencyCode: 'USD', EventDataType: Types.MessageType.Commerce, ShoppingCart: {}, - } as unknown) as IUploadObject; + } as unknown as IUploadObject; const expectedShoppingCart = { pl: [], @@ -865,7 +858,7 @@ describe('ServerModel', () => { }); it('should add product action to DTO', () => { - const uploadObject = ({ + const uploadObject = { CurrencyCode: 'USD', EventDataType: Types.MessageType.Commerce, ProductAction: { @@ -915,7 +908,7 @@ describe('ServerModel', () => { }, ], }, - } as unknown) as IUploadObject; + } as unknown as IUploadObject; const expectedProducts = [ { @@ -954,11 +947,11 @@ describe('ServerModel', () => { expect(actualDTO.cu).to.equal('USD'); expect(actualDTO.pd.an, 'ActionName').to.equal( - Types.ProductActionType.AddToCart + Types.ProductActionType.AddToCart, ); expect(actualDTO.pd.cs, 'CheckoutStep').to.equal(42); expect(actualDTO.pd.co, 'CheckoutOptions').to.equal( - 'test-checkout-option' + 'test-checkout-option', ); expect(actualDTO.pd.ti, 'TransactionId').to.equal('id'); expect(actualDTO.pd.ta, 'Affiliation').to.equal('affiliation'); @@ -970,7 +963,7 @@ describe('ServerModel', () => { }); it('should add promotion action to DTO', () => { - const uploadObject = ({ + const uploadObject = { CurrencyCode: 'USD', EventDataType: Types.MessageType.Commerce, PromotionAction: { @@ -991,7 +984,7 @@ describe('ServerModel', () => { }, ], }, - } as unknown) as IUploadObject; + } as unknown as IUploadObject; const expectedPromotion = [ { @@ -1011,13 +1004,13 @@ describe('ServerModel', () => { expect(actualDTO.cu).to.equal('USD'); expect(actualDTO.pm.an, 'ActionName').to.equal( - Types.PromotionActionType.PromotionView + Types.PromotionActionType.PromotionView, ); expect(actualDTO.pm.pl, 'ProductList').to.eql(expectedPromotion); }); it('should add product impression to DTO', () => { - const uploadObject = ({ + const uploadObject = { CurrencyCode: 'USD', EventDataType: Types.MessageType.Commerce, ProductImpressions: [ @@ -1058,7 +1051,7 @@ describe('ServerModel', () => { ], }, ], - } as unknown) as IUploadObject; + } as unknown as IUploadObject; const expectedProducts = [ { @@ -1097,16 +1090,16 @@ describe('ServerModel', () => { expect(actualDTO.cu).to.equal('USD'); expect(actualDTO.pi[0].pil, 'ProductImpressionList').to.equal( - 'test-product-impression' + 'test-product-impression', ); expect(actualDTO.pi[0].pl, 'ProductList').to.eql(expectedProducts); }); it('should add profile to DTO', () => { - const uploadObject = ({ + const uploadObject = { EventDataType: Types.MessageType.Profile, ProfileMessageType: Types.ProfileMessageType.Logout, - } as unknown) as IUploadObject; + } as unknown as IUploadObject; const actualDTO = ServerModel.convertEventToV2DTO(uploadObject); @@ -1114,7 +1107,7 @@ describe('ServerModel', () => { }); }); - describe('Integration Tests', function() { + describe('Integration Tests', function () { const event = { messageType: Types.MessageType.PageEvent, name: 'foo page', @@ -1123,23 +1116,23 @@ describe('ServerModel', () => { customFlags: { 'foo-flag': 'foo-flag-val' }, }; - beforeEach(function() { + beforeEach(function () { fetchMockSuccess(urls.identify, { - mpid: testMPID, is_logged_in: false + mpid: testMPID, + is_logged_in: false, }); mParticle.init(apiKey, mParticle.config); }); - afterEach(function() { - }); + afterEach(function () {}); - it('Should not convert data plan object to server DTO when no id or version is set', function(done) { - let sdkEvent = window.mParticle + it('Should not convert data plan object to server DTO when no id or version is set', function (done) { + const sdkEvent = window.mParticle .getInstance() ._ServerModel.createEventObject(event); - let upload = window.mParticle + const upload = window.mParticle .getInstance() ._ServerModel.convertEventToV2DTO(sdkEvent as IUploadObject); @@ -1148,17 +1141,17 @@ describe('ServerModel', () => { done(); }); - it('Should convert data plan id to server DTO', function(done) { + it('Should convert data plan id to server DTO', function (done) { mParticle._resetForTests(); mParticle.config.dataPlan = { planId: 'plan_slug', }; mParticle.init('foo', mParticle.config); - let sdkEvent = mParticle + const sdkEvent = mParticle .getInstance() ._ServerModel.createEventObject(event); - let upload = mParticle + const upload = mParticle .getInstance() ._ServerModel.convertEventToV2DTO(sdkEvent as IUploadObject); @@ -1167,17 +1160,17 @@ describe('ServerModel', () => { done(); }); - it('Should not convert data plan object to server DTO when no id is set', function(done) { + it('Should not convert data plan object to server DTO when no id is set', function (done) { mParticle._resetForTests(); mParticle.config.dataPlan = { planVersion: 5, }; mParticle.init('foo', mParticle.config); - let sdkEvent = mParticle + const sdkEvent = mParticle .getInstance() ._ServerModel.createEventObject(event); - let upload = mParticle + const upload = mParticle .getInstance() ._ServerModel.convertEventToV2DTO(sdkEvent as IUploadObject); @@ -1186,7 +1179,7 @@ describe('ServerModel', () => { done(); }); - it('Should convert entire data plan object to server DTO', function(done) { + it('Should convert entire data plan object to server DTO', function (done) { mParticle._resetForTests(); mParticle.config.dataPlan = { planId: 'plan_slug', @@ -1194,10 +1187,10 @@ describe('ServerModel', () => { }; mParticle.init('foo', mParticle.config); - let sdkEvent = mParticle + const sdkEvent = mParticle .getInstance() ._ServerModel.createEventObject(event); - let upload = mParticle + const upload = mParticle .getInstance() ._ServerModel.convertEventToV2DTO(sdkEvent as IUploadObject); @@ -1206,7 +1199,7 @@ describe('ServerModel', () => { done(); }); - it('Should convert complete consent object', function(done) { + it('Should convert complete consent object', function (done) { const consentState = mParticle .getInstance() ._Consent.createConsentState(); @@ -1220,8 +1213,8 @@ describe('ServerModel', () => { 10, 'foo document', 'foo location', - 'foo hardware id' - ) + 'foo hardware id', + ), ); // TODO: Resolve differences between SDKConsentState and ConsentState @@ -1229,7 +1222,7 @@ describe('ServerModel', () => { const consent = mParticle .getInstance() ._ServerModel.convertToConsentStateV2DTO( - (consentState as unknown) as SDKConsentState + consentState as unknown as SDKConsentState, ); expect(consent).to.be.ok; @@ -1244,24 +1237,23 @@ describe('ServerModel', () => { done(); }); - it('Should not append user info when no user exists', function(done) { - waitForCondition(hasIdentifyReturned) - .then(() => { - mParticle.getInstance()._Store.should.be.ok; + it('Should not append user info when no user exists', function (done) { + waitForCondition(hasIdentifyReturned).then(() => { + mParticle.getInstance()._Store.should.be.ok; - let sdkEvent = mParticle - .getInstance() - ._ServerModel.createEventObject(event); + const sdkEvent = mParticle + .getInstance() + ._ServerModel.createEventObject(event); - sdkEvent.should.be.ok; - expect(sdkEvent.UserIdentities).to.eql([]); - expect(sdkEvent.UserAttributes).to.eql({}); - expect(sdkEvent.ConsentState === null).to.eql(true); - done(); - }) + sdkEvent.should.be.ok; + expect(sdkEvent.UserIdentities).to.eql([]); + expect(sdkEvent.UserAttributes).to.eql({}); + expect(sdkEvent.ConsentState === null).to.eql(true); + done(); + }); }); - it('Should append all user info when user is present', function(done) { + it('Should append all user info when user is present', function (done) { mParticle.getInstance()._Store.should.be.ok; const consentState = mParticle .getInstance() @@ -1275,8 +1267,8 @@ describe('ServerModel', () => { 10, 'foo document', 'foo location', - 'foo hardware id' - ) + 'foo hardware id', + ), ); const expectedUserIdentities = [ @@ -1321,7 +1313,7 @@ describe('ServerModel', () => { }, } as IMParticleUser; }; - let sdkEvent = mParticle + const sdkEvent = mParticle .getInstance() ._ServerModel.createEventObject(event); @@ -1334,132 +1326,129 @@ describe('ServerModel', () => { done(); }); - it('Should append identities when user is present', function(done) { - waitForCondition(hasIdentifyReturned) - .then(() => { - let sdkEvent = mParticle - .getInstance() - ._ServerModel.createEventObject(event); + it('Should append identities when user is present', function (done) { + waitForCondition(hasIdentifyReturned).then(() => { + const sdkEvent = mParticle + .getInstance() + ._ServerModel.createEventObject(event); - sdkEvent.should.be.ok; - expect(sdkEvent.UserIdentities).to.eql([]); + sdkEvent.should.be.ok; + expect(sdkEvent.UserIdentities).to.eql([]); - const user: IMParticleUser = ({ - getUserIdentities: () => { - return { - userIdentities: { - customerid: '1234567', - email: 'foo-email', - other: 'foo-other', - other2: 'foo-other2', - other3: 'foo-other3', - other4: 'foo-other4', - not_a_valid_id: 'foo', - }, - }; - }, - getAllUserAttributes: () => { - return null; - }, - getMPID: () => { - return null; - }, - getConsentState: () => { - return null; - }, - } as unknown) as IMParticleUser; - - const identityMapping = {}; - identityMapping[Types.IdentityType.CustomerId] = '1234567'; - identityMapping[Types.IdentityType.Email] = 'foo-email'; - identityMapping[Types.IdentityType.Other] = 'foo-other'; - identityMapping[Types.IdentityType.Other2] = 'foo-other2'; - identityMapping[Types.IdentityType.Other3] = 'foo-other3'; - identityMapping[Types.IdentityType.Other4] = 'foo-other4'; - - appendUserInfo(user, sdkEvent); - sdkEvent.UserIdentities.should.be.ok; - sdkEvent.UserIdentities.length.should.equal(6); - - sdkEvent.UserIdentities.forEach(function(id) { - const type = id.Type; - const value = id.Identity; - identityMapping[type].should.equal(value); + const user: IMParticleUser = { + getUserIdentities: () => { + return { + userIdentities: { + customerid: '1234567', + email: 'foo-email', + other: 'foo-other', + other2: 'foo-other2', + other3: 'foo-other3', + other4: 'foo-other4', + not_a_valid_id: 'foo', + }, + }; + }, + getAllUserAttributes: () => { + return null; + }, + getMPID: () => { + return null; + }, + getConsentState: () => { + return null; + }, + } as unknown as IMParticleUser; + + const identityMapping = {}; + identityMapping[Types.IdentityType.CustomerId] = '1234567'; + identityMapping[Types.IdentityType.Email] = 'foo-email'; + identityMapping[Types.IdentityType.Other] = 'foo-other'; + identityMapping[Types.IdentityType.Other2] = 'foo-other2'; + identityMapping[Types.IdentityType.Other3] = 'foo-other3'; + identityMapping[Types.IdentityType.Other4] = 'foo-other4'; + + appendUserInfo(user, sdkEvent); + sdkEvent.UserIdentities.should.be.ok; + sdkEvent.UserIdentities.length.should.equal(6); + + sdkEvent.UserIdentities.forEach(function (id) { + const type = id.Type; + const value = id.Identity; + identityMapping[type].should.equal(value); + }); + + done(); }); - - done(); - }) }); - it('Should append user attributes when user present', function(done) { - waitForCondition(hasIdentifyReturned) - .then(() => { - let sdkEvent = mParticle - .getInstance() - ._ServerModel.createEventObject(event); - - sdkEvent.should.be.ok; - expect(sdkEvent.UserAttributes).to.eql({}); - const attributes = { foo: 'bar', 'foo-arr': ['bar1', 'bar2'] }; - const user: IMParticleUser = { - getUserIdentities: (): IdentityApiData => ({ - userIdentities: {}, - }), - getAllUserAttributes: (): ISDKUserAttributes => { - return attributes; - }, - getMPID: () => { - return null; - }, - getConsentState: () => { - return null; - }, - } as IMParticleUser; + it('Should append user attributes when user present', function (done) { + waitForCondition(hasIdentifyReturned).then(() => { + const sdkEvent = mParticle + .getInstance() + ._ServerModel.createEventObject(event); + + sdkEvent.should.be.ok; + expect(sdkEvent.UserAttributes).to.eql({}); + const attributes = { foo: 'bar', 'foo-arr': ['bar1', 'bar2'] }; + const user: IMParticleUser = { + getUserIdentities: (): IdentityApiData => ({ + userIdentities: {}, + }), + getAllUserAttributes: (): ISDKUserAttributes => { + return attributes; + }, + getMPID: () => { + return null; + }, + getConsentState: () => { + return null; + }, + } as IMParticleUser; - appendUserInfo(user, sdkEvent); - expect(sdkEvent.UserAttributes).to.be.ok; - expect(sdkEvent.UserAttributes).to.eql(attributes); + appendUserInfo(user, sdkEvent); + expect(sdkEvent.UserAttributes).to.be.ok; + expect(sdkEvent.UserAttributes).to.eql(attributes); - done(); + done(); }); }); - it('Should update mpid when user info is appended with a new mpid', function(done) { - waitForCondition(hasIdentifyReturned) - .then(() => { - let sdkEvent = mParticle - .getInstance() - ._ServerModel.createEventObject(event); + it('Should update mpid when user info is appended with a new mpid', function (done) { + waitForCondition(hasIdentifyReturned).then(() => { + const sdkEvent = mParticle + .getInstance() + ._ServerModel.createEventObject(event); - sdkEvent.should.be.ok; + sdkEvent.should.be.ok; - // By default, all tests instances have 'testMPID' - expect(sdkEvent.MPID).to.equal('testMPID'); + // By default, all tests instances have 'testMPID' + expect(sdkEvent.MPID).to.equal('testMPID'); - const user: IMParticleUser = { - getUserIdentities: () => { - return ({ - userIdentites: {}, - } as unknown) as IdentityApiData; - }, - getAllUserAttributes: () => { - return null; - }, - getMPID: () => { - return '98765'; - }, - getConsentState: () => { - return null; - }, - } as IMParticleUser; - appendUserInfo(user, sdkEvent); - expect(sdkEvent.MPID).to.equal('98765'); - done(); - }) + const user: IMParticleUser = { + getUserIdentities: () => { + return { + userIdentites: {}, + } as unknown as IdentityApiData; + }, + getAllUserAttributes: () => { + return null; + }, + getMPID: () => { + return '98765'; + }, + getConsentState: () => { + return null; + }, + } as IMParticleUser; + appendUserInfo(user, sdkEvent); + expect(sdkEvent.MPID).to.equal('98765'); + done(); + }); }); - it('convertEventToDTO should contain launch referral', function(done) { - const event = ({ + it('convertEventToDTO should contain launch referral', function (done) { + const event = { EventName: 10, EventAttributes: null, SourceMessageId: '7efa0811-c716-4a1d-b8bf-dae90242849c', @@ -1485,7 +1474,7 @@ describe('ServerModel', () => { IntegrationAttributes: {}, DataPlan: {}, Timestamp: 1630528218899, - } as unknown) as IUploadObject; + } as unknown as IUploadObject; const upload = mParticle .getInstance() @@ -1496,4 +1485,4 @@ describe('ServerModel', () => { done(); }); }); -}); \ No newline at end of file +}); diff --git a/test/src/tests-session-manager.ts b/test/src/tests-session-manager.ts index 08dde9089..828b3a93e 100644 --- a/test/src/tests-session-manager.ts +++ b/test/src/tests-session-manager.ts @@ -35,11 +35,12 @@ describe('SessionManager', () => { clock = sinon.useFakeTimers(now.getTime()); fetchMockSuccess(urls.identify, { - mpid: testMPID, is_logged_in: false + mpid: testMPID, + is_logged_in: false, }); }); - afterEach(function() { + afterEach(function () { sandbox.restore(); clock.restore(); mParticle._resetForTests(MPConfig); @@ -55,7 +56,7 @@ describe('SessionManager', () => { it('starts a new session if Store does not contain a sessionId', () => { const generateUniqueIdSpy = sinon.stub( mParticle.getInstance()._Helpers, - 'generateUniqueId' + 'generateUniqueId', ); generateUniqueIdSpy.returns('test-unique-id'); @@ -74,7 +75,7 @@ describe('SessionManager', () => { const generateUniqueIdSpy = sinon.stub( mParticle.getInstance()._Helpers, - 'generateUniqueId' + 'generateUniqueId', ); generateUniqueIdSpy.returns('test-unique-id'); @@ -83,9 +84,10 @@ describe('SessionManager', () => { mpInstance._Store.sessionId = 'OLD-ID'; - const timeLastEventSent = mpInstance._Store.dateLastEventSent.getTime(); + const timeLastEventSent = + mpInstance._Store.dateLastEventSent.getTime(); mpInstance._Store.dateLastEventSent = new Date( - timeLastEventSent - timePassed + timeLastEventSent - timePassed, ); mpInstance._SessionManager.initialize(); @@ -100,14 +102,15 @@ describe('SessionManager', () => { mParticle.getInstance()._Store.sessionId = 'OLD-ID'; - const timeLastEventSent = mpInstance._Store.dateLastEventSent.getTime(); + const timeLastEventSent = + mpInstance._Store.dateLastEventSent.getTime(); mpInstance._Store.dateLastEventSent = new Date( - timeLastEventSent - timePassed + timeLastEventSent - timePassed, ); mParticle.getInstance()._SessionManager.initialize(); expect(mParticle.getInstance()._Store.sessionId).to.equal( - 'OLD-ID' + 'OLD-ID', ); }); }); @@ -133,7 +136,7 @@ describe('SessionManager', () => { mpInstance._SessionManager.getSession(); expect(consoleSpy.lastCall.firstArg).to.equal( - 'SessionManager.getSession() is a deprecated method and will be removed in future releases SessionManager.getSessionId() is a deprecated method and will be removed in future releases' + 'SessionManager.getSession() is a deprecated method and will be removed in future releases SessionManager.getSessionId() is a deprecated method and will be removed in future releases', ); }); }); @@ -155,7 +158,7 @@ describe('SessionManager', () => { it('should create a new session', () => { const generateUniqueIdSpy = sinon.stub( mParticle.getInstance()._Helpers, - 'generateUniqueId' + 'generateUniqueId', ); generateUniqueIdSpy.returns('new-session-id'); @@ -190,7 +193,7 @@ describe('SessionManager', () => { const mpInstance = mParticle.getInstance(); const timerSpy = sinon.spy( mpInstance._SessionManager, - 'setSessionTimer' + 'setSessionTimer', ); mpInstance._SessionManager.startNewSession(); @@ -220,7 +223,7 @@ describe('SessionManager', () => { mpInstance._SessionManager.startNewSession(); expect(mpInstance._Store.sessionStartDate).to.eql( - dateInThePast + dateInThePast, ); }); @@ -279,7 +282,7 @@ describe('SessionManager', () => { expect(callbackSpy.called).to.equal(true); expect(mpInstance._Store.identifyCalled).to.eql(true); expect(mpInstance._Store.SDKConfig.identityCallback).to.eql( - null + null, ); }); }); @@ -289,25 +292,25 @@ describe('SessionManager', () => { mParticle.init(apiKey, window.mParticle.config); waitForCondition(() => { return ( - mParticle.Identity.getCurrentUser()?.getMPID() === testMPID + mParticle.Identity.getCurrentUser()?.getMPID() === + testMPID + ); + }).then(() => { + const mpInstance = mParticle.getInstance(); + const persistenceSpy = sinon.spy( + mpInstance._Persistence, + 'update', ); - }) - .then(() => { - const mpInstance = mParticle.getInstance(); - const persistenceSpy = sinon.spy( - mpInstance._Persistence, - 'update' - ); - mpInstance._SessionManager.endSession(); + mpInstance._SessionManager.endSession(); - expect(mpInstance._Store.sessionId).to.equal(null); - expect(mpInstance._Store.dateLastEventSent).to.equal(null); - expect(mpInstance._Store.sessionAttributes).to.eql({}); + expect(mpInstance._Store.sessionId).to.equal(null); + expect(mpInstance._Store.dateLastEventSent).to.equal(null); + expect(mpInstance._Store.sessionAttributes).to.eql({}); - // Persistence isn't necessary for this feature, but we should test - // to see that it is called in case this ever needs to be refactored - expect(persistenceSpy.called).to.equal(true); + // Persistence isn't necessary for this feature, but we should test + // to see that it is called in case this ever needs to be refactored + expect(persistenceSpy.called).to.equal(true); }); }); @@ -316,7 +319,7 @@ describe('SessionManager', () => { const mpInstance = mParticle.getInstance(); const persistenceSpy = sinon.spy( mpInstance._Persistence, - 'update' + 'update', ); mpInstance._SessionManager.endSession(true); @@ -345,10 +348,10 @@ describe('SessionManager', () => { // Should log initial StartingEndSession and NoSessionToEnd messages expect(consoleSpy.getCalls().length).to.equal(2); expect(consoleSpy.firstCall.firstArg).to.equal( - Messages.InformationMessages.StartingEndSession + Messages.InformationMessages.StartingEndSession, ); expect(consoleSpy.lastCall.firstArg).to.equal( - Messages.InformationMessages.NoSessionToEnd + Messages.InformationMessages.NoSessionToEnd, ); }); @@ -367,7 +370,7 @@ describe('SessionManager', () => { // Should log initial StartingEndSession and NoSessionToEnd messages expect(consoleSpy.getCalls().length).to.equal(2); expect(consoleSpy.lastCall.firstArg).to.equal( - Messages.InformationMessages.NoSessionToEnd + Messages.InformationMessages.NoSessionToEnd, ); }); @@ -388,7 +391,7 @@ describe('SessionManager', () => { // Should log initial StartingEndSession and AbandonEndSession messages expect(consoleSpy.getCalls().length).to.equal(2); expect(consoleSpy.lastCall.firstArg).to.equal( - Messages.InformationMessages.AbandonEndSession + Messages.InformationMessages.AbandonEndSession, ); }); @@ -409,7 +412,7 @@ describe('SessionManager', () => { // Should log initial StartingEndSession and AbandonEndSession messagesk expect(consoleSpy.getCalls().length).to.equal(2); expect(consoleSpy.lastCall.firstArg).to.equal( - Messages.InformationMessages.AbandonEndSession + Messages.InformationMessages.AbandonEndSession, ); }); @@ -432,7 +435,7 @@ describe('SessionManager', () => { // Should log initial StartingEndSession and AbandonEndSession messages expect(consoleSpy.getCalls().length).to.equal(2); expect(consoleSpy.lastCall.firstArg).to.equal( - Messages.InformationMessages.AbandonEndSession + Messages.InformationMessages.AbandonEndSession, ); }); @@ -455,7 +458,7 @@ describe('SessionManager', () => { // Should log initial StartingEndSession and NoSessionToEnd messages expect(consoleSpy.getCalls().length).to.equal(2); expect(consoleSpy.lastCall.firstArg).to.equal( - Messages.InformationMessages.NoSessionToEnd + Messages.InformationMessages.NoSessionToEnd, ); }); @@ -474,7 +477,7 @@ describe('SessionManager', () => { mpInstance._SessionManager.endSession(); expect(mpInstance._Store.sessionId).to.equal( - 'cookie-session-id' + 'cookie-session-id', ); }); @@ -488,7 +491,7 @@ describe('SessionManager', () => { const mpInstance = mParticle.getInstance(); const timerSpy = sinon.spy( mpInstance._SessionManager, - 'setSessionTimer' + 'setSessionTimer', ); // Session Manager relies on persistence to determine last event sent (LES) time @@ -515,7 +518,7 @@ describe('SessionManager', () => { it('should end session if the session timeout limit has been reached', () => { const generateUniqueIdSpy = sinon.stub( mParticle.getInstance()._Helpers, - 'generateUniqueId' + 'generateUniqueId', ); generateUniqueIdSpy.returns('test-unique-id'); @@ -535,7 +538,7 @@ describe('SessionManager', () => { const persistenceUpdateSpy = sinon.spy( mpInstance._Persistence, - 'update' + 'update', ); // Session Manager relies on persistence to determine last event seen (LES) time @@ -584,7 +587,7 @@ describe('SessionManager', () => { const mpInstance = mParticle.getInstance(); const endSessionSpy = sinon.spy( mpInstance._SessionManager, - 'endSession' + 'endSession', ); // Start Timer @@ -621,7 +624,7 @@ describe('SessionManager', () => { const startNewSessionSpy = sinon.spy( mpInstance._SessionManager, - 'startNewSession' + 'startNewSession', ); mpInstance._SessionManager.resetSessionTimer(); @@ -636,7 +639,7 @@ describe('SessionManager', () => { const startNewSessionSpy = sinon.spy( mpInstance._SessionManager, - 'startNewSession' + 'startNewSession', ); mpInstance._SessionManager.resetSessionTimer(); @@ -651,15 +654,15 @@ describe('SessionManager', () => { const startNewSessionSpy = sinon.spy( mpInstance._SessionManager, - 'startNewSession' + 'startNewSession', ); const clearSessionTimeoutSpy = sinon.spy( mpInstance._SessionManager, - 'clearSessionTimeout' + 'clearSessionTimeout', ); const setSessionTimerSpy = sinon.spy( mpInstance._SessionManager, - 'setSessionTimer' + 'setSessionTimer', ); mpInstance._SessionManager.resetSessionTimer(); @@ -674,11 +677,11 @@ describe('SessionManager', () => { const clearSessionTimeoutSpy = sinon.spy( mpInstance._SessionManager, - 'clearSessionTimeout' + 'clearSessionTimeout', ); const setSessionTimerSpy = sinon.spy( mpInstance._SessionManager, - 'setSessionTimer' + 'setSessionTimer', ); mpInstance._SessionManager.resetSessionTimer(); @@ -692,7 +695,7 @@ describe('SessionManager', () => { const startNewSessionIfNeededSpy = sinon.spy( mpInstance._SessionManager, - 'startNewSessionIfNeeded' + 'startNewSessionIfNeeded', ); expect(startNewSessionIfNeededSpy.called).to.equal(false); @@ -731,7 +734,7 @@ describe('SessionManager', () => { const startNewSessionSpy = sinon.spy( mpInstance._SessionManager, - 'startNewSession' + 'startNewSession', ); mpInstance._SessionManager.startNewSessionIfNeeded(); @@ -753,7 +756,7 @@ describe('SessionManager', () => { const startNewSessionSpy = sinon.spy( mpInstance._SessionManager, - 'startNewSession' + 'startNewSession', ); mpInstance._SessionManager.startNewSessionIfNeeded(); @@ -791,7 +794,7 @@ describe('SessionManager', () => { const startNewSessionSpy = sinon.spy( mpInstance._SessionManager, - 'startNewSession' + 'startNewSession', ); mpInstance._Store.sessionId = undefined; @@ -814,7 +817,7 @@ describe('SessionManager', () => { const startNewSessionSpy = sinon.spy( mpInstance._SessionManager, - 'startNewSession' + 'startNewSession', ); mpInstance._Store.sessionId = null; @@ -832,7 +835,7 @@ describe('SessionManager', () => { const startNewSessionSpy = sinon.spy( mpInstance._SessionManager, - 'startNewSession' + 'startNewSession', ); mpInstance._SessionManager.startNewSessionIfNeeded(); @@ -845,7 +848,7 @@ describe('SessionManager', () => { it('should end a session if the session timeout expires', () => { const generateUniqueIdSpy = sinon.stub( mParticle.getInstance()._Helpers, - 'generateUniqueId' + 'generateUniqueId', ); generateUniqueIdSpy.returns('test-unique-id'); @@ -882,4 +885,4 @@ describe('SessionManager', () => { expect(persistenceSpy.called).to.equal(true); }); }); -}); \ No newline at end of file +}); diff --git a/test/src/tests-store.ts b/test/src/tests-store.ts index 680040404..b695bd9d6 100644 --- a/test/src/tests-store.ts +++ b/test/src/tests-store.ts @@ -103,14 +103,14 @@ describe('Store', () => { }, }; - beforeEach(function() { + beforeEach(function () { sandbox = sinon.createSandbox(); clock = sinon.useFakeTimers(now.getTime()); // MP Instance is just used because Store requires an mParticle instance window.mParticle.init(apiKey, window.mParticle.config); }); - afterEach(function() { + afterEach(function () { window.mParticle._resetForTests(MPConfig); sandbox.restore(); clock.restore(); @@ -121,7 +121,7 @@ describe('Store', () => { // Use sample config to make sure our types are safe const store: IStore = new Store( sampleConfig, - window.mParticle.getInstance() + window.mParticle.getInstance(), ); expect(store).to.be.ok; expect(store.isEnabled, 'isEnabled').to.eq(true); @@ -145,10 +145,10 @@ describe('Store', () => { expect(store.globalTimer, 'globalTimer').to.eq(null); expect(store.context, 'context').to.eq(null); expect(store.configurationLoaded, 'configurationLoaded').to.eq( - false + false, ); expect(store.identityCallInFlight, 'identityCallInFlight').to.eq( - false + false, ); expect(store.nonCurrentUserMPIDs, 'nonCurrentUserMPIDs').to.be.ok; expect(store.identifyCalled, 'identifyCalled').to.eq(false); @@ -159,7 +159,7 @@ describe('Store', () => { expect(store.requireDelay, 'requireDelay').to.eq(true); expect( store.isLocalStorageAvailable, - 'isLocalStorageAvailable' + 'isLocalStorageAvailable', ).to.eq(null); expect(store.storageName, 'storageName').to.eq(null); expect(store.prodStorageName, 'prodStorageName').to.eq(null); @@ -169,33 +169,33 @@ describe('Store', () => { expect(store.configuredForwarders, 'configuredForwarders').to.be.ok; expect( store.pixelConfigurations.length, - 'pixelConfigurations' + 'pixelConfigurations', ).to.eq(0); expect( store.integrationDelayTimeoutStart, - 'integrationDelayTimeoutStart' + 'integrationDelayTimeoutStart', ).to.eq(clock.now); }); it('should initialize store.SDKConfig with valid defaults', () => { const store: IStore = new Store( sampleConfig, - window.mParticle.getInstance() + window.mParticle.getInstance(), ); expect(store.SDKConfig.aliasMaxWindow, 'aliasMaxWindow').to.eq(90); expect(store.SDKConfig.aliasUrl, 'aliasUrl').to.eq( - 'jssdks.mparticle.com/v1/identity/' + 'jssdks.mparticle.com/v1/identity/', ); expect(store.SDKConfig.appName).to.eq('Store Test'); expect(store.SDKConfig.appVersion, 'appVersion').to.eq('1.x'); expect(store.SDKConfig.cookieDomain, 'cookieDomain').to.eq(null); expect(store.SDKConfig.configUrl, 'configUrl').to.eq( - 'jssdkcdns.mparticle.com/JS/v2/' + 'jssdkcdns.mparticle.com/JS/v2/', ); expect(store.SDKConfig.customFlags, 'customFlags').to.deep.equal( - {} + {}, ); expect(store.SDKConfig.dataPlan, 'dataPlan').to.deep.equal({}); @@ -206,24 +206,24 @@ describe('Store', () => { expect( store.SDKConfig.flags.eventBatchingIntervalMillis, - 'flags.eventBatchingIntervalMillis' + 'flags.eventBatchingIntervalMillis', ).to.eq(0); expect(store.SDKConfig.forceHttps, 'forceHttps').to.eq(true); expect(store.SDKConfig.identityCallback, 'identityCallback').to.be .undefined; expect(store.SDKConfig.identityUrl, 'identityUrl').to.eq( - 'identity.mparticle.com/v1/' + 'identity.mparticle.com/v1/', ); expect(store.SDKConfig.identifyRequest, 'identifyRequest').to.be .undefined; expect( store.SDKConfig.integrationDelayTimeout, - 'integrationDelayTimeout' + 'integrationDelayTimeout', ).to.eq(5000); expect( store.SDKConfig.isDevelopmentMode, - 'isDevelopmentMode' + 'isDevelopmentMode', ).to.eq(false); expect(store.SDKConfig.isIOS, 'isIOS').to.eq(false); @@ -235,31 +235,31 @@ describe('Store', () => { expect(store.SDKConfig.maxProducts, 'maxProducts').to.eq(20); expect( store.SDKConfig.minWebviewBridgeVersion, - 'minWebviewBridgeVersion' + 'minWebviewBridgeVersion', ).to.eq(1); expect(store.SDKConfig.package, 'package').to.eq( - 'com.mparticle.test' + 'com.mparticle.test', ); expect(store.SDKConfig.sessionTimeout, 'sessionTimeout').to.eq(30); expect(store.SDKConfig.useCookieStorage, 'useCookieStorage').to.eq( - false + false, ); expect(store.SDKConfig.useNativeSdk, 'useNativeSdk').to.eq(false); expect( store.SDKConfig.v1SecureServiceUrl, - 'v1SecureServiceUrl' + 'v1SecureServiceUrl', ).to.eq('jssdks.mparticle.com/v1/JS/'); expect( store.SDKConfig.v2SecureServiceUrl, - 'v2SecureServiceUrl' + 'v2SecureServiceUrl', ).to.eq('jssdks.mparticle.com/v2/JS/'); expect( store.SDKConfig.v3SecureServiceUrl, - 'v3SecureServiceUrl' + 'v3SecureServiceUrl', ).to.eq('jssdks.mparticle.com/v3/JS/'); }); @@ -273,7 +273,7 @@ describe('Store', () => { }; const store: IStore = new Store( dataPlanConfig, - window.mParticle.getInstance() + window.mParticle.getInstance(), ); expect(store.SDKConfig.dataPlan, 'dataPlan').to.deep.equal({ @@ -293,20 +293,20 @@ describe('Store', () => { }; const store: IStore = new Store( config, - window.mParticle.getInstance() + window.mParticle.getInstance(), ); expect( store.SDKConfig.sideloadedKits.length, - 'side loaded kits' + 'side loaded kits', ).to.equal(sideloadedKits.length); expect( store.SDKConfig.sideloadedKits[0], - 'side loaded kits' + 'side loaded kits', ).to.deep.equal(sideloadedKit1); expect( store.SDKConfig.sideloadedKits[1], - 'side loaded kits' + 'side loaded kits', ).to.deep.equal(sideloadedKit2); }); @@ -318,7 +318,7 @@ describe('Store', () => { const store: IStore = new Store( config, window.mParticle.getInstance(), - apiKey + apiKey, ); expect(store.devToken, 'devToken').to.equal(apiKey); @@ -329,7 +329,7 @@ describe('Store', () => { it('should move a new mpid to the end of the currentSessionMPIDs list', () => { const store: IStore = new Store( sampleConfig, - window.mParticle.getInstance() + window.mParticle.getInstance(), ); store.sessionId = 'my-session-id'; @@ -347,7 +347,7 @@ describe('Store', () => { it('should move an older mpid to the end of the currentSessionMPIDs list if it exists', () => { const store: IStore = new Store( sampleConfig, - window.mParticle.getInstance() + window.mParticle.getInstance(), ); store.sessionId = 'my-session-id'; @@ -364,7 +364,7 @@ describe('Store', () => { it('should move an mpid to the end of the currentSessionMPIDs list if it is also the previous mpid', () => { const store: IStore = new Store( sampleConfig, - window.mParticle.getInstance() + window.mParticle.getInstance(), ); store.sessionId = 'my-session-id'; @@ -381,7 +381,7 @@ describe('Store', () => { it('should move an mpid to the end of the currentSessionMPIDs list if it exists in the middle of the list', () => { const store: IStore = new Store( sampleConfig, - window.mParticle.getInstance() + window.mParticle.getInstance(), ); store.sessionId = 'my-session-id'; @@ -400,21 +400,21 @@ describe('Store', () => { it('should return a consent state object from the store', () => { const store: IStore = new Store( sampleConfig, - window.mParticle.getInstance() + window.mParticle.getInstance(), ); store.persistenceData[testMPID] = sampleConsentState; expect(store.getConsentState(testMPID)).to.be.ok; expect(store.getConsentState(testMPID)).to.haveOwnProperty( - 'getGDPRConsentState' + 'getGDPRConsentState', ); expect(store.getConsentState(testMPID)).to.haveOwnProperty( - 'getCCPAConsentState' + 'getCCPAConsentState', ); expect( - store.getConsentState(testMPID).getGDPRConsentState() + store.getConsentState(testMPID).getGDPRConsentState(), ).to.deep.equal({ analytics: { Consented: true, @@ -426,7 +426,7 @@ describe('Store', () => { }); expect( - store.getConsentState(testMPID).getCCPAConsentState() + store.getConsentState(testMPID).getCCPAConsentState(), ).to.deep.equal({ Consented: false, ConsentDocument: 'foo ccpa document', @@ -439,7 +439,7 @@ describe('Store', () => { it('should return null if no consent state is found', () => { const store: IStore = new Store( sampleConfig, - window.mParticle.getInstance() + window.mParticle.getInstance(), ); expect(store.getConsentState(testMPID)).to.deep.equal(null); @@ -448,7 +448,7 @@ describe('Store', () => { it('should return in-memory consent state if persistence is empty', () => { const store: IStore = new Store( sampleConfig, - window.mParticle.getInstance() + window.mParticle.getInstance(), ); store.persistenceData[testMPID] = sampleConsentStateFromStore; @@ -458,10 +458,10 @@ describe('Store', () => { expect(store.getConsentState(testMPID)).to.be.ok; expect(store.getConsentState(testMPID)).to.haveOwnProperty( - 'getGDPRConsentState' + 'getGDPRConsentState', ); expect( - store.getConsentState(testMPID).getGDPRConsentState() + store.getConsentState(testMPID).getGDPRConsentState(), ).to.deep.equal({ analytics: { Consented: false, @@ -473,11 +473,11 @@ describe('Store', () => { }); expect(store.getConsentState(testMPID)).to.haveOwnProperty( - 'getCCPAConsentState' + 'getCCPAConsentState', ); expect( - store.getConsentState(testMPID).getCCPAConsentState() + store.getConsentState(testMPID).getCCPAConsentState(), ).to.deep.equal({ Consented: true, ConsentDocument: 'foo ccpa document from store', @@ -492,7 +492,7 @@ describe('Store', () => { it('should set consent state as a minified object in the store', () => { const store: IStore = new Store( sampleConfig, - window.mParticle.getInstance() + window.mParticle.getInstance(), ); const consentState = window.mParticle.Consent.createConsentState(); @@ -504,7 +504,7 @@ describe('Store', () => { 10, 'foo gdpr document', 'foo gdpr location', - 'foo gdpr hardware id' + 'foo gdpr hardware id', ); const ccpaConsent = window.mParticle @@ -514,7 +514,7 @@ describe('Store', () => { 42, 'foo ccpa document', 'foo ccpa location', - 'foo ccpa hardware id' + 'foo ccpa hardware id', ); const expectedConsentState = sampleConsentState.con; @@ -528,19 +528,19 @@ describe('Store', () => { expect(store.persistenceData[testMPID].con.gdpr).to.be.ok; expect(store.persistenceData[testMPID].con.gdpr).to.deep.equal( - expectedConsentState.gdpr + expectedConsentState.gdpr, ); expect(store.persistenceData[testMPID].con.ccpa).to.be.ok; expect(store.persistenceData[testMPID].con.ccpa).to.deep.equal( - expectedConsentState.ccpa + expectedConsentState.ccpa, ); }); it('should set consent state as a minified object in persistence', () => { const store: IStore = new Store( sampleConfig, - window.mParticle.getInstance() + window.mParticle.getInstance(), ); const consentState = window.mParticle.Consent.createConsentState(); @@ -552,7 +552,7 @@ describe('Store', () => { 10, 'foo gdpr document', 'foo gdpr location', - 'foo gdpr hardware id' + 'foo gdpr hardware id', ); const ccpaConsent = window.mParticle @@ -562,7 +562,7 @@ describe('Store', () => { 42, 'foo ccpa document', 'foo ccpa location', - 'foo ccpa hardware id' + 'foo ccpa hardware id', ); const expectedConsentState = sampleConsentState.con; @@ -581,12 +581,12 @@ describe('Store', () => { expect(fromPersistence[testMPID].con.gdpr).to.be.ok; expect(fromPersistence[testMPID].con.gdpr).to.deep.equal( - expectedConsentState.gdpr + expectedConsentState.gdpr, ); expect(fromPersistence[testMPID].con.ccpa).to.be.ok; expect(fromPersistence[testMPID].con.ccpa).to.deep.equal( - expectedConsentState.ccpa + expectedConsentState.ccpa, ); }); @@ -600,7 +600,7 @@ describe('Store', () => { 101, 'analytics gdpr document from store', 'analytics gdpr location from store', - 'analytics gdpr hardware id from store' + 'analytics gdpr hardware id from store', ); const marketingGdprConsent = window.mParticle @@ -610,7 +610,7 @@ describe('Store', () => { 202, 'marketing gdpr document from store', 'marketing gdpr location from store', - 'marketing gdpr hardware id from store' + 'marketing gdpr hardware id from store', ); const ccpaConsent = window.mParticle @@ -620,7 +620,7 @@ describe('Store', () => { 24, 'foo ccpa document from store', 'foo ccpa location from store', - 'foo ccpa hardware id from store' + 'foo ccpa hardware id from store', ); const expectedConsentState = sampleConsentStateFromStore.con; @@ -638,7 +638,7 @@ describe('Store', () => { const store: IStore = new Store( sampleConfig, - window.mParticle.getInstance() + window.mParticle.getInstance(), ); store.setConsentState(testMPID, consentState); @@ -663,7 +663,7 @@ describe('Store', () => { }); expect(fromPersistence[testMPID].con.ccpa).to.deep.equal( - expectedConsentState.ccpa + expectedConsentState.ccpa, ); consentState.addGDPRConsentState('marketing', marketingGdprConsent); @@ -694,7 +694,7 @@ describe('Store', () => { it('should not set consent state if consent state is null', () => { const store: IStore = new Store( sampleConfig, - window.mParticle.getInstance() + window.mParticle.getInstance(), ); const expectedConsentState = sampleConsentState; @@ -704,7 +704,7 @@ describe('Store', () => { store.setConsentState(testMPID, null); expect(store.persistenceData[testMPID]).to.deep.equal( - expectedConsentState + expectedConsentState, ); }); }); @@ -713,7 +713,7 @@ describe('Store', () => { it('should return the deviceId from the store', () => { const store: IStore = new Store( sampleConfig, - window.mParticle.getInstance() + window.mParticle.getInstance(), ); store.deviceId = 'foo'; @@ -726,7 +726,7 @@ describe('Store', () => { it('should return user attributes from the store', () => { const store: IStore = new Store( sampleConfig, - window.mParticle.getInstance() + window.mParticle.getInstance(), ); store.persistenceData[testMPID] = { @@ -741,7 +741,7 @@ describe('Store', () => { it('should return an empty object if mpid is null', () => { const store: IStore = new Store( sampleConfig, - window.mParticle.getInstance() + window.mParticle.getInstance(), ); expect(store.getUserAttributes(null)).to.deep.equal({}); @@ -750,7 +750,7 @@ describe('Store', () => { it('should return an empty object if no user attributes are found', () => { const store: IStore = new Store( sampleConfig, - window.mParticle.getInstance() + window.mParticle.getInstance(), ); expect(store.getUserAttributes(testMPID)).to.deep.equal({}); @@ -761,7 +761,7 @@ describe('Store', () => { it('should set user attributes in the store, overwriting any previous user attributes that exist', () => { const store: IStore = new Store( sampleConfig, - window.mParticle.getInstance() + window.mParticle.getInstance(), ); store.setUserAttributes(testMPID, { foo: 'bar' }); @@ -778,7 +778,7 @@ describe('Store', () => { it('should set user attributes in persistence', () => { const store: IStore = new Store( sampleConfig, - window.mParticle.getInstance() + window.mParticle.getInstance(), ); store.setUserAttributes(testMPID, { foo: 'bar' }); @@ -809,7 +809,7 @@ describe('Store', () => { const store: IStore = new Store( sampleConfig, - window.mParticle.getInstance() + window.mParticle.getInstance(), ); store.setUserAttributes(testMPID, { fizz: 'buzz' }); @@ -829,7 +829,7 @@ describe('Store', () => { it('should set the deviceId in the store', () => { const store: IStore = new Store( sampleConfig, - window.mParticle.getInstance() + window.mParticle.getInstance(), ); store.setDeviceId('foo'); @@ -853,7 +853,7 @@ describe('Store', () => { it('should return the firstSeenTime from the store', () => { const store: IStore = new Store( sampleConfig, - window.mParticle.getInstance() + window.mParticle.getInstance(), ); store.persistenceData[testMPID] = { fst: 12345, @@ -864,7 +864,7 @@ describe('Store', () => { it('should return null if mpid is null', () => { const store: IStore = new Store( sampleConfig, - window.mParticle.getInstance() + window.mParticle.getInstance(), ); expect(store.getFirstSeenTime(null)).to.equal(null); @@ -873,7 +873,7 @@ describe('Store', () => { it('should return null if no firstSeenTime is found', () => { const store: IStore = new Store( sampleConfig, - window.mParticle.getInstance() + window.mParticle.getInstance(), ); expect(store.getFirstSeenTime(testMPID)).to.equal(null); }); @@ -883,7 +883,7 @@ describe('Store', () => { it('should set the firstSeenTime in the store', () => { const store: IStore = new Store( sampleConfig, - window.mParticle.getInstance() + window.mParticle.getInstance(), ); store.setFirstSeenTime(testMPID, 12345); @@ -893,7 +893,7 @@ describe('Store', () => { it('should return undefined if mpid is null', () => { const store: IStore = new Store( sampleConfig, - window.mParticle.getInstance() + window.mParticle.getInstance(), ); expect(store.setFirstSeenTime(null, 12345)).to.equal(undefined); @@ -902,7 +902,7 @@ describe('Store', () => { it('should set the firstSeenTime in persistence', () => { const store: IStore = new Store( sampleConfig, - window.mParticle.getInstance() + window.mParticle.getInstance(), ); store.setFirstSeenTime(testMPID, 12345); @@ -926,7 +926,7 @@ describe('Store', () => { const store: IStore = new Store( sampleConfig, - window.mParticle.getInstance() + window.mParticle.getInstance(), ); store.setFirstSeenTime(testMPID, 54321); @@ -944,7 +944,7 @@ describe('Store', () => { it('should return the lastSeenTime from the store', () => { const store: IStore = new Store( sampleConfig, - window.mParticle.getInstance() + window.mParticle.getInstance(), ); store.persistenceData[testMPID] = { @@ -957,7 +957,7 @@ describe('Store', () => { it('should return null if no lastSeenTime is found', () => { const store: IStore = new Store( sampleConfig, - window.mParticle.getInstance() + window.mParticle.getInstance(), ); expect(store.getLastSeenTime(testMPID)).to.equal(null); @@ -966,7 +966,7 @@ describe('Store', () => { it('should return null if mpid is null', () => { const store: IStore = new Store( sampleConfig, - window.mParticle.getInstance() + window.mParticle.getInstance(), ); expect(store.getLastSeenTime(null)).to.equal(null); @@ -975,7 +975,7 @@ describe('Store', () => { it('should return the current time if mpid matches current user', () => { const userSpy = sinon.stub( window.mParticle.getInstance().Identity, - 'getCurrentUser' + 'getCurrentUser', ); userSpy.returns({ getMPID: () => 'testMPID', @@ -983,7 +983,7 @@ describe('Store', () => { const store: IStore = new Store( sampleConfig, - window.mParticle.getInstance() + window.mParticle.getInstance(), ); expect(store.getLastSeenTime(testMPID)).to.equal(now.getTime()); @@ -994,7 +994,7 @@ describe('Store', () => { it('should set the lastSeenTime in the store', () => { const store: IStore = new Store( sampleConfig, - window.mParticle.getInstance() + window.mParticle.getInstance(), ); store.setLastSeenTime(testMPID, 12345); @@ -1004,7 +1004,7 @@ describe('Store', () => { it('should set the lastSeenTime in persistence', () => { const store: IStore = new Store( sampleConfig, - window.mParticle.getInstance() + window.mParticle.getInstance(), ); store.setLastSeenTime(testMPID, 12345); @@ -1028,7 +1028,7 @@ describe('Store', () => { const store: IStore = new Store( sampleConfig, - window.mParticle.getInstance() + window.mParticle.getInstance(), ); store.setLastSeenTime(testMPID, 54321); @@ -1046,7 +1046,7 @@ describe('Store', () => { it('should return the userIdentities from the store', () => { const store: IStore = new Store( sampleConfig, - window.mParticle.getInstance() + window.mParticle.getInstance(), ); store.persistenceData[testMPID] = { @@ -1061,7 +1061,7 @@ describe('Store', () => { it('should return an empty object if mpid is null', () => { const store: IStore = new Store( sampleConfig, - window.mParticle.getInstance() + window.mParticle.getInstance(), ); expect(store.getUserIdentities(null)).to.deep.equal({}); @@ -1070,7 +1070,7 @@ describe('Store', () => { it('should return an empty object if no userIdentities are found', () => { const store: IStore = new Store( sampleConfig, - window.mParticle.getInstance() + window.mParticle.getInstance(), ); expect(store.getUserIdentities(testMPID)).to.deep.equal({}); @@ -1081,7 +1081,7 @@ describe('Store', () => { it('should set userIdentities in the store', () => { const store: IStore = new Store( sampleConfig, - window.mParticle.getInstance() + window.mParticle.getInstance(), ); store.setUserIdentities(testMPID, { customerid: '12345' }); @@ -1093,7 +1093,7 @@ describe('Store', () => { it('should set userIdentities in persistence', () => { const store: IStore = new Store( sampleConfig, - window.mParticle.getInstance() + window.mParticle.getInstance(), ); store.setUserIdentities(testMPID, { customerid: '12345' }); @@ -1119,7 +1119,7 @@ describe('Store', () => { const store: IStore = new Store( sampleConfig, - window.mParticle.getInstance() + window.mParticle.getInstance(), ); store.setUserIdentities(testMPID, { customerid: '54321' }); @@ -1134,12 +1134,12 @@ describe('Store', () => { }); }); }); - + describe('#nullifySessionData', () => { it('should nullify session data on the store', () => { const store: IStore = new Store( sampleConfig, - window.mParticle.getInstance() + window.mParticle.getInstance(), ); store.sessionId = '123'; @@ -1246,7 +1246,7 @@ describe('Store', () => { const store: IStore = new Store( config, - window.mParticle.getInstance() + window.mParticle.getInstance(), ); store.processConfig(config); @@ -1273,17 +1273,17 @@ describe('Store', () => { const store: IStore = new Store( config, - window.mParticle.getInstance() + window.mParticle.getInstance(), ); store.processConfig(config); expect(store.storageName, 'storageName').to.equal('mprtcl-v4_foo'); expect(store.prodStorageName, 'prodStorageName').to.equal( - 'mprtcl-prodv4_foo' + 'mprtcl-prodv4_foo', ); expect(store.SDKConfig.workspaceToken, 'workspace token').to.equal( - 'foo' + 'foo', ); }); @@ -1294,19 +1294,19 @@ describe('Store', () => { const store: IStore = new Store( config, - window.mParticle.getInstance() + window.mParticle.getInstance(), ); const warnSpy = sinon.spy( window.mParticle.getInstance().Logger, - 'warning' + 'warning', ); store.processConfig(config); expect(warnSpy.calledOnce, 'should call Logger.warn').to.be.true; expect(warnSpy.getCall(0).firstArg).to.equal( - 'You should have a workspaceToken on your config object for security purposes.' + 'You should have a workspaceToken on your config object for security purposes.', ); }); @@ -1319,14 +1319,14 @@ describe('Store', () => { const store: IStore = new Store( config, - window.mParticle.getInstance() + window.mParticle.getInstance(), ); store.processConfig(config); expect( store.SDKConfig.requiredWebviewBridgeName, - 'webviewBridgeName' + 'webviewBridgeName', ).to.equal('my-webview-bridge-name'); }); @@ -1338,14 +1338,14 @@ describe('Store', () => { const store: IStore = new Store( config, - window.mParticle.getInstance() + window.mParticle.getInstance(), ); store.processConfig(config); expect( store.SDKConfig.requiredWebviewBridgeName, - 'webviewBridgeName' + 'webviewBridgeName', ).to.equal('my-workspace-token'); }); @@ -1357,7 +1357,7 @@ describe('Store', () => { const store: IStore = new Store( config, - window.mParticle.getInstance() + window.mParticle.getInstance(), ); // Webview bridge requires a bridge name set on the global mParticle object @@ -1378,7 +1378,7 @@ describe('Store', () => { const store: IStore = new Store( config, - window.mParticle.getInstance() + window.mParticle.getInstance(), ); store.processConfig(config); @@ -1401,7 +1401,7 @@ describe('Store', () => { const store: IStore = new Store( sampleConfig, - window.mParticle.getInstance() + window.mParticle.getInstance(), ); store.syncPersistenceData(); @@ -1409,7 +1409,7 @@ describe('Store', () => { expect(store.persistenceData[testMPID].lst).to.equal(12345); expect(store.persistenceData[testMPID].fst).to.equal(54321); expect(store.persistenceData[testMPID].con).to.deep.equal( - sampleConsentStateFromPersistence.con + sampleConsentStateFromPersistence.con, ); }); @@ -1426,7 +1426,7 @@ describe('Store', () => { const store: IStore = new Store( sampleConfig, - window.mParticle.getInstance() + window.mParticle.getInstance(), ); store.persistenceData[testMPID] = { @@ -1440,7 +1440,7 @@ describe('Store', () => { expect(store.persistenceData[testMPID].lst).to.equal(12345); expect(store.persistenceData[testMPID].fst).to.equal(54321); expect(store.persistenceData[testMPID].con).to.deep.equal( - sampleConsentStateFromPersistence.con + sampleConsentStateFromPersistence.con, ); }); }); @@ -1479,9 +1479,9 @@ describe('Store', () => { astBackgroundEvents: 'True', }; - const flags = processFlags( - ({ flags: cutomizedFlags } as unknown) as SDKInitConfig - ); + const flags = processFlags({ + flags: cutomizedFlags, + } as unknown as SDKInitConfig); const expectedResult = { reportBatching: true, @@ -1506,9 +1506,9 @@ describe('Store', () => { const baseUrls: Dictionary = Constants.DefaultBaseUrls; const result = processBaseUrls( - ({} as unknown) as SDKInitConfig, - (featureFlags as unknown) as IFeatureFlags, - 'apikey' + {} as unknown as SDKInitConfig, + featureFlags as unknown as IFeatureFlags, + 'apikey', ); expect(result).to.deep.equal(baseUrls); @@ -1524,9 +1524,9 @@ describe('Store', () => { }; const result = processBaseUrls( - (config as unknown) as SDKInitConfig, - (featureFlags as unknown) as IFeatureFlags, - 'apikey' + config as unknown as SDKInitConfig, + featureFlags as unknown as IFeatureFlags, + 'apikey', ); const expectedResult = { @@ -1543,16 +1543,16 @@ describe('Store', () => { }); it('should append url paths to domain when config.domain is set', () => { - // This example assumes only the domain is set, and not any of the + // This example assumes only the domain is set, and not any of the // configurable URLs const config = { - domain: 'custom.domain.com' + domain: 'custom.domain.com', }; const result = processBaseUrls( - (config as unknown) as SDKInitConfig, - (featureFlags as unknown) as IFeatureFlags, - 'apikey' + config as unknown as SDKInitConfig, + featureFlags as unknown as IFeatureFlags, + 'apikey', ); const expectedResult = { @@ -1568,7 +1568,7 @@ describe('Store', () => { }); it('should prioritize domain over custom baseUrls when both are set', () => { - // If both the domain and other configurable URLs are set, then + // If both the domain and other configurable URLs are set, then // we use the domain. A customer should not be passing in both, as // that would be an implementation error. const config = { @@ -1582,9 +1582,9 @@ describe('Store', () => { }; const result = processBaseUrls( - (config as unknown) as SDKInitConfig, - (featureFlags as unknown) as IFeatureFlags, - 'apikey' + config as unknown as SDKInitConfig, + featureFlags as unknown as IFeatureFlags, + 'apikey', ); const expectedResult = { @@ -1605,9 +1605,9 @@ describe('Store', () => { const featureFlags = { directURLRouting: true }; const result = processBaseUrls( - ({} as unknown) as SDKInitConfig, - (featureFlags as unknown) as IFeatureFlags, - 'apikey' + {} as unknown as SDKInitConfig, + featureFlags as unknown as IFeatureFlags, + 'apikey', ); const expectedResult = { @@ -1623,13 +1623,13 @@ describe('Store', () => { expect(result.configUrl).to.equal(expectedResult.configUrl); expect(result.identityUrl).to.equal(expectedResult.identityUrl); expect(result.v1SecureServiceUrl).to.equal( - expectedResult.v1SecureServiceUrl + expectedResult.v1SecureServiceUrl, ); expect(result.v2SecureServiceUrl).to.equal( - expectedResult.v2SecureServiceUrl + expectedResult.v2SecureServiceUrl, ); expect(result.v3SecureServiceUrl).to.equal( - expectedResult.v3SecureServiceUrl + expectedResult.v3SecureServiceUrl, ); }); @@ -1645,9 +1645,9 @@ describe('Store', () => { }; const result = processBaseUrls( - (config as unknown) as SDKInitConfig, - (featureFlags as unknown) as IFeatureFlags, - 'apikey' + config as unknown as SDKInitConfig, + featureFlags as unknown as IFeatureFlags, + 'apikey', ); const expectedResult = { @@ -1664,4 +1664,4 @@ describe('Store', () => { }); }); }); -}); \ No newline at end of file +}); diff --git a/test/src/tests-types.js b/test/src/tests-types.js index 6b4d2e682..d8ed07748 100644 --- a/test/src/tests-types.js +++ b/test/src/tests-types.js @@ -1,166 +1,166 @@ import Types from '../../src/types'; -var EventType = Types.EventType, +const EventType = Types.EventType, CommerceEventType = Types.CommerceEventType, ProductActionType = Types.ProductActionType, PromotionType = Types.PromotionActionType, IdentityType = Types.IdentityType; -describe('Types', function() { - describe('Environment', function() { - it('should return `production`', function() { +describe('Types', function () { + describe('Environment', function () { + it('should return `production`', function () { mParticle.Types.Environment.Production.should.equal('production'); }); - it('should return `development`', function() { + it('should return `development`', function () { mParticle.Types.Environment.Development.should.equal('development'); }); }); - it('event type should return name', function(done) { + it('event type should return name', function (done) { mParticle.EventType.getName(EventType.Navigation).should.equal( - 'Navigation' + 'Navigation', ); mParticle.EventType.getName(EventType.Location).should.equal( - 'Location' + 'Location', ); mParticle.EventType.getName(EventType.Search).should.equal('Search'); mParticle.EventType.getName(EventType.Transaction).should.equal( - 'Transaction' + 'Transaction', ); mParticle.EventType.getName(EventType.UserContent).should.equal( - 'User Content' + 'User Content', ); mParticle.EventType.getName(EventType.UserPreference).should.equal( - 'User Preference' + 'User Preference', ); mParticle.EventType.getName(EventType.Social).should.equal('Social'); mParticle.EventType.getName( - CommerceEventType.ProductAddToCart + CommerceEventType.ProductAddToCart, ).should.equal('Product Added to Cart'); mParticle.EventType.getName( - CommerceEventType.ProductAddToWishlist + CommerceEventType.ProductAddToWishlist, ).should.equal('Product Added to Wishlist'); mParticle.EventType.getName( - CommerceEventType.ProductCheckout + CommerceEventType.ProductCheckout, ).should.equal('Product Checkout'); mParticle.EventType.getName( - CommerceEventType.ProductCheckoutOption + CommerceEventType.ProductCheckoutOption, ).should.equal('Product Checkout Options'); mParticle.EventType.getName( - CommerceEventType.ProductClick + CommerceEventType.ProductClick, ).should.equal('Product Click'); mParticle.EventType.getName( - CommerceEventType.ProductImpression + CommerceEventType.ProductImpression, ).should.equal('Product Impression'); mParticle.EventType.getName( - CommerceEventType.ProductPurchase + CommerceEventType.ProductPurchase, ).should.equal('Product Purchased'); mParticle.EventType.getName( - CommerceEventType.ProductRefund + CommerceEventType.ProductRefund, ).should.equal('Product Refunded'); mParticle.EventType.getName( - CommerceEventType.ProductRemoveFromCart + CommerceEventType.ProductRemoveFromCart, ).should.equal('Product Removed From Cart'); mParticle.EventType.getName( - CommerceEventType.ProductRemoveFromWishlist + CommerceEventType.ProductRemoveFromWishlist, ).should.equal('Product Removed from Wishlist'); mParticle.EventType.getName( - CommerceEventType.ProductViewDetail + CommerceEventType.ProductViewDetail, ).should.equal('Product View Details'); mParticle.EventType.getName( - CommerceEventType.PromotionClick + CommerceEventType.PromotionClick, ).should.equal('Promotion Click'); mParticle.EventType.getName( - CommerceEventType.PromotionView + CommerceEventType.PromotionView, ).should.equal('Promotion View'); mParticle.EventType.getName(null).should.equal('Other'); done(); }); - it('identity type should return name', function(done) { + it('identity type should return name', function (done) { mParticle.IdentityType.getName(IdentityType.CustomerId).should.equal( - 'Customer ID' + 'Customer ID', ); mParticle.IdentityType.getName(IdentityType.Facebook).should.equal( - 'Facebook ID' + 'Facebook ID', ); mParticle.IdentityType.getName(IdentityType.Twitter).should.equal( - 'Twitter ID' + 'Twitter ID', ); mParticle.IdentityType.getName(IdentityType.Google).should.equal( - 'Google ID' + 'Google ID', ); mParticle.IdentityType.getName(IdentityType.Microsoft).should.equal( - 'Microsoft ID' + 'Microsoft ID', ); mParticle.IdentityType.getName(IdentityType.Yahoo).should.equal( - 'Yahoo ID' + 'Yahoo ID', ); mParticle.IdentityType.getName(IdentityType.Email).should.equal( - 'Email' + 'Email', ); mParticle.IdentityType.getName( - IdentityType.FacebookCustomAudienceId + IdentityType.FacebookCustomAudienceId, ).should.equal('Facebook App User ID'); mParticle.IdentityType.getName(null).should.equal('Other ID'); done(); }); - it('product action type should return name', function(done) { + it('product action type should return name', function (done) { mParticle.ProductActionType.getName( - ProductActionType.AddToCart + ProductActionType.AddToCart, ).should.equal('Add to Cart'); mParticle.ProductActionType.getName( - ProductActionType.RemoveFromCart + ProductActionType.RemoveFromCart, ).should.equal('Remove from Cart'); mParticle.ProductActionType.getName( - ProductActionType.Checkout + ProductActionType.Checkout, ).should.equal('Checkout'); mParticle.ProductActionType.getName( - ProductActionType.CheckoutOption + ProductActionType.CheckoutOption, ).should.equal('Checkout Option'); mParticle.ProductActionType.getName( - ProductActionType.Click + ProductActionType.Click, ).should.equal('Click'); mParticle.ProductActionType.getName( - ProductActionType.ViewDetail + ProductActionType.ViewDetail, ).should.equal('View Detail'); mParticle.ProductActionType.getName( - ProductActionType.Purchase + ProductActionType.Purchase, ).should.equal('Purchase'); mParticle.ProductActionType.getName( - ProductActionType.Refund + ProductActionType.Refund, ).should.equal('Refund'); mParticle.ProductActionType.getName( - ProductActionType.AddToWishlist + ProductActionType.AddToWishlist, ).should.equal('Add to Wishlist'); mParticle.ProductActionType.getName( - ProductActionType.RemoveFromWishlist + ProductActionType.RemoveFromWishlist, ).should.equal('Remove from Wishlist'); mParticle.ProductActionType.getName(null).should.equal('Unknown'); done(); }); - it('promotion action type should return name', function(done) { + it('promotion action type should return name', function (done) { mParticle.PromotionType.getName( - PromotionType.PromotionView + PromotionType.PromotionView, ).should.equal('Promotion View'); mParticle.PromotionType.getName( - PromotionType.PromotionClick + PromotionType.PromotionClick, ).should.equal('Promotion Click'); mParticle.PromotionType.getName(null).should.equal('Unknown'); done(); }); - it('should return false for an invalid identity type and true for a valid identity type', function(done) { - var invalidResult1 = IdentityType.isValid(11); - var invalidResult2 = IdentityType.isValid('5'); - var validResult = IdentityType.isValid(1); + it('should return false for an invalid identity type and true for a valid identity type', function (done) { + const invalidResult1 = IdentityType.isValid(11); + const invalidResult2 = IdentityType.isValid('5'); + const validResult = IdentityType.isValid(1); invalidResult1.should.be.false; invalidResult2.should.be.false; diff --git a/test/src/tests-user.ts b/test/src/tests-user.ts index 19637ff13..69bebab73 100644 --- a/test/src/tests-user.ts +++ b/test/src/tests-user.ts @@ -1,14 +1,10 @@ -import sinon from 'sinon'; import { expect } from 'chai'; import Utils from './config/utils'; -import Constants from '../../src/constants'; import { urls, apiKey, MPConfig, testMPID } from './config/constants'; import fetchMock from 'fetch-mock/esm/client'; import { IMParticleInstanceManager } from '../../src/sdkRuntimeModels'; const { fetchMockSuccess, waitForCondition } = Utils; -const { HTTPCodes } = Constants; - declare global { interface Window { mParticle: IMParticleInstanceManager; @@ -16,7 +12,7 @@ declare global { } } -const mParticle = window.mParticle as IMParticleInstanceManager;; +const mParticle = window.mParticle as IMParticleInstanceManager; // https://go.mparticle.com/work/SQDSDKS-6849 const hasIdentifyReturned = () => { @@ -24,177 +20,186 @@ const hasIdentifyReturned = () => { }; // https://go.mparticle.com/work/SQDSDKS-6508 -describe('mParticle User', function() { - beforeEach(function() { +describe('mParticle User', function () { + beforeEach(function () { delete mParticle.config.useCookieStorage; fetchMock.post(urls.events, 200); localStorage.clear(); fetchMockSuccess(urls.identify, { - mpid: testMPID, is_logged_in: false + mpid: testMPID, + is_logged_in: false, }); mParticle.init(apiKey, window.mParticle.config); }); - afterEach(function() { + afterEach(function () { fetchMock.restore(); mParticle._resetForTests(MPConfig); }); - describe('Consent State', function() { - it('get/set consent state for single user', done => { + describe('Consent State', function () { + it('get/set consent state for single user', (done) => { mParticle._resetForTests(MPConfig); mParticle.init(apiKey, mParticle.config); - waitForCondition(hasIdentifyReturned) - .then(() => { - let consentState = mParticle - .getInstance() - .Identity.getCurrentUser() - .getConsentState(); - - expect(consentState).to.equal(null); - consentState = mParticle.Consent.createConsentState(); - consentState.addGDPRConsentState( - 'foo purpose', - mParticle.Consent.createGDPRConsent(true, 10) - ); - - mParticle - .getInstance() - .Identity.getCurrentUser() - .setConsentState(consentState); - - const storedConsentState = mParticle - .getInstance() - .Identity.getCurrentUser() - .getConsentState(); - expect(storedConsentState).to.be.ok; - expect(storedConsentState.getGDPRConsentState()).to.have.property( - 'foo purpose' - ); - expect( - storedConsentState.getGDPRConsentState()['foo purpose'] - ).to.have.property('Consented', true); - expect( - storedConsentState.getGDPRConsentState()['foo purpose'] - ).to.have.property('Timestamp', 10); - done(); - }); + waitForCondition(hasIdentifyReturned).then(() => { + let consentState = mParticle + .getInstance() + .Identity.getCurrentUser() + .getConsentState(); + + expect(consentState).to.equal(null); + consentState = mParticle.Consent.createConsentState(); + consentState.addGDPRConsentState( + 'foo purpose', + mParticle.Consent.createGDPRConsent(true, 10), + ); + + mParticle + .getInstance() + .Identity.getCurrentUser() + .setConsentState(consentState); + + const storedConsentState = mParticle + .getInstance() + .Identity.getCurrentUser() + .getConsentState(); + expect(storedConsentState).to.be.ok; + expect( + storedConsentState.getGDPRConsentState(), + ).to.have.property('foo purpose'); + expect( + storedConsentState.getGDPRConsentState()['foo purpose'], + ).to.have.property('Consented', true); + expect( + storedConsentState.getGDPRConsentState()['foo purpose'], + ).to.have.property('Timestamp', 10); + done(); + }); }); - it('get/set consent state for multiple users', done => { + it('get/set consent state for multiple users', (done) => { mParticle._resetForTests(MPConfig); mParticle.init(apiKey, mParticle.config); - waitForCondition(hasIdentifyReturned) - .then(() => { - const userIdentities1 = { - userIdentities: { - customerid: 'foo1', - }, - }; - - fetchMockSuccess(urls.login, { - mpid: 'loginMPID1', is_logged_in: false + waitForCondition(hasIdentifyReturned).then(() => { + const userIdentities1 = { + userIdentities: { + customerid: 'foo1', + }, + }; + + fetchMockSuccess(urls.login, { + mpid: 'loginMPID1', + is_logged_in: false, + }); + + mParticle.Identity.login(userIdentities1); + waitForCondition(() => { + return ( + mParticle.Identity.getCurrentUser()?.getMPID() === + 'loginMPID1' + ); + }).then(() => { + let user1StoredConsentState = mParticle + .getInstance() + .Identity.getCurrentUser() + .getConsentState(); + expect(user1StoredConsentState).to.equal(null); + const consentState = mParticle.Consent.createConsentState(); + consentState.addGDPRConsentState( + 'foo purpose', + mParticle.Consent.createGDPRConsent(true, 10), + ); + + mParticle + .getInstance() + .Identity.getCurrentUser() + .setConsentState(consentState); + + fetchMockSuccess(urls.login, { + mpid: 'loginMPID2', + is_logged_in: false, + }); + + const userIdentities2 = { + userIdentities: { + customerid: 'foo2', + }, + }; + + mParticle.Identity.login(userIdentities2); + waitForCondition(() => { + return ( + mParticle.Identity.getCurrentUser()?.getMPID() === + 'loginMPID2' + ); + }).then(() => { + let user2StoredConsentState = mParticle + .getInstance() + .Identity.getCurrentUser() + .getConsentState(); + expect(user2StoredConsentState).to.equal(null); + + consentState.removeGDPRConsentState('foo purpose'); + + consentState.addGDPRConsentState( + 'foo purpose 2', + mParticle.Consent.createGDPRConsent(false, 11), + ); + + mParticle + .getInstance() + .Identity.getCurrentUser() + .setConsentState(consentState); + + user1StoredConsentState = mParticle + .getInstance() + ._Store.getConsentState('loginMPID1'); + user2StoredConsentState = mParticle + .getInstance() + ._Store.getConsentState('loginMPID2'); + + expect( + user1StoredConsentState.getGDPRConsentState(), + ).to.have.property('foo purpose'); + expect( + user1StoredConsentState.getGDPRConsentState(), + ).to.not.have.property('foo purpose 2'); + expect( + user1StoredConsentState.getGDPRConsentState()[ + 'foo purpose' + ], + ).to.have.property('Consented', true); + expect( + user1StoredConsentState.getGDPRConsentState()[ + 'foo purpose' + ], + ).to.have.property('Timestamp', 10); + + expect( + user2StoredConsentState.getGDPRConsentState(), + ).to.have.property('foo purpose 2'); + expect( + user1StoredConsentState.getGDPRConsentState(), + ).to.not.have.property('foo purpose 1'); + expect( + user2StoredConsentState.getGDPRConsentState()[ + 'foo purpose 2' + ], + ).to.have.property('Consented', false); + expect( + user2StoredConsentState.getGDPRConsentState()[ + 'foo purpose 2' + ], + ).to.have.property('Timestamp', 11); + done(); + }); + }); }); - - mParticle.Identity.login(userIdentities1); - waitForCondition(() => { - return ( - mParticle.Identity.getCurrentUser()?.getMPID() === 'loginMPID1' - ); - }) - .then(() => { - let user1StoredConsentState = mParticle - .getInstance() - .Identity.getCurrentUser() - .getConsentState(); - expect(user1StoredConsentState).to.equal(null); - const consentState = mParticle.Consent.createConsentState(); - consentState.addGDPRConsentState( - 'foo purpose', - mParticle.Consent.createGDPRConsent(true, 10) - ); - - mParticle - .getInstance() - .Identity.getCurrentUser() - .setConsentState(consentState); - - fetchMockSuccess(urls.login, { - mpid: 'loginMPID2', is_logged_in: false - }); - - const userIdentities2 = { - userIdentities: { - customerid: 'foo2', - }, - }; - - mParticle.Identity.login(userIdentities2); - waitForCondition(() => { - return ( - mParticle.Identity.getCurrentUser()?.getMPID() === 'loginMPID2' - ); - }) - .then(() => { - let user2StoredConsentState = mParticle - .getInstance() - .Identity.getCurrentUser() - .getConsentState(); - expect(user2StoredConsentState).to.equal(null); - - consentState.removeGDPRConsentState('foo purpose'); - - consentState.addGDPRConsentState( - 'foo purpose 2', - mParticle.Consent.createGDPRConsent(false, 11) - ); - - mParticle - .getInstance() - .Identity.getCurrentUser() - .setConsentState(consentState); - - user1StoredConsentState = mParticle - .getInstance() - ._Store.getConsentState('loginMPID1'); - user2StoredConsentState = mParticle - .getInstance() - ._Store.getConsentState('loginMPID2'); - - expect( - user1StoredConsentState.getGDPRConsentState() - ).to.have.property('foo purpose'); - expect( - user1StoredConsentState.getGDPRConsentState() - ).to.not.have.property('foo purpose 2'); - expect( - user1StoredConsentState.getGDPRConsentState()['foo purpose'] - ).to.have.property('Consented', true); - expect( - user1StoredConsentState.getGDPRConsentState()['foo purpose'] - ).to.have.property('Timestamp', 10); - - expect( - user2StoredConsentState.getGDPRConsentState() - ).to.have.property('foo purpose 2'); - expect( - user1StoredConsentState.getGDPRConsentState() - ).to.not.have.property('foo purpose 1'); - expect( - user2StoredConsentState.getGDPRConsentState()['foo purpose 2'] - ).to.have.property('Consented', false); - expect( - user2StoredConsentState.getGDPRConsentState()['foo purpose 2'] - ).to.have.property('Timestamp', 11); - done(); }); - }) - }) - }); }); }); diff --git a/test/src/tests-utils.ts b/test/src/tests-utils.ts index 3e224eb42..bc843db61 100644 --- a/test/src/tests-utils.ts +++ b/test/src/tests-utils.ts @@ -53,10 +53,10 @@ describe('Utils', () => { expect(generateHash('3569038')).to.equal(-412991536); expect(generateHash('TestHash')).to.equal(-1146196832); expect(generateHash('mParticle'), 'mParticle String').to.equal( - 1744810483 + 1744810483, ); expect( - generateHash('d71b49a6-4248-4581-afff-abb28dada53d') + generateHash('d71b49a6-4248-4581-afff-abb28dada53d'), ).to.equal(635757846); }); @@ -66,7 +66,7 @@ describe('Utils', () => { // Use bad values to verify expected fail cases expect(typeof generateHash(false as unknown as string)).to.equal( - 'number' + 'number', ); expect(generateHash(false as unknown as string)).to.not.equal(0); }); @@ -98,10 +98,10 @@ describe('Utils', () => { expect(getRampNumber()).to.equal(100); expect(getRampNumber(null)).to.equal(100); expect( - getRampNumber('2b907d8b-cefe-4530-a6fe-60a381f2e066') + getRampNumber('2b907d8b-cefe-4530-a6fe-60a381f2e066'), ).to.equal(60); expect( - getRampNumber('d71b49a6-4248-4581-afff-abb28dada53d') + getRampNumber('d71b49a6-4248-4581-afff-abb28dada53d'), ).to.equal(47); const uniqueId = generateUniqueId(); @@ -115,7 +115,7 @@ describe('Utils', () => { it('returns true if object is an object', () => { const validObject = { foo: 'bar', - fizz:'buzz', + fizz: 'buzz', }; expect(isObject(validObject)).to.eq(true); }); @@ -131,7 +131,7 @@ describe('Utils', () => { }); describe('#isStringOrNumber', () => { - it(' should correctly validate a string or number', ()=> { + it(' should correctly validate a string or number', () => { expect(isStringOrNumber(42)).to.eq(true); expect(isStringOrNumber('42')).to.eq(true); @@ -139,7 +139,7 @@ describe('Utils', () => { expect(isStringOrNumber(undefined)).to.eq(false); expect(isStringOrNumber([])).to.eq(false); expect(isStringOrNumber({})).to.eq(false); - expect(isStringOrNumber(function (){})).to.eq(false); + expect(isStringOrNumber(function () {})).to.eq(false); }); }); @@ -159,11 +159,9 @@ describe('Utils', () => { it('should correctly parse string or number', () => { expect(parseStringOrNumber('abc')).to.eq('abc'); expect(parseStringOrNumber(123)).to.eq(123); - expect(parseStringOrNumber(({} as unknown) as string)).to.eq(null); - expect(parseStringOrNumber(([] as unknown) as string)).to.eq(null); - expect(parseStringOrNumber((null as unknown) as string)).to.eq( - null - ); + expect(parseStringOrNumber({} as unknown as string)).to.eq(null); + expect(parseStringOrNumber([] as unknown as string)).to.eq(null); + expect(parseStringOrNumber(null as unknown as string)).to.eq(null); }); }); @@ -212,7 +210,7 @@ describe('Utils', () => { }); describe('#returnConvertedBoolean', () => { - it ('returns expected boolean value when strings are passed', () => { + it('returns expected boolean value when strings are passed', () => { returnConvertedBoolean('false').should.equal(false); returnConvertedBoolean(false).should.equal(false); returnConvertedBoolean('true').should.equal(true); @@ -229,13 +227,13 @@ describe('Utils', () => { }); describe('#inArray', () => { - it('returns true if element is in the array', ()=> { + it('returns true if element is in the array', () => { const things = ['people', 'places', 'things']; expect(inArray(things, 'people')).to.eq(true); }); - it('returns false if element is not in the array', ()=> { + it('returns false if element is not in the array', () => { const things = ['people', 'places', 'things']; expect(inArray(things, 'cats')).to.eq(false); @@ -250,7 +248,7 @@ describe('Utils', () => { music: 'blues', }; - expect(findKeyInObject(things, 'music')).to.eq('music') + expect(findKeyInObject(things, 'music')).to.eq('music'); }); it('returns null if the key is not in the object', () => { @@ -272,9 +270,12 @@ describe('Utils', () => { describe('#converted', () => { it('should convert cookie strings', () => { - const cookieString = "{'sid':'1992BDBB-AD74-49DB-9B20-5EC8037E72DE'|'ie':1|'ua':'eyJ0ZXN'0Ijoiwq7igJkifQ=='"; - expect(converted(cookieString)).to.eq("{\'sid\':\'1992BDBB-AD74-49DB-9B20-5EC8037E72DE\'|\'ie\':1|\'ua\':\'eyJ0ZXN\'0Ijoiwq7igJkifQ==\'") - }) + const cookieString = + "{'sid':'1992BDBB-AD74-49DB-9B20-5EC8037E72DE'|'ie':1|'ua':'eyJ0ZXN'0Ijoiwq7igJkifQ=='"; + expect(converted(cookieString)).to.eq( + "{\'sid\':\'1992BDBB-AD74-49DB-9B20-5EC8037E72DE\'|\'ie\':1|\'ua\':\'eyJ0ZXN\'0Ijoiwq7igJkifQ==\'", + ); + }); }); describe('#toDataPlanSlug', () => { @@ -282,10 +283,16 @@ describe('Utils', () => { expect(toDataPlanSlug('string')).to.equal('string'); expect(toDataPlanSlug('42')).to.equal('42'); expect(toDataPlanSlug(37)).to.equal('37'); - expect(toDataPlanSlug('string with spaces')).to.equal('string_with_spaces'); - expect(toDataPlanSlug('kabob-case-string')).to.equal('kabob_case_string'); + expect(toDataPlanSlug('string with spaces')).to.equal( + 'string_with_spaces', + ); + expect(toDataPlanSlug('kabob-case-string')).to.equal( + 'kabob_case_string', + ); expect(toDataPlanSlug('PascalSlug')).to.equal('pascalslug'); - expect(toDataPlanSlug('under_score_slug')).to.equal('under_score_slug'); + expect(toDataPlanSlug('under_score_slug')).to.equal( + 'under_score_slug', + ); }); it('should convert non-strings to an empty string', () => { @@ -294,7 +301,7 @@ describe('Utils', () => { expect(toDataPlanSlug({})).to.equal(''); expect(toDataPlanSlug(null)).to.equal(''); expect(toDataPlanSlug(undefined)).to.equal(''); - expect(toDataPlanSlug(()=>{})).to.equal(''); + expect(toDataPlanSlug(() => {})).to.equal(''); }); }); @@ -339,12 +346,12 @@ describe('Utils', () => { expect(isEmpty([1, 2, 3])).to.equal(false); }); - it('returns true if object is empty', ()=> { + it('returns true if object is empty', () => { expect(isEmpty({})).to.equal(true); }); - it('returns false if object is not empty', ()=> { - expect(isEmpty({'foo': 'bar'})).to.equal(false); + it('returns false if object is not empty', () => { + expect(isEmpty({ foo: 'bar' })).to.equal(false); }); it('returns true if object is null', () => { @@ -363,7 +370,7 @@ describe('Utils', () => { expect(isEmpty('string')).to.equal(false); }); }); - + describe('#isValidCustomFlagProperty', () => { it('returns true if Custom Flag Property is a number', () => { expect(isValidCustomFlagProperty(42)).to.equal(true); @@ -379,8 +386,13 @@ describe('Utils', () => { it('returns true if Custom Flag Property is not valid', () => { expect(isValidCustomFlagProperty(null), 'null').to.equal(false); - expect(isValidCustomFlagProperty(function(){}), 'function').to.equal(false); - expect(isValidCustomFlagProperty(undefined), 'undefined').to.equal(false); + expect( + isValidCustomFlagProperty(function () {}), + 'function', + ).to.equal(false); + expect(isValidCustomFlagProperty(undefined), 'undefined').to.equal( + false, + ); }); }); @@ -444,4 +456,4 @@ describe('Utils', () => { ]); }); }); -}); \ No newline at end of file +}); diff --git a/test/src/tests-validators.ts b/test/src/tests-validators.ts index 54183ea4e..2da98e0a9 100644 --- a/test/src/tests-validators.ts +++ b/test/src/tests-validators.ts @@ -2,7 +2,7 @@ import Validators from '../../src/validators'; import { expect } from 'chai'; describe('Validators', () => { - it('#isValidAttributeValue should correctly validate an attribute value', ()=> { + it('#isValidAttributeValue should correctly validate an attribute value', () => { const validatedString = Validators.isValidAttributeValue('testValue1'); const validatedNumber = Validators.isValidAttributeValue(1); const validatedNull = Validators.isValidAttributeValue(null); @@ -18,7 +18,7 @@ describe('Validators', () => { expect(validatedUndefined).to.eq(false); }); - it('#validateIdentities should properly validate identityApiRequest values', ()=> { + it('#validateIdentities should properly validate identityApiRequest values', () => { const badUserIdentitiesArray = { userIdentities: { customerid: [], @@ -63,15 +63,29 @@ describe('Validators', () => { }; // Hiding from TS validation to make sure actual unit test works in JS - const badUserIdentitiesArrayResult = Validators.validateIdentities(badUserIdentitiesArray as unknown as any); - const badUserIdentitiesObjectResult = Validators.validateIdentities(badUserIdentitiesObject as unknown as any); - const badUserIdentitiesBooleanResult = Validators.validateIdentities(badUserIdentitiesBoolean as unknown as any); - const badUserIdentitiesUndefinedResult = Validators.validateIdentities(badUserIdentitiesUndefined); - - const validUserIdentitiesNullResult = Validators.validateIdentities(validUserIdentitiesNull); - const validUserIdentitiesStringResult = Validators.validateIdentities(validUserIdentitiesString); - - const invalidUserIdentitiesComboResult = Validators.validateIdentities(invalidUserIdentitiesCombo); + const badUserIdentitiesArrayResult = Validators.validateIdentities( + badUserIdentitiesArray as unknown as any, + ); + const badUserIdentitiesObjectResult = Validators.validateIdentities( + badUserIdentitiesObject as unknown as any, + ); + const badUserIdentitiesBooleanResult = Validators.validateIdentities( + badUserIdentitiesBoolean as unknown as any, + ); + const badUserIdentitiesUndefinedResult = Validators.validateIdentities( + badUserIdentitiesUndefined, + ); + + const validUserIdentitiesNullResult = Validators.validateIdentities( + validUserIdentitiesNull, + ); + const validUserIdentitiesStringResult = Validators.validateIdentities( + validUserIdentitiesString, + ); + + const invalidUserIdentitiesComboResult = Validators.validateIdentities( + invalidUserIdentitiesCombo, + ); expect(badUserIdentitiesArrayResult.valid).to.eq(false); expect(badUserIdentitiesObjectResult.valid).to.eq(false); @@ -82,7 +96,6 @@ describe('Validators', () => { expect(validUserIdentitiesStringResult.valid).to.eq(true); expect(invalidUserIdentitiesComboResult.valid).to.eq(false); - }); it('#isValidKeyValue should correctly validate a key value', () => { @@ -93,10 +106,10 @@ describe('Validators', () => { expect(Validators.isValidKeyValue(undefined)).to.eq(false); expect(Validators.isValidKeyValue([])).to.eq(false); expect(Validators.isValidKeyValue({})).to.eq(false); - expect(Validators.isValidKeyValue(function (){})).to.eq(false); + expect(Validators.isValidKeyValue(function () {})).to.eq(false); }); - it('#isStringOrNumber should correctly validate a string or number', ()=> { + it('#isStringOrNumber should correctly validate a string or number', () => { expect(Validators.isStringOrNumber(42)).to.eq(true); expect(Validators.isStringOrNumber('42')).to.eq(true); @@ -104,7 +117,7 @@ describe('Validators', () => { expect(Validators.isStringOrNumber(undefined)).to.eq(false); expect(Validators.isStringOrNumber([])).to.eq(false); expect(Validators.isStringOrNumber({})).to.eq(false); - expect(Validators.isStringOrNumber(function (){})).to.eq(false); + expect(Validators.isStringOrNumber(function () {})).to.eq(false); }); it('#isNumber should correctly validate a number', () => { @@ -115,7 +128,7 @@ describe('Validators', () => { expect(Validators.isNumber(undefined)).to.eq(false); expect(Validators.isNumber([])).to.eq(false); expect(Validators.isNumber({})).to.eq(false); - expect(Validators.isNumber(function (){})).to.eq(false); + expect(Validators.isNumber(function () {})).to.eq(false); }); it('#isFunction should correctly validate a function', () => { @@ -126,7 +139,7 @@ describe('Validators', () => { expect(Validators.isFunction([])).to.eq(false); expect(Validators.isFunction({})).to.eq(false); - expect(Validators.isFunction(function (){})).to.eq(true); + expect(Validators.isFunction(function () {})).to.eq(true); expect(Validators.isFunction(() => {})).to.eq(true); }); -}); \ No newline at end of file +}); diff --git a/test/src/vault.spec.ts b/test/src/vault.spec.ts index 7d9274ab2..eaab65098 100644 --- a/test/src/vault.spec.ts +++ b/test/src/vault.spec.ts @@ -13,8 +13,8 @@ const testArray: Dictionary[] = [ { narf: 'poit' }, ]; -const testString: string = 'foo'; -const testNumber: number = 123; +const testString = 'foo'; +const testNumber = 123; describe('Vault', () => { describe('SessionStorageVault', () => { @@ -34,7 +34,7 @@ describe('Vault', () => { expect(vault.contents).to.equal(testObject); expect(window.sessionStorage.getItem(storageKey)).to.equal( - JSON.stringify(testObject) + JSON.stringify(testObject), ); }); @@ -42,44 +42,40 @@ describe('Vault', () => { const storageKey = 'test-key-store-array'; const vault = new SessionStorageVault[]>( - storageKey + storageKey, ); vault.store(testArray); expect(vault.contents).to.equal(testArray); expect(window.sessionStorage.getItem(storageKey)).to.equal( - JSON.stringify(testArray) + JSON.stringify(testArray), ); }); it('should store a string', () => { const storageKey = 'test-key-store-string'; - const vault = new SessionStorageVault( - storageKey - ); + const vault = new SessionStorageVault(storageKey); vault.store(testString); expect(vault.contents).to.equal(testString); expect(window.sessionStorage.getItem(storageKey)).to.equal( - JSON.stringify(testString) + JSON.stringify(testString), ); }); it('should store a number', () => { const storageKey = 'test-key-store-number'; - const vault = new SessionStorageVault( - storageKey - ); + const vault = new SessionStorageVault(storageKey); vault.store(testNumber); expect(vault.contents).to.equal(testNumber); expect(window.sessionStorage.getItem(storageKey)).to.equal( - JSON.stringify(testNumber) + JSON.stringify(testNumber), ); }); }); @@ -90,7 +86,7 @@ describe('Vault', () => { window.sessionStorage.setItem( storageKey, - JSON.stringify(testObject) + JSON.stringify(testObject), ); const vault = new SessionStorageVault< @@ -110,11 +106,11 @@ describe('Vault', () => { window.sessionStorage.setItem( storageKey, - JSON.stringify(testArray) + JSON.stringify(testArray), ); const vault = new SessionStorageVault[]>( - storageKey + storageKey, ); const retrievedItem = vault.retrieve(); @@ -127,12 +123,10 @@ describe('Vault', () => { window.sessionStorage.setItem( storageKey, - JSON.stringify(testString) + JSON.stringify(testString), ); - const vault = new SessionStorageVault( - storageKey - ); + const vault = new SessionStorageVault(storageKey); const retrievedItem = vault.retrieve(); @@ -144,12 +138,10 @@ describe('Vault', () => { window.sessionStorage.setItem( storageKey, - JSON.stringify(testNumber) + JSON.stringify(testNumber), ); - const vault = new SessionStorageVault( - storageKey - ); + const vault = new SessionStorageVault(storageKey); const retrievedItem = vault.retrieve(); @@ -163,7 +155,7 @@ describe('Vault', () => { window.sessionStorage.setItem( storageKey, - JSON.stringify(testObject) + JSON.stringify(testObject), ); const vault = new SessionStorageVault< @@ -174,7 +166,7 @@ describe('Vault', () => { expect(vault.contents).to.equal(null); expect(window.sessionStorage.getItem(storageKey)).to.equal( - null + null, ); }); @@ -183,18 +175,18 @@ describe('Vault', () => { window.sessionStorage.setItem( storageKey, - JSON.stringify(testArray) + JSON.stringify(testArray), ); const vault = new SessionStorageVault[]>( - storageKey + storageKey, ); vault.purge(); expect(vault.contents).to.equal(null); expect(window.sessionStorage.getItem(storageKey)).to.equal( - null + null, ); }); }); @@ -217,7 +209,7 @@ describe('Vault', () => { expect(vault.contents).to.equal(testObject); expect(window.localStorage.getItem(storageKey)).to.equal( - JSON.stringify(testObject) + JSON.stringify(testObject), ); }); @@ -225,44 +217,40 @@ describe('Vault', () => { const storageKey = 'test-key-store-array'; const vault = new LocalStorageVault[]>( - storageKey + storageKey, ); vault.store(testArray); expect(vault.contents).to.equal(testArray); expect(window.localStorage.getItem(storageKey)).to.equal( - JSON.stringify(testArray) + JSON.stringify(testArray), ); }); it('should store a string', () => { const storageKey = 'test-key-store-array'; - const vault = new LocalStorageVault( - storageKey - ); + const vault = new LocalStorageVault(storageKey); vault.store(testString); expect(vault.contents).to.equal(testString); expect(window.localStorage.getItem(storageKey)).to.equal( - JSON.stringify(testString) + JSON.stringify(testString), ); }); it('should store a number', () => { const storageKey = 'test-key-store-array'; - const vault = new LocalStorageVault( - storageKey - ); + const vault = new LocalStorageVault(storageKey); vault.store(testNumber); expect(vault.contents).to.equal(testNumber); expect(window.localStorage.getItem(storageKey)).to.equal( - JSON.stringify(testNumber) + JSON.stringify(testNumber), ); }); }); @@ -273,7 +261,7 @@ describe('Vault', () => { window.localStorage.setItem( storageKey, - JSON.stringify(testObject) + JSON.stringify(testObject), ); const vault = new LocalStorageVault< @@ -293,11 +281,11 @@ describe('Vault', () => { window.localStorage.setItem( storageKey, - JSON.stringify(testArray) + JSON.stringify(testArray), ); const vault = new LocalStorageVault[]>( - storageKey + storageKey, ); const retrievedItem = vault.retrieve(); @@ -310,12 +298,10 @@ describe('Vault', () => { window.localStorage.setItem( storageKey, - JSON.stringify(testString) + JSON.stringify(testString), ); - const vault = new LocalStorageVault( - storageKey - ); + const vault = new LocalStorageVault(storageKey); const retrievedItem = vault.retrieve(); @@ -327,12 +313,10 @@ describe('Vault', () => { window.localStorage.setItem( storageKey, - JSON.stringify(testNumber) + JSON.stringify(testNumber), ); - const vault = new LocalStorageVault( - storageKey - ); + const vault = new LocalStorageVault(storageKey); const retrievedItem = vault.retrieve(); @@ -346,7 +330,7 @@ describe('Vault', () => { window.localStorage.setItem( storageKey, - JSON.stringify(testObject) + JSON.stringify(testObject), ); const vault = new LocalStorageVault< @@ -364,11 +348,11 @@ describe('Vault', () => { window.localStorage.setItem( storageKey, - JSON.stringify(testArray) + JSON.stringify(testArray), ); const vault = new LocalStorageVault[]>( - storageKey + storageKey, ); vault.purge(); @@ -431,7 +415,7 @@ describe('Vault', () => { expect(vault.retrieve()[4]).to.eql(batch5); expect(window.localStorage.getItem(storageKey)).to.equal( - JSON.stringify([batch1, batch2, batch3, batch4, batch5]) + JSON.stringify([batch1, batch2, batch3, batch4, batch5]), ); }); }); From 5299fd30bc451572fb0e8a6b6e71914a9eef37e1 Mon Sep 17 00:00:00 2001 From: Alexander Sapountzis Date: Tue, 10 Jun 2025 15:18:54 -0400 Subject: [PATCH 2/5] Save Point --- test/src/config/utils.js | 17 +- test/src/tests-batchUploader.ts | 1350 +++++++++++++-------------- test/src/tests-batchUploader_2.ts | 4 +- test/src/tests-batchUploader_3.ts | 6 - test/src/tests-batchUploader_4.ts | 5 +- test/src/tests-beaconUpload.ts | 9 +- test/src/tests-config-api-client.ts | 8 +- test/src/tests-cookie-syncing.ts | 10 +- test/src/tests-identity.ts | 6 - test/src/tests-kit-blocking.ts | 10 - 10 files changed, 648 insertions(+), 777 deletions(-) diff --git a/test/src/config/utils.js b/test/src/config/utils.js index 18f9ddcc5..9eb174a60 100644 --- a/test/src/config/utils.js +++ b/test/src/config/utils.js @@ -11,7 +11,7 @@ import { } from './constants'; import fetchMock from 'fetch-mock/esm/client'; -var pluses = /\+/g, +const pluses = /\+/g, getLocalStorageProducts = function getLocalStorageProducts() { return JSON.parse( atob( @@ -42,9 +42,8 @@ var pluses = /\+/g, } }, getDomain = function (doc, locationHostname) { - let i, - testParts, - mpTest = 'mptest=cookie', + let i, testParts; + const mpTest = 'mptest=cookie', hostname = locationHostname.split('.'); for (i = hostname.length - 1; i >= 0; i--) { testParts = hostname.slice(i).join('.'); @@ -89,13 +88,11 @@ var pluses = /\+/g, } }, setCookie = function (cname, data, raw) { - let date = new Date(), + const date = new Date(), expires = new Date( date.getTime() + 365 * 24 * 60 * 60 * 1000, - ).toGMTString(), - domain, - cookieDomain, - value; + ).toGMTString(); + let domain, value; if (cname === v4CookieKey || cname === workspaceCookieName) { value = Utils.replaceCommasWithPipes(data); } else if (cname === v3CookieKey) { @@ -108,7 +105,7 @@ var pluses = /\+/g, value = data; } - cookieDomain = getCookieDomain(); + const cookieDomain = getCookieDomain(); if (cookieDomain === '') { domain = ''; diff --git a/test/src/tests-batchUploader.ts b/test/src/tests-batchUploader.ts index 12a7e61d1..e5af5c3df 100644 --- a/test/src/tests-batchUploader.ts +++ b/test/src/tests-batchUploader.ts @@ -631,84 +631,78 @@ describe('batch uploader', () => { describe('Unit Tests', () => { describe('#queueEvent', () => { - it('should add events to the Pending Events Queue', () => { + it('should add events to the Pending Events Queue', async () => { window.mParticle._resetForTests(MPConfig); window.mParticle.init(apiKey, window.mParticle.config); - waitForCondition(hasIdentifyReturned).then(() => { - const mpInstance = window.mParticle.getInstance(); + await waitForCondition(hasIdentifyReturned); - const uploader = new BatchUploader(mpInstance, 1000); + const mpInstance = window.mParticle.getInstance(); - const event: SDKEvent = { - EventName: 'Test Event', - EventAttributes: null, - SourceMessageId: 'test-smid', - EventDataType: 4, - EventCategory: 1, - ExpandedEventCount: 0, - CustomFlags: {}, - IsFirstRun: false, - CurrencyCode: null, - MPID: 'testMPID', - ConsentState: null, - UserAttributes: {}, - UserIdentities: [], - SDKVersion: 'X.XX.XX', - SessionId: 'test-session-id', - SessionStartDate: 0, - Debug: false, - DeviceId: 'test-device', - Timestamp: 0, - ActiveTimeOnSite: 10, - }; - - uploader.queueEvent(event); - - expect(uploader.eventsQueuedForProcessing.length).to.eql(1); - }); + const uploader = new BatchUploader(mpInstance, 1000); + + const event: SDKEvent = { + EventName: 'Test Event', + EventAttributes: null, + SourceMessageId: 'test-smid', + EventDataType: 4, + EventCategory: 1, + ExpandedEventCount: 0, + CustomFlags: {}, + IsFirstRun: false, + CurrencyCode: null, + MPID: 'testMPID', + ConsentState: null, + UserAttributes: {}, + UserIdentities: [], + SDKVersion: 'X.XX.XX', + SessionId: 'test-session-id', + SessionStartDate: 0, + Debug: false, + DeviceId: 'test-device', + Timestamp: 0, + ActiveTimeOnSite: 10, + }; + + uploader.queueEvent(event); + + expect(uploader.eventsQueuedForProcessing.length).to.eql(1); }); - it('should reject batches without events', () => { + it('should reject batches without events', async () => { window.mParticle._resetForTests(MPConfig); window.mParticle.init(apiKey, window.mParticle.config); - waitForCondition(hasIdentifyReturned).then(() => { - const mpInstance = window.mParticle.getInstance(); + await waitForCondition(hasIdentifyReturned); - const uploader = new BatchUploader(mpInstance, 1000); + const mpInstance = window.mParticle.getInstance(); - uploader.queueEvent(null); - uploader.queueEvent({} as unknown as SDKEvent); + const uploader = new BatchUploader(mpInstance, 1000); - expect(uploader.eventsQueuedForProcessing).to.eql([]); - expect(uploader.batchesQueuedForProcessing).to.eql([]); - }); + uploader.queueEvent(null); + uploader.queueEvent({} as unknown as SDKEvent); + + expect(uploader.eventsQueuedForProcessing).to.eql([]); + expect(uploader.batchesQueuedForProcessing).to.eql([]); }); - it('should add events in the order they are received', () => { + it('should add events in the order they are received', async () => { window.mParticle._resetForTests(MPConfig); window.mParticle.init(apiKey, window.mParticle.config); - waitForCondition(hasIdentifyReturned).then(() => { - const mpInstance = window.mParticle.getInstance(); + await waitForCondition(hasIdentifyReturned); - const uploader = new BatchUploader(mpInstance, 1000); + const mpInstance = window.mParticle.getInstance(); - uploader.queueEvent(event1); - uploader.queueEvent(event2); - uploader.queueEvent(event3); + const uploader = new BatchUploader(mpInstance, 1000); - expect(uploader.eventsQueuedForProcessing.length).to.eql(3); - expect(uploader.eventsQueuedForProcessing[0]).to.eql( - event1, - ); - expect(uploader.eventsQueuedForProcessing[1]).to.eql( - event2, - ); - expect(uploader.eventsQueuedForProcessing[2]).to.eql( - event3, - ); - }); + uploader.queueEvent(event1); + uploader.queueEvent(event2); + uploader.queueEvent(event3); + + expect(uploader.eventsQueuedForProcessing.length).to.eql(3); + expect(uploader.eventsQueuedForProcessing[0]).to.eql(event1); + expect(uploader.eventsQueuedForProcessing[1]).to.eql(event2); + expect(uploader.eventsQueuedForProcessing[2]).to.eql(event3); }); }); @@ -755,59 +749,55 @@ describe('batch uploader', () => { expect(actualBatchResult.events).to.eql(actualBatch.events); }); - it('should return batches that fail to upload with 500 errors', () => { + it('should return batches that fail to upload with 500 errors', async () => { window.mParticle.init(apiKey, window.mParticle.config); - waitForCondition(hasIdentifyReturned) - .then(async () => { - fetchMock.post(urls.events, 500); - - const newLogger = new Logger(window.mParticle.config); - const mpInstance = window.mParticle.getInstance(); - - const uploader = new BatchUploader(mpInstance, 1000); - - const batchValidator = new _BatchValidator(); - - const batch1 = batchValidator.returnBatch({ - messageType: 4, - name: 'Test Event 1', - }); - - const batch2 = batchValidator.returnBatch({ - messageType: 4, - name: 'Test Event 2', - }); - const batch3 = batchValidator.returnBatch({ - messageType: 4, - name: 'Test Event 3', - }); - - // HACK: Directly access uploader to Force an upload - const batchesNotUploaded = await (( - uploader - )).uploadBatches( - newLogger, - [batch1, batch2, batch3], - false, - ); - - expect( - batchesNotUploaded.length, - 'Should have 3 uploaded batches', - ).to.equal(3); - - expect( - batchesNotUploaded[0].events[0].data.event_name, - ).to.equal('Test Event 1'); - expect( - batchesNotUploaded[1].events[0].data.event_name, - ).to.equal('Test Event 2'); - expect( - batchesNotUploaded[2].events[0].data.event_name, - ).to.equal('Test Event 3'); - }) - .catch((e) => {}); + await waitForCondition(hasIdentifyReturned); + + fetchMock.post(urls.events, 500); + + const newLogger = new Logger(window.mParticle.config); + const mpInstance = window.mParticle.getInstance(); + + const uploader = new BatchUploader(mpInstance, 1000); + + const batchValidator = new _BatchValidator(); + + const batch1 = batchValidator.returnBatch({ + messageType: 4, + name: 'Test Event 1', + }); + + const batch2 = batchValidator.returnBatch({ + messageType: 4, + name: 'Test Event 2', + }); + const batch3 = batchValidator.returnBatch({ + messageType: 4, + name: 'Test Event 3', + }); + + // HACK: Directly access uploader to Force an upload + const batchesNotUploaded = await (uploader).uploadBatches( + newLogger, + [batch1, batch2, batch3], + false, + ); + + expect( + batchesNotUploaded.length, + 'Should have 3 uploaded batches', + ).to.equal(3); + + expect( + batchesNotUploaded[0].events[0].data.event_name, + ).to.equal('Test Event 1'); + expect( + batchesNotUploaded[1].events[0].data.event_name, + ).to.equal('Test Event 2'); + expect( + batchesNotUploaded[2].events[0].data.event_name, + ).to.equal('Test Event 3'); }); it('should return batches that fail to upload with 429 errors', async () => { @@ -866,41 +856,39 @@ describe('batch uploader', () => { it('should return null if batches fail to upload with 401 errors', async () => { window.mParticle.init(apiKey, window.mParticle.config); - waitForCondition(hasIdentifyReturned).then(async () => { - fetchMock.post(urls.events, 401); - - const newLogger = new Logger(window.mParticle.config); - const mpInstance = window.mParticle.getInstance(); + await waitForCondition(hasIdentifyReturned); - const uploader = new BatchUploader(mpInstance, 1000); + fetchMock.post(urls.events, 401); - const batchValidator = new _BatchValidator(); + const newLogger = new Logger(window.mParticle.config); + const mpInstance = window.mParticle.getInstance(); - const batch1 = batchValidator.returnBatch({ - messageType: 4, - name: 'Test Event 1', - }); + const uploader = new BatchUploader(mpInstance, 1000); - const batch2 = batchValidator.returnBatch({ - messageType: 4, - name: 'Test Event 2', - }); - const batch3 = batchValidator.returnBatch({ - messageType: 4, - name: 'Test Event 3', - }); + const batchValidator = new _BatchValidator(); - // HACK: Directly access uploader to Force an upload - const batchesNotUploaded = await (( - uploader - )).uploadBatches( - newLogger, - [batch1, batch2, batch3], - false, - ); + const batch1 = batchValidator.returnBatch({ + messageType: 4, + name: 'Test Event 1', + }); - expect(batchesNotUploaded === null).to.equal(true); + const batch2 = batchValidator.returnBatch({ + messageType: 4, + name: 'Test Event 2', }); + const batch3 = batchValidator.returnBatch({ + messageType: 4, + name: 'Test Event 3', + }); + + // HACK: Directly access uploader to Force an upload + const batchesNotUploaded = await (uploader).uploadBatches( + newLogger, + [batch1, batch2, batch3], + false, + ); + + expect(batchesNotUploaded === null).to.equal(true); }); it('should not throw an error when upload is called while storage has not been created yet', async () => { @@ -925,58 +913,54 @@ describe('batch uploader', () => { it('should return batches that fail to unknown HTTP errors', async () => { window.mParticle.init(apiKey, window.mParticle.config); - waitForCondition(hasIdentifyReturned) - .then(async () => { - fetchMock.post(urls.events, 400); - - const newLogger = new Logger(window.mParticle.config); - const mpInstance = window.mParticle.getInstance(); - - const uploader = new BatchUploader(mpInstance, 1000); - - const batchValidator = new _BatchValidator(); - - const batch1 = batchValidator.returnBatch({ - messageType: 4, - name: 'Test Event 1', - }); - - const batch2 = batchValidator.returnBatch({ - messageType: 4, - name: 'Test Event 2', - }); - const batch3 = batchValidator.returnBatch({ - messageType: 4, - name: 'Test Event 3', - }); - - // HACK: Directly access uploader to Force an upload - const batchesNotUploaded = await (( - uploader - )).uploadBatches( - newLogger, - [batch1, batch2, batch3], - false, - ); - - expect(batchesNotUploaded).to.be.ok; - - expect( - batchesNotUploaded.length, - 'Should have 3 uploaded batches', - ).to.equal(3); - - expect( - batchesNotUploaded[0].events[0].data.event_name, - ).to.equal('Test Event 1'); - expect( - batchesNotUploaded[1].events[0].data.event_name, - ).to.equal('Test Event 2'); - expect( - batchesNotUploaded[2].events[0].data.event_name, - ).to.equal('Test Event 3'); - }) - .catch((e) => {}); + await waitForCondition(hasIdentifyReturned); + + fetchMock.post(urls.events, 400); + + const newLogger = new Logger(window.mParticle.config); + const mpInstance = window.mParticle.getInstance(); + + const uploader = new BatchUploader(mpInstance, 1000); + + const batchValidator = new _BatchValidator(); + + const batch1 = batchValidator.returnBatch({ + messageType: 4, + name: 'Test Event 1', + }); + + const batch2 = batchValidator.returnBatch({ + messageType: 4, + name: 'Test Event 2', + }); + const batch3 = batchValidator.returnBatch({ + messageType: 4, + name: 'Test Event 3', + }); + + // HACK: Directly access uploader to Force an upload + const batchesNotUploaded = await (uploader).uploadBatches( + newLogger, + [batch1, batch2, batch3], + false, + ); + + expect(batchesNotUploaded).to.be.ok; + + expect( + batchesNotUploaded.length, + 'Should have 3 uploaded batches', + ).to.equal(3); + + expect( + batchesNotUploaded[0].events[0].data.event_name, + ).to.equal('Test Event 1'); + expect( + batchesNotUploaded[1].events[0].data.event_name, + ).to.equal('Test Event 2'); + expect( + batchesNotUploaded[2].events[0].data.event_name, + ).to.equal('Test Event 3'); }); }); }); @@ -994,118 +978,112 @@ describe('batch uploader', () => { sinon.restore(); }); - it('should use local storage when enabled', (done) => { + it('should use local storage when enabled', async () => { window.mParticle.config.flags = { offlineStorage: '100', }; window.mParticle._resetForTests(MPConfig); window.mParticle.init(apiKey, window.mParticle.config); - waitForCondition(hasIdentifyReturned) - .then(() => { - const getItemSpy = sinon.spy(Storage.prototype, 'getItem'); - const setItemSpy = sinon.spy(Storage.prototype, 'setItem'); + await waitForCondition(hasIdentifyReturned); - const mpInstance = window.mParticle.getInstance(); + const getItemSpy = sinon.spy(Storage.prototype, 'getItem'); + const setItemSpy = sinon.spy(Storage.prototype, 'setItem'); + + const mpInstance = window.mParticle.getInstance(); + + const uploader = new BatchUploader(mpInstance, 1000); + + const event: SDKEvent = { + EventName: 'Test Event', + EventAttributes: null, + SourceMessageId: 'test-smid', + EventDataType: 4, + EventCategory: 1, + ExpandedEventCount: 0, + CustomFlags: {}, + IsFirstRun: false, + CurrencyCode: null, + MPID: 'testMPID', + ConsentState: null, + UserAttributes: {}, + UserIdentities: [], + SDKVersion: 'X.XX.XX', + SessionId: 'test-session-id', + SessionStartDate: 0, + Debug: false, + DeviceId: 'test-device', + Timestamp: 0, + ActiveTimeOnSite: 10, + }; - const uploader = new BatchUploader(mpInstance, 1000); + const expectedEvent = [event]; - const event: SDKEvent = { - EventName: 'Test Event', - EventAttributes: null, - SourceMessageId: 'test-smid', - EventDataType: 4, - EventCategory: 1, - ExpandedEventCount: 0, - CustomFlags: {}, - IsFirstRun: false, - CurrencyCode: null, - MPID: 'testMPID', - ConsentState: null, - UserAttributes: {}, - UserIdentities: [], - SDKVersion: 'X.XX.XX', - SessionId: 'test-session-id', - SessionStartDate: 0, - Debug: false, - DeviceId: 'test-device', - Timestamp: 0, - ActiveTimeOnSite: 10, - }; - - const expectedEvent = [event]; - - uploader.queueEvent(event); - - expect(uploader.eventsQueuedForProcessing.length).to.eql(1); - - expect(setItemSpy.called).to.eq(true); - expect(setItemSpy.getCall(0).lastArg).to.equal( - JSON.stringify(expectedEvent), - ); + uploader.queueEvent(event); - expect(getItemSpy.called).to.eq(true); - expect(getItemSpy.getCall(0).lastArg).to.equal( - 'mprtcl-v4_abcdef-events', - ); + expect(uploader.eventsQueuedForProcessing.length).to.eql(1); + + expect(setItemSpy.called).to.eq(true); + expect(setItemSpy.getCall(0).lastArg).to.equal( + JSON.stringify(expectedEvent), + ); - done(); - }) - .catch((e) => {}); + expect(getItemSpy.called).to.eq(true); + expect(getItemSpy.getCall(0).lastArg).to.equal( + 'mprtcl-v4_abcdef-events', + ); }); - it('should not use local storage when disabled', () => { + it('should not use local storage when disabled', async () => { window.mParticle.config.flags = { // offlineStorage: '0', // Defaults to 0, but test if not included, just in case }; window.mParticle._resetForTests(MPConfig); window.mParticle.init(apiKey, window.mParticle.config); - waitForCondition(hasIdentifyReturned) - .then(() => { - const getItemSpy = sinon.spy(Storage.prototype, 'getItem'); - const setItemSpy = sinon.spy(Storage.prototype, 'setItem'); + await waitForCondition(hasIdentifyReturned); - const mpInstance = window.mParticle.getInstance(); + const getItemSpy = sinon.spy(Storage.prototype, 'getItem'); + const setItemSpy = sinon.spy(Storage.prototype, 'setItem'); + + const mpInstance = window.mParticle.getInstance(); + + const uploader = new BatchUploader(mpInstance, 1000); + + const event: SDKEvent = { + EventName: 'Test Event', + EventAttributes: null, + SourceMessageId: 'test-smid', + EventDataType: 4, + EventCategory: 1, + ExpandedEventCount: 0, + CustomFlags: {}, + IsFirstRun: false, + CurrencyCode: null, + MPID: 'testMPID', + ConsentState: null, + UserAttributes: {}, + UserIdentities: [], + SDKVersion: 'X.XX.XX', + SessionId: 'test-session-id', + SessionStartDate: 0, + Debug: false, + DeviceId: 'test-device', + Timestamp: 0, + ActiveTimeOnSite: 10, + }; - const uploader = new BatchUploader(mpInstance, 1000); + uploader.queueEvent(event); - const event: SDKEvent = { - EventName: 'Test Event', - EventAttributes: null, - SourceMessageId: 'test-smid', - EventDataType: 4, - EventCategory: 1, - ExpandedEventCount: 0, - CustomFlags: {}, - IsFirstRun: false, - CurrencyCode: null, - MPID: 'testMPID', - ConsentState: null, - UserAttributes: {}, - UserIdentities: [], - SDKVersion: 'X.XX.XX', - SessionId: 'test-session-id', - SessionStartDate: 0, - Debug: false, - DeviceId: 'test-device', - Timestamp: 0, - ActiveTimeOnSite: 10, - }; - - uploader.queueEvent(event); - - expect(uploader.eventsQueuedForProcessing.length).to.eql(1); - expect(uploader.eventsQueuedForProcessing[0]).to.eql(event); - - expect(setItemSpy.called).to.eq(false); - expect(getItemSpy.called).to.eq(false); + expect(uploader.eventsQueuedForProcessing.length).to.eql(1); + expect(uploader.eventsQueuedForProcessing[0]).to.eql(event); - expect( - window.localStorage.getItem('mprtcl-v4_abcdef-events'), - ).to.equal(null); - }) - .catch((e) => {}); + expect(setItemSpy.called).to.eq(false); + expect(getItemSpy.called).to.eq(false); + + expect( + window.localStorage.getItem('mprtcl-v4_abcdef-events'), + ).to.equal(null); }); }); @@ -1119,49 +1097,43 @@ describe('batch uploader', () => { window.localStorage.clear(); }); - it('should not save events or batches in local storage', (done) => { + it('should not save events or batches in local storage', async () => { const eventStorageKey = 'mprtcl-v4_abcdef-events'; const batchStorageKey = 'mprtcl-v4_abcdef-batches'; window.mParticle._resetForTests(MPConfig); window.mParticle.init(apiKey, window.mParticle.config); - waitForCondition(hasIdentifyReturned) - .then(() => { - const mpInstance = window.mParticle.getInstance(); - const uploader = mpInstance._APIClient.uploader; + await waitForCondition(hasIdentifyReturned); - // Init will fire a Session Start and AST. We are adding event0 - // to show that manually queued events will also be grouped - // into a batch - uploader.queueEvent(event0); + const mpInstance = window.mParticle.getInstance(); + const uploader = mpInstance._APIClient.uploader; - const eventQueue: SDKEvent[] = - uploader.eventsQueuedForProcessing; + // Init will fire a Session Start and AST. We are adding event0 + // to show that manually queued events will also be grouped + // into a batch + uploader.queueEvent(event0); - expect(eventQueue.length).to.equal(3); + const eventQueue: SDKEvent[] = uploader.eventsQueuedForProcessing; - expect( - window.localStorage.getItem(eventStorageKey), - 'Local Storage Events should be empty', - ).to.equal(null); + expect(eventQueue.length).to.equal(3); - const batchQueue: Batch[] = - uploader.batchesQueuedForProcessing; + expect( + window.localStorage.getItem(eventStorageKey), + 'Local Storage Events should be empty', + ).to.equal(null); - // Manually initiate the upload process - turn event into batches and upload the batch - window.mParticle.upload(); + const batchQueue: Batch[] = uploader.batchesQueuedForProcessing; - expect(batchQueue.length).to.equal(2); + // Manually initiate the upload process - turn event into batches and upload the batch + window.mParticle.upload(); - expect( - window.localStorage.getItem(batchStorageKey), - 'Local Storage Batches should be empty', - ).to.equal(null); + expect(batchQueue.length).to.equal(2); - done(); - }) - .catch((e) => {}); + expect( + window.localStorage.getItem(batchStorageKey), + 'Local Storage Batches should be empty', + ).to.equal(null); }); }); @@ -1184,50 +1156,38 @@ describe('batch uploader', () => { sinon.restore(); }); - it('should store events in Session Storage in order of creation', (done) => { + it('should store events in Session Storage in order of creation', async () => { const eventStorageKey = 'mprtcl-v4_abcdef-events'; window.mParticle._resetForTests(MPConfig); window.mParticle.init(apiKey, window.mParticle.config); - waitForCondition(hasIdentifyReturned) - .then(() => { - const mpInstance = window.mParticle.getInstance(); - const uploader = mpInstance._APIClient.uploader; + await waitForCondition(hasIdentifyReturned); - // Init will fire a Session Start and AST. We are adding event0 - // to show that manually queued events will also be grouped - // into a batch - uploader.queueEvent(event0); + const mpInstance = window.mParticle.getInstance(); + const uploader = mpInstance._APIClient.uploader; - const eventQueue: SDKEvent[] = - uploader.eventsQueuedForProcessing; + // Init will fire a Session Start and AST. We are adding event0 + // to show that manually queued events will also be grouped + // into a batch + uploader.queueEvent(event0); - expect(eventQueue.length).to.equal(3); + const eventQueue: SDKEvent[] = uploader.eventsQueuedForProcessing; - const storedEvents: SDKEvent[] = JSON.parse( - window.sessionStorage.getItem(eventStorageKey), - ); + expect(eventQueue.length).to.equal(3); - expect( - storedEvents.length, - 'Local Storage Events', - ).to.equal(3); + const storedEvents: SDKEvent[] = JSON.parse( + window.sessionStorage.getItem(eventStorageKey), + ); - expect( - storedEvents[0], - 'Local Storage: Session Start', - ).to.eql(eventQueue[0]); - expect(storedEvents[1], 'Local Storage: AST').to.eql( - eventQueue[1], - ); - expect( - storedEvents[2], - 'Local Storage: Test Event 0', - ).to.eql(eventQueue[2]); + expect(storedEvents.length, 'Local Storage Events').to.equal(3); - done(); - }) - .catch((e) => {}); + expect(storedEvents[0], 'Local Storage: Session Start').to.eql( + eventQueue[0], + ); + expect(storedEvents[1], 'Local Storage: AST').to.eql(eventQueue[1]); + expect(storedEvents[2], 'Local Storage: Test Event 0').to.eql( + eventQueue[2], + ); }); it('should purge events from Session Storage upon Batch Creation', async () => { @@ -1237,54 +1197,40 @@ describe('batch uploader', () => { window.mParticle._resetForTests(MPConfig); window.mParticle.init(apiKey, window.mParticle.config); - waitForCondition(hasIdentifyReturned) - .then(async () => { - const mpInstance = window.mParticle.getInstance(); - const uploader = mpInstance._APIClient.uploader; - - // Init will fire a Session Start and AST. We are adding event0 - // to show that manually queued events will also be grouped - // into a batch - uploader.queueEvent(event0); - - expect(uploader.eventsQueuedForProcessing.length).to.equal( - 3, - ); - expect(uploader.batchesQueuedForProcessing.length).to.equal( - 0, - ); + await waitForCondition(hasIdentifyReturned); - expect( - window.sessionStorage.getItem(eventStorageKey), - 'Queued Events should appear in Session Storage', - ).to.be.ok; - expect( - JSON.parse( - window.sessionStorage.getItem(eventStorageKey), - ).length, - ).to.equal(3); + const mpInstance = window.mParticle.getInstance(); + const uploader = mpInstance._APIClient.uploader; - // Manually initiate the upload process - turn event into batches and upload the batch - await window.mParticle - .getInstance() - ._APIClient.uploader.prepareAndUpload(); + // Init will fire a Session Start and AST. We are adding event0 + // to show that manually queued events will also be grouped + // into a batch + uploader.queueEvent(event0); - // If Session Storage is purged, it should return an empty string - expect( - window.sessionStorage.getItem(eventStorageKey), - ).to.equal(''); - expect(uploader.eventsQueuedForProcessing.length).to.equal( - 0, - ); + expect(uploader.eventsQueuedForProcessing.length).to.equal(3); + expect(uploader.batchesQueuedForProcessing.length).to.equal(0); - // Batch Queue should be empty because batch successfully uploaded - expect(uploader.batchesQueuedForProcessing.length).to.equal( - 0, - ); - clock.restore(); - // done(); - }) - .catch((e) => {}); + expect( + window.sessionStorage.getItem(eventStorageKey), + 'Queued Events should appear in Session Storage', + ).to.be.ok; + expect( + JSON.parse(window.sessionStorage.getItem(eventStorageKey)) + .length, + ).to.equal(3); + + // Manually initiate the upload process - turn event into batches and upload the batch + await window.mParticle + .getInstance() + ._APIClient.uploader.prepareAndUpload(); + + // If Session Storage is purged, it should return an empty string + expect(window.sessionStorage.getItem(eventStorageKey)).to.equal(''); + expect(uploader.eventsQueuedForProcessing.length).to.equal(0); + + // Batch Queue should be empty because batch successfully uploaded + expect(uploader.batchesQueuedForProcessing.length).to.equal(0); + clock.restore(); }); it('should save batches in sequence to Local Storage when an HTTP 500 error is encountered', async () => { @@ -1294,111 +1240,103 @@ describe('batch uploader', () => { window.mParticle._resetForTests(MPConfig); window.mParticle.init(apiKey, window.mParticle.config); - waitForCondition(hasIdentifyReturned) - .then(async () => { - const mpInstance = window.mParticle.getInstance(); - const uploader = mpInstance._APIClient.uploader; + await waitForCondition(hasIdentifyReturned); - // Init will fire a Session Start and AST. We are adding event0 - // to show that manually queued events will also be grouped - // into a batch - uploader.queueEvent(event0); + const mpInstance = window.mParticle.getInstance(); + const uploader = mpInstance._APIClient.uploader; - // Manually initiate the upload process - turn event into batches and upload the batch - await window.mParticle - .getInstance() - ._APIClient.uploader.prepareAndUpload(); + // Init will fire a Session Start and AST. We are adding event0 + // to show that manually queued events will also be grouped + // into a batch + uploader.queueEvent(event0); - expect(window.localStorage.getItem(batchStorageKey)).to.be - .ok; + // Manually initiate the upload process - turn event into batches and upload the batch + await window.mParticle + .getInstance() + ._APIClient.uploader.prepareAndUpload(); - const storedBatches: Batch[] = JSON.parse( - window.localStorage.getItem(batchStorageKey), - ); + expect(window.localStorage.getItem(batchStorageKey)).to.be.ok; - // Note: Events are usually are groupd together into a single batch - // However, in this case, since we are mocking a custom event (event0) - // our batching logic is grouping event0 into a separate batch from - // the Session Start + AST event from init as they have a different - // SessionID - expect(storedBatches.length).to.equal(2); - expect( - storedBatches[0].events[0].event_type, - 'Batch 1: Session Start', - ).to.equal('session_start'); - expect( - storedBatches[0].events[1].event_type, - 'Batch 1: AST', - ).to.equal('application_state_transition'); + const storedBatches: Batch[] = JSON.parse( + window.localStorage.getItem(batchStorageKey), + ); - expect( - storedBatches[1].events[0].event_type, - 'Batch 2: Custom Event Type', - ).to.equal('custom_event'); - expect( - (storedBatches[1].events[0].data as CustomEventData) - .event_name, - 'Batch 2: Custom Event Name', - ).to.equal('Test Event 0'); - }) - .catch((e) => {}); + // Note: Events are usually are groupd together into a single batch + // However, in this case, since we are mocking a custom event (event0) + // our batching logic is grouping event0 into a separate batch from + // the Session Start + AST event from init as they have a different + // SessionID + expect(storedBatches.length).to.equal(2); + expect( + storedBatches[0].events[0].event_type, + 'Batch 1: Session Start', + ).to.equal('session_start'); + expect( + storedBatches[0].events[1].event_type, + 'Batch 1: AST', + ).to.equal('application_state_transition'); + + expect( + storedBatches[1].events[0].event_type, + 'Batch 2: Custom Event Type', + ).to.equal('custom_event'); + expect( + (storedBatches[1].events[0].data as CustomEventData).event_name, + 'Batch 2: Custom Event Name', + ).to.equal('Test Event 0'); }); - it('should save batches in sequence to Local Storage when an HTTP 429 error is encountered', () => { + it('should save batches in sequence to Local Storage when an HTTP 429 error is encountered', async () => { const batchStorageKey = 'mprtcl-v4_abcdef-batches'; fetchMock.post(urls.events, 429); window.mParticle._resetForTests(MPConfig); window.mParticle.init(apiKey, window.mParticle.config); - waitForCondition(hasIdentifyReturned) - .then(async () => { - const mpInstance = window.mParticle.getInstance(); - const uploader = mpInstance._APIClient.uploader; + await waitForCondition(hasIdentifyReturned); - // Init will fire a Session Start and AST. We are adding event0 - // to show that manually queued events will also be grouped - // into a batch - uploader.queueEvent(event0); + const mpInstance = window.mParticle.getInstance(); + const uploader = mpInstance._APIClient.uploader; - // Manually initiate the upload process - turn event into batches and upload the batch - await window.mParticle - .getInstance() - ._APIClient.uploader.prepareAndUpload(); + // Init will fire a Session Start and AST. We are adding event0 + // to show that manually queued events will also be grouped + // into a batch + uploader.queueEvent(event0); - clock.restore(); + // Manually initiate the upload process - turn event into batches and upload the batch + await window.mParticle + .getInstance() + ._APIClient.uploader.prepareAndUpload(); - expect(window.localStorage.getItem(batchStorageKey)).to.be - .ok; + clock.restore(); - const storedBatches: Batch[] = JSON.parse( - window.localStorage.getItem(batchStorageKey), - ); + expect(window.localStorage.getItem(batchStorageKey)).to.be.ok; - expect(storedBatches.length).to.equal(2); - expect( - storedBatches[0].events[0].event_type, - 'Batch 1: Session Start', - ).to.equal('session_start'); - expect( - storedBatches[0].events[1].event_type, - 'Batch 1: AST', - ).to.equal('application_state_transition'); + const storedBatches: Batch[] = JSON.parse( + window.localStorage.getItem(batchStorageKey), + ); - expect( - storedBatches[1].events[0].event_type, - 'Batch 2: Custom Event Type', - ).to.equal('custom_event'); - expect( - (storedBatches[1].events[0].data as CustomEventData) - .event_name, - 'Batch 2: Custom Event Name', - ).to.equal('Test Event 0'); - }) - .catch((e) => {}); + expect(storedBatches.length).to.equal(2); + expect( + storedBatches[0].events[0].event_type, + 'Batch 1: Session Start', + ).to.equal('session_start'); + expect( + storedBatches[0].events[1].event_type, + 'Batch 1: AST', + ).to.equal('application_state_transition'); + + expect( + storedBatches[1].events[0].event_type, + 'Batch 2: Custom Event Type', + ).to.equal('custom_event'); + expect( + (storedBatches[1].events[0].data as CustomEventData).event_name, + 'Batch 2: Custom Event Name', + ).to.equal('Test Event 0'); }); - it('should NOT save any batches to Local Storage when an HTTP 401 error is encountered', (done) => { + it('should NOT save any batches to Local Storage when an HTTP 401 error is encountered', async () => { // When a 401 is encountered, we assume that the batch is bad so we clear those // batches from the Upload Queue. Therefore, there should not be anything in // Offline Storage afterwards @@ -1408,27 +1346,22 @@ describe('batch uploader', () => { window.mParticle._resetForTests(MPConfig); window.mParticle.init(apiKey, window.mParticle.config); - waitForCondition(hasIdentifyReturned) - .then(async () => { - const mpInstance = window.mParticle.getInstance(); - const uploader = mpInstance._APIClient.uploader; + await waitForCondition(hasIdentifyReturned); - // Init will fire a Session Start and AST. We are adding event0 - // to show that manually queued events will also be grouped - // into a batch - uploader.queueEvent(event0); + const mpInstance = window.mParticle.getInstance(); + const uploader = mpInstance._APIClient.uploader; - // Manually initiate the upload process - turn event into batches and upload the batch - await window.mParticle - .getInstance() - ._APIClient.uploader.prepareAndUpload(); + // Init will fire a Session Start and AST. We are adding event0 + // to show that manually queued events will also be grouped + // into a batch + uploader.queueEvent(event0); - expect( - window.localStorage.getItem(batchStorageKey), - ).to.equal(''); - done(); - }) - .catch((e) => {}); + // Manually initiate the upload process - turn event into batches and upload the batch + await window.mParticle + .getInstance() + ._APIClient.uploader.prepareAndUpload(); + + expect(window.localStorage.getItem(batchStorageKey)).to.equal(''); }); it('should save batches in sequence to Local Storage when upload is interrupted', async () => { @@ -1452,131 +1385,118 @@ describe('batch uploader', () => { // Set up SDK and Uploader window.mParticle._resetForTests(MPConfig); window.mParticle.init(apiKey, window.mParticle.config); - waitForCondition(hasIdentifyReturned) - .then(async () => { - const mpInstance = window.mParticle.getInstance(); - const uploader = mpInstance._APIClient.uploader; + await waitForCondition(hasIdentifyReturned); - const batchValidator = new _BatchValidator(); + const mpInstance = window.mParticle.getInstance(); + const uploader = mpInstance._APIClient.uploader; - // Create sample batches for testing - const batch1 = batchValidator.returnBatch([ - { - messageType: 4, - name: 'Test Event 1', - }, - { - messageType: 4, - name: 'Test Event 2', - }, - ]); - - const batch2 = batchValidator.returnBatch([ - { - messageType: 4, - name: 'Test Event 3', - }, - { - messageType: 4, - name: 'Test Event 4', - }, - ]); - - const batch3 = batchValidator.returnBatch([ - { - messageType: 4, - name: 'Test Event 5', - }, - { - messageType: 4, - name: 'Test Event 6', - }, - ]); - - // Init will generate a batch with Session Start and AST which normally comes first - // but for testing purposes the Session Start + AST batches will be the last batches - // as we are manually queueing additional batches to verify sequence - uploader.batchesQueuedForProcessing.push(batch1); - uploader.batchesQueuedForProcessing.push(batch2); - uploader.batchesQueuedForProcessing.push(batch3); - - // Manually initiate the upload process - // This will also turn the SessionStart + AST events into a batch and add it to the end of the queue - await window.mParticle - .getInstance() - ._APIClient.uploader.prepareAndUpload(); - - expect(window.localStorage.getItem(batchStorageKey)).to.be - .ok; - - const storedBatches: Batch[] = JSON.parse( - window.localStorage.getItem(batchStorageKey), - ); + const batchValidator = new _BatchValidator(); - // We tried to upload 4 batches (3 unique batches + Session Start/AST from init) - expect(storedBatches.length).to.equal(3); + // Create sample batches for testing + const batch1 = batchValidator.returnBatch([ + { + messageType: 4, + name: 'Test Event 1', + }, + { + messageType: 4, + name: 'Test Event 2', + }, + ]); - // FIXME: cursor changed these comments. Double check that this is correct - // The following assertions should verify the sequence presented below - // - Batch 1: Test Event 1 and 2 - Read from Offline Storage - // - Batch 2: Test Event 3 and 4 - Read from Offline Storage - // - Batch 3: Test Event 5 and 6 - Read from Offline Storage - // - Batch 4: Session Start and AST - (new) Created by Init + const batch2 = batchValidator.returnBatch([ + { + messageType: 4, + name: 'Test Event 3', + }, + { + messageType: 4, + name: 'Test Event 4', + }, + ]); - expect( - (storedBatches[0].events[0].data as CustomEventData) - .event_name, - 'Batch 1: Test Event 1 ', - ).to.equal('Test Event 1'); - expect( - (storedBatches[0].events[1].data as CustomEventData) - .event_name, - 'Batch 1: Test Event 2', - ).to.equal('Test Event 2'); + const batch3 = batchValidator.returnBatch([ + { + messageType: 4, + name: 'Test Event 5', + }, + { + messageType: 4, + name: 'Test Event 6', + }, + ]); - expect( - (storedBatches[1].events[0].data as CustomEventData) - .event_name, - 'Batch 2: Test Event 3 Event Name', - ).to.equal('Test Event 3'); - expect( - (storedBatches[1].events[1].data as CustomEventData) - .event_name, - 'Batch 2: Test Event 4 Event Name', - ).to.equal('Test Event 4'); + // Init will generate a batch with Session Start and AST which normally comes first + // but for testing purposes the Session Start + AST batches will be the last batches + // as we are manually queueing additional batches to verify sequence + uploader.batchesQueuedForProcessing.push(batch1); + uploader.batchesQueuedForProcessing.push(batch2); + uploader.batchesQueuedForProcessing.push(batch3); - expect( - (storedBatches[2].events[0].data as CustomEventData) - .event_name, - 'Batch 2: Test Event 5 Event Name', - ).to.equal('Test Event 5'); - expect( - (storedBatches[2].events[1].data as CustomEventData) - .event_name, - 'Batch 2: Test Event 6 Event Name', - ).to.equal('Test Event 6'); - - // These are the events that are generated by mParticle.init. Usually they - // come before any queued events, but we manually queued the previous - // batches increase the number of attempted uploads to verify that batches - // are retained in Offline Storage in order of creation - expect( - storedBatches[3].events[0].event_type, - 'Batch 4: Session Start', - ).to.equal('session_start'); - expect( - storedBatches[3].events[1].event_type, - 'Batch 4: AST', - ).to.equal('application_state_transition'); - }) - .catch((e) => { - console.log( - 'should save batches in sequence to Local Storage when upload is interrupted', - ); - }); + // Manually initiate the upload process + // This will also turn the SessionStart + AST events into a batch and add it to the end of the queue + await window.mParticle + .getInstance() + ._APIClient.uploader.prepareAndUpload(); + + expect(window.localStorage.getItem(batchStorageKey)).to.be.ok; + + const storedBatches: Batch[] = JSON.parse( + window.localStorage.getItem(batchStorageKey), + ); + + // We tried to upload 4 batches (3 unique batches + Session Start/AST from init) + expect(storedBatches.length).to.equal(3); + + // FIXME: cursor changed these comments. Double check that this is correct + // The following assertions should verify the sequence presented below + // - Batch 1: Test Event 1 and 2 - Read from Offline Storage + // - Batch 2: Test Event 3 and 4 - Read from Offline Storage + // - Batch 3: Test Event 5 and 6 - Read from Offline Storage + // - Batch 4: Session Start and AST - (new) Created by Init + + expect( + (storedBatches[0].events[0].data as CustomEventData).event_name, + 'Batch 1: Test Event 1 ', + ).to.equal('Test Event 1'); + expect( + (storedBatches[0].events[1].data as CustomEventData).event_name, + 'Batch 1: Test Event 2', + ).to.equal('Test Event 2'); + + expect( + (storedBatches[1].events[0].data as CustomEventData).event_name, + 'Batch 2: Test Event 3 Event Name', + ).to.equal('Test Event 3'); + expect( + (storedBatches[1].events[1].data as CustomEventData).event_name, + 'Batch 2: Test Event 4 Event Name', + ).to.equal('Test Event 4'); + + expect( + (storedBatches[2].events[0].data as CustomEventData).event_name, + 'Batch 2: Test Event 5 Event Name', + ).to.equal('Test Event 5'); + expect( + (storedBatches[2].events[1].data as CustomEventData).event_name, + 'Batch 2: Test Event 6 Event Name', + ).to.equal('Test Event 6'); + + // These are the events that are generated by mParticle.init. Usually they + // come before any queued events, but we manually queued the previous + // batches increase the number of attempted uploads to verify that batches + // are retained in Offline Storage in order of creation + expect( + storedBatches[3].events[0].event_type, + 'Batch 4: Session Start', + ).to.equal('session_start'); + expect( + storedBatches[3].events[1].event_type, + 'Batch 4: AST', + ).to.equal('application_state_transition'); }); - it('should attempt to upload batches from Offline Storage before new batches', () => { + it('should attempt to upload batches from Offline Storage before new batches', async () => { // This test should verify that batches read from Offline Storage are prepended // to the upload queue before newly created batches. @@ -1587,138 +1507,128 @@ describe('batch uploader', () => { // Set up SDK and Uploader window.mParticle._resetForTests(MPConfig); window.mParticle.init(apiKey, window.mParticle.config); - waitForCondition(hasIdentifyReturned) - .then(async () => { - const mpInstance = window.mParticle.getInstance(); - const uploader = mpInstance._APIClient.uploader; + await waitForCondition(hasIdentifyReturned); - const batchValidator = new _BatchValidator(); + const mpInstance = window.mParticle.getInstance(); + const uploader = mpInstance._APIClient.uploader; - // Create sample batches for testing - const batch1 = batchValidator.returnBatch([ - { - messageType: 4, - name: 'Test Event 1', - }, - { - messageType: 4, - name: 'Test Event 2', - }, - ]); - - const batch2 = batchValidator.returnBatch([ - { - messageType: 4, - name: 'Test Event 3', - }, - { - messageType: 4, - name: 'Test Event 4', - }, - ]); - - const batch3 = batchValidator.returnBatch([ - { - messageType: 4, - name: 'Test Event 5', - }, - { - messageType: 4, - name: 'Test Event 6', - }, - ]); - - // Write batches to Offline Storage before queuing new events or batches - window.localStorage.setItem( - batchStorageKey, - JSON.stringify([batch1, batch2, batch3]), - ); + const batchValidator = new _BatchValidator(); - // Batch Queue should be empty before we upload - expect(uploader.batchesQueuedForProcessing.length).to.equal( - 0, - ); + // Create sample batches for testing + const batch1 = batchValidator.returnBatch([ + { + messageType: 4, + name: 'Test Event 1', + }, + { + messageType: 4, + name: 'Test Event 2', + }, + ]); + + const batch2 = batchValidator.returnBatch([ + { + messageType: 4, + name: 'Test Event 3', + }, + { + messageType: 4, + name: 'Test Event 4', + }, + ]); - // Manually initiate the upload process - turn event into batches and upload the batch - await window.mParticle - .getInstance() - ._APIClient.uploader.prepareAndUpload(); + const batch3 = batchValidator.returnBatch([ + { + messageType: 4, + name: 'Test Event 5', + }, + { + messageType: 4, + name: 'Test Event 6', + }, + ]); - expect( - window.localStorage.getItem(batchStorageKey), - 'Offline Batch Storage should be empty', - ).to.equal(''); + // Write batches to Offline Storage before queuing new events or batches + window.localStorage.setItem( + batchStorageKey, + JSON.stringify([batch1, batch2, batch3]), + ); - // To verify the sequence, we should look at what has been uploaded - // as the upload queue and Offline Storage should be empty - expect(fetchMock.calls().length).to.equal(4); + // Batch Queue should be empty before we upload + expect(uploader.batchesQueuedForProcessing.length).to.equal(0); - const uploadedBatch1: Batch = JSON.parse( - fetchMock.calls()[0][1].body as string, - ); - const uploadedBatch2: Batch = JSON.parse( - fetchMock.calls()[1][1].body as string, - ); - const uploadedBatch3: Batch = JSON.parse( - fetchMock.calls()[2][1].body as string, - ); - const uploadedBatch4: Batch = JSON.parse( - fetchMock.calls()[3][1].body as string, - ); + // Manually initiate the upload process - turn event into batches and upload the batch + await window.mParticle + .getInstance() + ._APIClient.uploader.prepareAndUpload(); - // The following assertions should verify the sequence presented below - // - Batch 1: Test Event 1 and 2 - Read from Offline Storage - // - Batch 2: Test Event 3 and 4 - Read from Offline Storage - // - Batch 3: Test Event 5 and 6 - Read from Offline Storage - // - Batch 4: Session Start and AST - (new) Created by Init + expect( + window.localStorage.getItem(batchStorageKey), + 'Offline Batch Storage should be empty', + ).to.equal(''); - expect( - (uploadedBatch1.events[0].data as CustomEventData) - .event_name, - 'Batch 1: Test Event 1 ', - ).to.equal('Test Event 1'); - expect( - (uploadedBatch1.events[1].data as CustomEventData) - .event_name, - 'Batch 1: Test Event 2', - ).to.equal('Test Event 2'); + // To verify the sequence, we should look at what has been uploaded + // as the upload queue and Offline Storage should be empty + expect(fetchMock.calls().length).to.equal(4); - expect( - (uploadedBatch2.events[0].data as CustomEventData) - .event_name, - 'Batch 2: Test Event 3 Event Name', - ).to.equal('Test Event 3'); - expect( - (uploadedBatch2.events[1].data as CustomEventData) - .event_name, - 'Batch 2: Test Event 4 Event Name', - ).to.equal('Test Event 4'); + const uploadedBatch1: Batch = JSON.parse( + fetchMock.calls()[0][1].body as string, + ); + const uploadedBatch2: Batch = JSON.parse( + fetchMock.calls()[1][1].body as string, + ); + const uploadedBatch3: Batch = JSON.parse( + fetchMock.calls()[2][1].body as string, + ); + const uploadedBatch4: Batch = JSON.parse( + fetchMock.calls()[3][1].body as string, + ); - expect( - (uploadedBatch3.events[0].data as CustomEventData) - .event_name, - 'Batch 2: Test Event 5 Event Name', - ).to.equal('Test Event 5'); - expect( - (uploadedBatch3.events[1].data as CustomEventData) - .event_name, - 'Batch 2: Test Event 6 Event Name', - ).to.equal('Test Event 6'); - - // These are the events that are generated by mParticle.init. Usually they - // come before any queued events, but we manually queued the previous - // batches increase the number of attempted uploads to verify that batches - // are retained in Offline Storage in order of creation - expect( - uploadedBatch4.events[0].event_type, - 'Batch 4: Session Start', - ).to.equal('session_start'); - expect( - uploadedBatch4.events[1].event_type, - 'Batch 4: AST', - ).to.equal('application_state_transition'); - }) - .catch((e) => {}); + // The following assertions should verify the sequence presented below + // - Batch 1: Test Event 1 and 2 - Read from Offline Storage + // - Batch 2: Test Event 3 and 4 - Read from Offline Storage + // - Batch 3: Test Event 5 and 6 - Read from Offline Storage + // - Batch 4: Session Start and AST - (new) Created by Init + + expect( + (uploadedBatch1.events[0].data as CustomEventData).event_name, + 'Batch 1: Test Event 1 ', + ).to.equal('Test Event 1'); + expect( + (uploadedBatch1.events[1].data as CustomEventData).event_name, + 'Batch 1: Test Event 2', + ).to.equal('Test Event 2'); + + expect( + (uploadedBatch2.events[0].data as CustomEventData).event_name, + 'Batch 2: Test Event 3 Event Name', + ).to.equal('Test Event 3'); + expect( + (uploadedBatch2.events[1].data as CustomEventData).event_name, + 'Batch 2: Test Event 4 Event Name', + ).to.equal('Test Event 4'); + + expect( + (uploadedBatch3.events[0].data as CustomEventData).event_name, + 'Batch 2: Test Event 5 Event Name', + ).to.equal('Test Event 5'); + expect( + (uploadedBatch3.events[1].data as CustomEventData).event_name, + 'Batch 2: Test Event 6 Event Name', + ).to.equal('Test Event 6'); + + // These are the events that are generated by mParticle.init. Usually they + // come before any queued events, but we manually queued the previous + // batches increase the number of attempted uploads to verify that batches + // are retained in Offline Storage in order of creation + expect( + uploadedBatch4.events[0].event_type, + 'Batch 4: Session Start', + ).to.equal('session_start'); + expect( + uploadedBatch4.events[1].event_type, + 'Batch 4: AST', + ).to.equal('application_state_transition'); }); }); }); diff --git a/test/src/tests-batchUploader_2.ts b/test/src/tests-batchUploader_2.ts index 69cd3aa8c..1a90d260f 100644 --- a/test/src/tests-batchUploader_2.ts +++ b/test/src/tests-batchUploader_2.ts @@ -1,7 +1,6 @@ import { urls, apiKey, MPConfig, testMPID } from './config/constants'; import Utils from './config/utils'; import { expect } from 'chai'; -import _BatchValidator from '../../src/mockBatchCreator'; import fetchMock from 'fetch-mock/esm/client'; import { IMParticleInstanceManager } from '../../src/sdkRuntimeModels'; import { CustomEvent } from '@mparticle/event-models'; @@ -18,7 +17,6 @@ const enableBatchingConfigFlags = { }; describe('batch uploader', () => { - let mockServer; let clock; beforeEach(() => { @@ -130,7 +128,7 @@ describe('batch uploader', () => { done(); }) - .catch((e) => {}); + .catch(() => {}); }); // TODO: Investigate workflow with unshift vs push diff --git a/test/src/tests-batchUploader_3.ts b/test/src/tests-batchUploader_3.ts index 066e70030..67e5be261 100644 --- a/test/src/tests-batchUploader_3.ts +++ b/test/src/tests-batchUploader_3.ts @@ -2,7 +2,6 @@ import sinon from 'sinon'; import { urls, apiKey, MPConfig, testMPID } from './config/constants'; import Utils from './config/utils'; import { expect } from 'chai'; -import _BatchValidator from '../../src/mockBatchCreator'; import fetchMock from 'fetch-mock/esm/client'; import { ProductActionType } from '../../src/types'; import { IMParticleInstanceManager } from '../../src/sdkRuntimeModels'; @@ -14,12 +13,7 @@ declare global { } } -const enableBatchingConfigFlags = { - eventBatchingIntervalMillis: 1000, -}; - describe('batch uploader', () => { - let mockServer; let clock; beforeEach(() => { diff --git a/test/src/tests-batchUploader_4.ts b/test/src/tests-batchUploader_4.ts index 045715b3b..8507cc393 100644 --- a/test/src/tests-batchUploader_4.ts +++ b/test/src/tests-batchUploader_4.ts @@ -3,7 +3,6 @@ import { urls, apiKey, MPConfig, testMPID } from './config/constants'; import { Batch, CustomEventData } from '@mparticle/event-models'; import Utils from './config/utils'; import { expect } from 'chai'; -import _BatchValidator from '../../src/mockBatchCreator'; import fetchMock from 'fetch-mock/esm/client'; import { ProductActionType } from '../../src/types'; import { IMParticleInstanceManager } from '../../src/sdkRuntimeModels'; @@ -87,7 +86,7 @@ describe('batch uploader', () => { done(); }) - .catch((e) => {}); + .catch(() => {}); }); it('should force uploads when using public `upload`', function (done) { @@ -326,7 +325,7 @@ describe('batch uploader', () => { it('should add a modified boolean of true to a batch that has been modified via a config.onCreateBatch call', function (done) { window.mParticle._resetForTests(MPConfig); - window.mParticle.config.onCreateBatch = function (batch: Batch) { + window.mParticle.config.onCreateBatch = function () { return undefined; }; diff --git a/test/src/tests-beaconUpload.ts b/test/src/tests-beaconUpload.ts index 0ba50e965..790a7a69e 100644 --- a/test/src/tests-beaconUpload.ts +++ b/test/src/tests-beaconUpload.ts @@ -4,16 +4,9 @@ import { expect } from 'chai'; import { urls, apiKey, MPConfig, testMPID } from './config/constants'; import { event0 } from '../fixtures/events'; import { batch1, batch2, batch3 } from '../fixtures/batches'; -import _BatchValidator from '../../src/mockBatchCreator'; import Utils from './config/utils'; import { IMParticleInstanceManager } from '../../src/sdkRuntimeModels'; -const { - findEventFromRequest, - findBatch, - waitForCondition, - fetchMockSuccess, - hasIdentifyReturned, -} = Utils; +const { waitForCondition, fetchMockSuccess, hasIdentifyReturned } = Utils; declare global { interface Window { diff --git a/test/src/tests-config-api-client.ts b/test/src/tests-config-api-client.ts index 054f43e8a..ad98b0302 100644 --- a/test/src/tests-config-api-client.ts +++ b/test/src/tests-config-api-client.ts @@ -18,7 +18,6 @@ declare global { describe('ConfigAPIClient', () => { let mockServer; - let sdkInitCompleteCallback; let configUrl; let dataPlan: DataPlanConfig; let dataPlanResult: DataPlanResult; @@ -27,7 +26,6 @@ describe('ConfigAPIClient', () => { fetchMock.restore(); mockServer = sinon.createFakeServer(); mockServer.respondImmediately = true; - sdkInitCompleteCallback = sinon.spy(); window.mParticle._resetForTests(MPConfig); }); @@ -150,8 +148,7 @@ describe('ConfigAPIClient', () => { window.mParticle.getInstance(), ); - const response = - await configAPIClient.getSDKConfiguration(); + await configAPIClient.getSDKConfiguration(); expect(fetchMock.calls().length).to.equal(1); expect(fetchMock.calls()[0][0]).to.equal(configUrl); @@ -304,8 +301,7 @@ describe('ConfigAPIClient', () => { window.mParticle.getInstance(), ); - const response = - await configAPIClient.getSDKConfiguration(); + await configAPIClient.getSDKConfiguration(); expect(mockServer.lastRequest).to.haveOwnProperty('url'); expect(mockServer.lastRequest.url).to.equal(configUrl); diff --git a/test/src/tests-cookie-syncing.ts b/test/src/tests-cookie-syncing.ts index 2f8216310..f305a73e1 100644 --- a/test/src/tests-cookie-syncing.ts +++ b/test/src/tests-cookie-syncing.ts @@ -45,11 +45,11 @@ describe('cookie syncing', function () { // Mock the img create onload method // https://raminmousavi.medium.com/mock-img-element-in-jest-3341c495ca8b window.document.createElement = (function (create) { - return function (this: Document) { - const element = create.apply( - this, - arguments as unknown as [string, ElementCreationOptions?], - ); + return function ( + this: Document, + ...args: [string, ElementCreationOptions?] + ) { + const element = create.apply(this, args); if (element.tagName === 'IMG') { // Add an `onload` mock that simulates the browser loading the image diff --git a/test/src/tests-identity.ts b/test/src/tests-identity.ts index 73ec45856..31c3a6396 100644 --- a/test/src/tests-identity.ts +++ b/test/src/tests-identity.ts @@ -3087,14 +3087,12 @@ describe('identity', function () { }); it('should have a getUser function on login result object', async () => { - let result; let loginResult; mParticle._resetForTests(MPConfig); mParticle.config.identityCallback = function (resp) { resp.getUser().setUserAttribute('attr', 'value'); - result = resp; }; fetchMockSuccess(urls.identify, { @@ -3135,14 +3133,12 @@ describe('identity', function () { }); it('should have a getUser function on logout result object', async () => { - let result; let logoutResult; mParticle._resetForTests(MPConfig); mParticle.config.identityCallback = function (resp) { resp.getUser().setUserAttribute('attr', 'value'); - result = resp; }; fetchMockSuccess(urls.identify, { @@ -3183,14 +3179,12 @@ describe('identity', function () { }); it('should have a getUser function on modify result object', async () => { - let result; let modifyResult; mParticle._resetForTests(MPConfig); mParticle.config.identityCallback = function (resp) { resp.getUser().setUserAttribute('attr', 'value'); - result = resp; }; fetchMockSuccess(urls.identify, { diff --git a/test/src/tests-kit-blocking.ts b/test/src/tests-kit-blocking.ts index 1b9a03c62..a14d98fef 100644 --- a/test/src/tests-kit-blocking.ts +++ b/test/src/tests-kit-blocking.ts @@ -300,14 +300,9 @@ describe('kit blocking', () => { }); describe('kit blocking - user attributes/identities', () => { - let kitBlocker; let event: SDKEvent; beforeEach(() => { - kitBlocker = new KitBlocker( - kitBlockerDataPlan, - window.mParticle.getInstance(), - ); event = { DeviceId: 'test', IsFirstRun: true, @@ -552,15 +547,10 @@ describe('kit blocking', () => { }); describe('kit blocking - product attributes', () => { - let kitBlocker; let event: SDKEvent; let products; beforeEach(() => { - kitBlocker = new KitBlocker( - kitBlockerDataPlan, - window.mParticle.getInstance(), - ); products = [ { Attributes: { From 88f144903e6b2e4ec298fd425398c297aa73f8e8 Mon Sep 17 00:00:00 2001 From: Alexander Sapountzis Date: Tue, 10 Jun 2025 17:11:32 -0400 Subject: [PATCH 3/5] Save Point --- test/jest/utils.spec.ts | 131 ++++++++++++++++++++------------ test/src/tests-batchUploader.ts | 84 ++++++++++---------- 2 files changed, 125 insertions(+), 90 deletions(-) diff --git a/test/jest/utils.spec.ts b/test/jest/utils.spec.ts index 83cbdb489..3addd52a4 100644 --- a/test/jest/utils.spec.ts +++ b/test/jest/utils.spec.ts @@ -30,8 +30,8 @@ describe('Utils', () => { it('returns all cookies as an object', () => { const expectedResult = { foo: 'bar', - '_cookie1': '1234', - '_cookie2': '39895811.9165333198', + _cookie1: '1234', + _cookie2: '39895811.9165333198', baz: 'qux', }; @@ -63,7 +63,7 @@ describe('Utils', () => { expect(getCookies()).toEqual({}); - global.window = originalWindow + global.window = originalWindow; }); }); @@ -73,29 +73,34 @@ describe('Utils', () => { describe('with URLSearchParams', () => { it('returns an object with the query string parameters that match an array of keys', () => { const keys = ['foo', 'narf']; - + const expectedResult = { foo: 'bar', narf: 'poit', }; - + expect(queryStringParser(url, keys)).toEqual(expectedResult); }); - + it('returns an empty object if no keys are found', () => { const keys = ['quux', 'corge']; - + expect(queryStringParser(url, keys)).toEqual({}); }); - + it('returns an empty object if the URL is empty', () => { const keys = ['foo', 'narf']; - + expect(queryStringParser('', keys)).toEqual({}); }); - + it('returns an empty object if there are no query parameters', () => { - expect(queryStringParser('https://www.example.com', ['foo', 'narf'])).toEqual({}); + expect( + queryStringParser('https://www.example.com', [ + 'foo', + 'narf', + ]), + ).toEqual({}); }); it('returns an object with all the query string parameters if no keys are passed', () => { @@ -115,31 +120,36 @@ describe('Utils', () => { URL = undefined; URLSearchParams = undefined; }); - + it('returns an object with the query string parameters that match an array of keys', () => { const keys = ['foo', 'narf']; - + const expectedResult = { foo: 'bar', narf: 'poit', }; expect(queryStringParser(url, keys)).toEqual(expectedResult); }); - + it('returns an empty object if no keys are found', () => { const keys = ['quux', 'corge']; - + expect(queryStringParser(url, keys)).toEqual({}); }); - + it('returns an empty object if the URL is empty', () => { const keys = ['foo', 'narf']; - + expect(queryStringParser('', keys)).toEqual({}); }); it('returns an empty object if there are no query parameters', () => { - expect(queryStringParser('https://www.example.com', ['foo', 'narf'])).toEqual({}); + expect( + queryStringParser('https://www.example.com', [ + 'foo', + 'narf', + ]), + ).toEqual({}); }); it('returns an object with all the query string parameters if no keys are passed', () => { @@ -154,7 +164,8 @@ describe('Utils', () => { }); it('should handle non-standard characters or malformed urls', () => { - const malformedUrl = 'https://www.example.com?foo=bar&baz=qux&mal=%E0%A4%A&narf=poit¶m0=你好&*;&http://a.com/?c=7&d=8#!/asd+/%^^%zz%%%world你好¶m1¶m2=¶m3=%E0%A4%A¶m4=value1=value2¶m5=a%AFc'; + const malformedUrl = + 'https://www.example.com?foo=bar&baz=qux&mal=%E0%A4%A&narf=poit¶m0=你好&*;&http://a.com/?c=7&d=8#!/asd+/%^^%zz%%%world你好¶m1¶m2=¶m3=%E0%A4%A¶m4=value1=value2¶m5=a%AFc'; const keys = [ 'foo', 'narf', @@ -162,7 +173,7 @@ describe('Utils', () => { 'param1', 'param2', 'param3', - 'param4' + 'param4', ]; const expectedResult = { @@ -171,16 +182,14 @@ describe('Utils', () => { param0: '你好', }; - expect(queryStringParser(malformedUrl, keys)).toEqual(expectedResult); + expect(queryStringParser(malformedUrl, keys)).toEqual( + expectedResult, + ); }); it('should handle different params case sensitivity and return them as lowercased params', () => { - const url = 'https://www.example.com?FoO=bar&bAz=qux&NARF=poit' - const keys = [ - 'foo', - 'baz', - 'narf', - ]; + const url = 'https://www.example.com?FoO=bar&bAz=qux&NARF=poit'; + const keys = ['foo', 'baz', 'narf']; const expectedResult = { foo: 'bar', @@ -214,7 +223,7 @@ describe('Utils', () => { const string = 'https://www.google.com?mpid=%%mpid%%&foo=bar'; expect(replaceMPID(string, mpid)).toEqual( - 'https://www.google.com?mpid=1234&foo=bar' + 'https://www.google.com?mpid=1234&foo=bar', ); }); }); @@ -224,21 +233,27 @@ describe('Utils', () => { const string = 'https://www.google.com?mpid=%%mpid%%&foo=bar'; expect(replaceAmpWithAmpersand(string)).toEqual( - 'https://www.google.com?mpid=%%mpid%%&foo=bar' + 'https://www.google.com?mpid=%%mpid%%&foo=bar', ); }); }); describe('#createCookieSyncUrl', () => { - const pixelUrl: string = 'https://abc.abcdex.net/ibs:exampleid=12345&exampleuuid=%%mpid%%&redir='; - const redirectUrl: string = 'https://cookiesync.mparticle.com/v1/sync?esid=123456&MPID=%%mpid%%&ID=${DD_UUID}&Key=mpApiKey&env=2'; + const pixelUrl = + 'https://abc.abcdex.net/ibs:exampleid=12345&exampleuuid=%%mpid%%&redir='; + const redirectUrl = + 'https://cookiesync.mparticle.com/v1/sync?esid=123456&MPID=%%mpid%%&ID=${DD_UUID}&Key=mpApiKey&env=2'; it('should return a cookieSyncUrl when both pixelUrl and redirectUrl are not null', () => { - expect(createCookieSyncUrl('testMPID', pixelUrl, redirectUrl)).toBe('https://abc.abcdex.net/ibs:exampleid=12345&exampleuuid=testMPID&redir=https%3A%2F%2Fcookiesync.mparticle.com%2Fv1%2Fsync%3Fesid%3D123456%26MPID%3DtestMPID%26ID%3D%24%7BDD_UUID%7D%26Key%3DmpApiKey%26env%3D2'); + expect(createCookieSyncUrl('testMPID', pixelUrl, redirectUrl)).toBe( + 'https://abc.abcdex.net/ibs:exampleid=12345&exampleuuid=testMPID&redir=https%3A%2F%2Fcookiesync.mparticle.com%2Fv1%2Fsync%3Fesid%3D123456%26MPID%3DtestMPID%26ID%3D%24%7BDD_UUID%7D%26Key%3DmpApiKey%26env%3D2', + ); }); it('should return a cookieSyncUrl when pixelUrl is not null but redirectUrl is null', () => { - expect(createCookieSyncUrl('testMPID', pixelUrl, null)).toBe('https://abc.abcdex.net/ibs:exampleid=12345&exampleuuid=testMPID&redir='); + expect(createCookieSyncUrl('testMPID', pixelUrl, null)).toBe( + 'https://abc.abcdex.net/ibs:exampleid=12345&exampleuuid=testMPID&redir=', + ); }); }); @@ -278,22 +293,26 @@ describe('Utils', () => { describe('#filterDictionaryWithHash', () => { it('should filter a dictionary based on a hash function and filter list', () => { const dictionary = { - 'foo': 'bar', - 'bar': 'baz', - 'baz': 'qux', - 'quux': 'corge', + foo: 'bar', + bar: 'baz', + baz: 'qux', + quux: 'corge', }; - + const filterList = [ 98, // charCode for 'b' 102, // charCode for 'f' ]; const hashFn = (key: string): number => key.charCodeAt(0); - const filtered = filterDictionaryWithHash(dictionary, filterList, hashFn); + const filtered = filterDictionaryWithHash( + dictionary, + filterList, + hashFn, + ); expect(filtered).toEqual({ - 'quux': 'corge', + quux: 'corge', }); }); }); @@ -311,7 +330,10 @@ describe('Utils', () => { }; const config: SDKInitConfig = { - kitConfigs: [roktKitConfig as IKitConfigs, otherKitConfig as IKitConfigs], + kitConfigs: [ + roktKitConfig as IKitConfigs, + otherKitConfig as IKitConfigs, + ], }; const result = parseConfig(config, 'Rokt', 181); @@ -330,21 +352,34 @@ describe('Utils', () => { describe('#parseSettingsString', () => { it('should parse a settings string', () => { - const settingsString = "[{"jsmap":null,"map":"f.name","maptype":"UserAttributeClass.Name","value":"firstname"},{"jsmap":null,"map":"last_name","maptype":"UserAttributeClass.Name","value":"lastname"}]"; + const settingsString = + '[{"jsmap":null,"map":"f.name","maptype":"UserAttributeClass.Name","value":"firstname"},{"jsmap":null,"map":"last_name","maptype":"UserAttributeClass.Name","value":"lastname"}]'; expect(parseSettingsString(settingsString)).toEqual([ - { jsmap: null, map: 'f.name', maptype: 'UserAttributeClass.Name', value: 'firstname' }, - { jsmap: null, map: 'last_name', maptype: 'UserAttributeClass.Name', value: 'lastname' }, + { + jsmap: null, + map: 'f.name', + maptype: 'UserAttributeClass.Name', + value: 'firstname', + }, + { + jsmap: null, + map: 'last_name', + maptype: 'UserAttributeClass.Name', + value: 'lastname', + }, ]); }); it('returns an empty array if the settings string is empty', () => { - const settingsString = ""; + const settingsString = ''; expect(parseSettingsString(settingsString)).toEqual([]); }); it('throws an error message if the settings string is not a valid JSON', () => { - const settingsString = "not a valid JSON"; - expect(() => parseSettingsString(settingsString)).toThrow('Settings string contains invalid JSON'); + const settingsString = 'not a valid JSON'; + expect(() => parseSettingsString(settingsString)).toThrow( + 'Settings string contains invalid JSON', + ); }); }); -}); \ No newline at end of file +}); diff --git a/test/src/tests-batchUploader.ts b/test/src/tests-batchUploader.ts index e5af5c3df..afeb5ef46 100644 --- a/test/src/tests-batchUploader.ts +++ b/test/src/tests-batchUploader.ts @@ -803,54 +803,52 @@ describe('batch uploader', () => { it('should return batches that fail to upload with 429 errors', async () => { window.mParticle.init(apiKey, window.mParticle.config); - waitForCondition(hasIdentifyReturned).then(async () => { - fetchMock.post(urls.events, 429); + await waitForCondition(hasIdentifyReturned); - const newLogger = new Logger(window.mParticle.config); - const mpInstance = window.mParticle.getInstance(); + fetchMock.post(urls.events, 429); - const uploader = new BatchUploader(mpInstance, 1000); + const newLogger = new Logger(window.mParticle.config); + const mpInstance = window.mParticle.getInstance(); - const batchValidator = new _BatchValidator(); + const uploader = new BatchUploader(mpInstance, 1000); - const batch1 = batchValidator.returnBatch({ - messageType: 4, - name: 'Test Event 1', - }); + const batchValidator = new _BatchValidator(); - const batch2 = batchValidator.returnBatch({ - messageType: 4, - name: 'Test Event 2', - }); - const batch3 = batchValidator.returnBatch({ - messageType: 4, - name: 'Test Event 3', - }); + const batch1 = batchValidator.returnBatch({ + messageType: 4, + name: 'Test Event 1', + }); - // HACK: Directly access uploader to Force an upload - const batchesNotUploaded = await (( - uploader - )).uploadBatches( - newLogger, - [batch1, batch2, batch3], - false, - ); + const batch2 = batchValidator.returnBatch({ + messageType: 4, + name: 'Test Event 2', + }); + const batch3 = batchValidator.returnBatch({ + messageType: 4, + name: 'Test Event 3', + }); - expect( - batchesNotUploaded.length, - 'Should have 3 uploaded batches', - ).to.equal(3); + // HACK: Directly access uploader to Force an upload + const batchesNotUploaded = await (uploader).uploadBatches( + newLogger, + [batch1, batch2, batch3], + false, + ); - expect( - batchesNotUploaded[0].events[0].data.event_name, - ).to.equal('Test Event 1'); - expect( - batchesNotUploaded[1].events[0].data.event_name, - ).to.equal('Test Event 2'); - expect( - batchesNotUploaded[2].events[0].data.event_name, - ).to.equal('Test Event 3'); - }); + expect( + batchesNotUploaded.length, + 'Should have 3 uploaded batches', + ).to.equal(3); + + expect( + batchesNotUploaded[0].events[0].data.event_name, + ).to.equal('Test Event 1'); + expect( + batchesNotUploaded[1].events[0].data.event_name, + ).to.equal('Test Event 2'); + expect( + batchesNotUploaded[2].events[0].data.event_name, + ).to.equal('Test Event 3'); }); it('should return null if batches fail to upload with 401 errors', async () => { @@ -1364,7 +1362,8 @@ describe('batch uploader', () => { expect(window.localStorage.getItem(batchStorageKey)).to.equal(''); }); - it('should save batches in sequence to Local Storage when upload is interrupted', async () => { + // https://go.mparticle.com/work/SQDSDKS-7393 + it.skip('should save batches in sequence to Local Storage when upload is interrupted', async () => { // Interruption in this context means that the first upload is successful, but // the next upload in sequence is not. For example, on a mobile device on the // subway or if a connection is rate limited. In this case, we should save @@ -1496,7 +1495,8 @@ describe('batch uploader', () => { ).to.equal('application_state_transition'); }); - it('should attempt to upload batches from Offline Storage before new batches', async () => { + // https://go.mparticle.com/work/SQDSDKS-7393 + it.skip('should attempt to upload batches from Offline Storage before new batches', async () => { // This test should verify that batches read from Offline Storage are prepended // to the upload queue before newly created batches. From 337e876a1f515f1f1bdd9d390b557e6abe05c133 Mon Sep 17 00:00:00 2001 From: Alexander Sapountzis Date: Tue, 10 Jun 2025 17:11:43 -0400 Subject: [PATCH 4/5] Save Point --- src/pre-init-utils.ts | 10 ++++++---- src/roktManager.ts | 6 +++--- src/sdkRuntimeModels.ts | 5 ++--- src/utils.ts | 3 +++ 4 files changed, 14 insertions(+), 10 deletions(-) diff --git a/src/pre-init-utils.ts b/src/pre-init-utils.ts index 4e02bc06c..874a612b6 100644 --- a/src/pre-init-utils.ts +++ b/src/pre-init-utils.ts @@ -4,14 +4,14 @@ import { IntegrationDelays } from './mp-instance'; import { isEmpty, isFunction } from './utils'; export interface IPreInit { - readyQueue: Function[] | any[]; + readyQueue: (() => void)[] | any[]; integrationDelays: IntegrationDelays; forwarderConstructors: MPForwarder[]; pixelConfigurations?: IPixelConfiguration[]; isDevelopmentMode?: boolean; } -export const processReadyQueue = (readyQueue): Function[] => { +export const processReadyQueue = (readyQueue): (() => void)[] => { if (!isEmpty(readyQueue)) { readyQueue.forEach((readyQueueItem) => { if (isFunction(readyQueueItem)) { @@ -34,7 +34,7 @@ const processPreloadedItem = (readyQueueItem): void => { window.mParticle && window.mParticle[args[0]] ) { - window.mParticle[method].apply(window.mParticle, args); + window.mParticle[method](...args); // otherwise, the method is on either eCommerce or Identity objects, ie. "eCommerce.setCurrencyCode", "Identity.login" } else { const methodArray = method.split('.'); @@ -49,7 +49,9 @@ const processPreloadedItem = (readyQueueItem): void => { } // Apply the function with its proper context - (computedMPFunction as unknown as Function).apply(context, args); + ( + computedMPFunction as unknown as (...args: unknown[]) => unknown + ).apply(context, args); } catch (e) { throw new Error('Unable to compute proper mParticle function ' + e); } diff --git a/src/roktManager.ts b/src/roktManager.ts index a4b6d5d14..79bd95cdd 100644 --- a/src/roktManager.ts +++ b/src/roktManager.ts @@ -2,7 +2,7 @@ import { IKitConfigs } from './configAPIClient'; import { UserAttributeFilters } from './forwarders.interfaces'; import { IMParticleUser } from './identity-user-interfaces'; import KitFilterHelper from './kitFilterHelper'; -import { Dictionary, parseSettingsString } from './utils'; +import { Dictionary, parseSettingsString, QueueFunction } from './utils'; import { SDKIdentityApi } from './identity.interfaces'; import { SDKLoggerApi } from './sdkRuntimeModels'; @@ -201,7 +201,7 @@ export default class RoktManager { // Call identify with the new user identities try { - await new Promise((resolve, reject) => { + await new Promise((resolve) => { this.identityService.identify( { userIdentities: { @@ -334,7 +334,7 @@ export default class RoktManager { if (this.messageQueue.length > 0 && this.isReady()) { this.messageQueue.forEach(async (message) => { if (this.kit && message.methodName in this.kit) { - await (this.kit[message.methodName] as Function)( + await (this.kit[message.methodName] as QueueFunction)( message.payload, ); } diff --git a/src/sdkRuntimeModels.ts b/src/sdkRuntimeModels.ts index f4cecf4f4..bd04a5ba4 100644 --- a/src/sdkRuntimeModels.ts +++ b/src/sdkRuntimeModels.ts @@ -237,14 +237,13 @@ export interface MParticleWebSDK { setOptOut(isOptingOut: boolean): void; eCommerce: SDKECommerceAPI; isInitialized(): boolean; - ready(f: Function): void; + ready(f: () => void): void; // https://go.mparticle.com/work/SQDSDKS-7072 reset(instance?: IMParticleWebSDKInstance): void; setAppName(name: string): void; setAppVersion(version: string): void; - setOptOut(isOptingOut: boolean): void; // https://go.mparticle.com/work/SQDSDKS-7063 startTrackingLocation(callback?: Callback): void; @@ -331,7 +330,7 @@ export interface SDKInitConfig launcherOptions?: IRoktLauncherOptions; - rq?: Function[] | any[]; + rq?: (() => void)[] | any[]; } export interface DataPlanConfig { diff --git a/src/utils.ts b/src/utils.ts index c71e64d7d..62fd8d92e 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -10,6 +10,8 @@ type valueof = T[keyof T]; // Placeholder for Dictionary-like Types export type Dictionary = Record; +export type QueueFunction = (payload: unknown) => unknown; + export type Environment = valueof; const createCookieString = (value: string): string => @@ -102,6 +104,7 @@ function generateHash(name: string): number { return hash; } +// https://go.mparticle.com/work/SQDSDKS-5226 const generateRandomValue = (value?: string): string => { let randomValue: string; let a: number; From 3440d97361065605a50d0ebbb22916b225077394 Mon Sep 17 00:00:00 2001 From: Alexander Sapountzis Date: Tue, 10 Jun 2025 17:29:45 -0400 Subject: [PATCH 5/5] Save Point --- src/persistence.js | 195 ++++++++++++++++++++++----------------------- 1 file changed, 95 insertions(+), 100 deletions(-) diff --git a/src/persistence.js b/src/persistence.js index 32cddb87e..d1fa8e618 100644 --- a/src/persistence.js +++ b/src/persistence.js @@ -21,10 +21,9 @@ export default function _Persistence(mpInstance) { this.initializeStorage = function () { try { - let storage, - localStorageData = self.getLocalStorage(), - cookies = self.getCookie(), - allData; + let storage, allData; + const localStorageData = self.getLocalStorage(), + cookies = self.getCookie(); // https://go.mparticle.com/work/SQDSDKS-6045 // Determine if there is any data in cookies or localStorage to figure out if it is the first time the browser is loading mParticle @@ -92,9 +91,10 @@ export default function _Persistence(mpInstance) { const encodedProducts = localStorage.getItem( mpInstance._Store.prodStorageName, ); + let decodedProducts; if (encodedProducts) { - var decodedProducts = JSON.parse( + decodedProducts = JSON.parse( Base64.decode(encodedProducts), ); } @@ -271,12 +271,10 @@ export default function _Persistence(mpInstance) { return []; } - let decodedProducts, - userProducts, - parsedProducts, - encodedProducts = localStorage.getItem( - mpInstance._Store.prodStorageName, - ); + let decodedProducts, userProducts, parsedProducts; + const encodedProducts = localStorage.getItem( + mpInstance._Store.prodStorageName, + ); if (encodedProducts) { decodedProducts = Base64.decode(encodedProducts); } @@ -306,11 +304,11 @@ export default function _Persistence(mpInstance) { }; this.getAllUserProductsFromLS = function () { - let decodedProducts, - encodedProducts = localStorage.getItem( - mpInstance._Store.prodStorageName, - ), - parsedDecodedProducts; + let decodedProducts; + let parsedDecodedProducts; + const encodedProducts = localStorage.getItem( + mpInstance._Store.prodStorageName, + ); if (encodedProducts) { decodedProducts = Base64.decode(encodedProducts); } @@ -330,16 +328,16 @@ export default function _Persistence(mpInstance) { return; } - let key = mpInstance._Store.storageName, - allLocalStorageProducts = self.getAllUserProductsFromLS(), - localStorageData = self.getLocalStorage() || {}, - currentUser = mpInstance.Identity.getCurrentUser(), - mpid = currentUser ? currentUser.getMPID() : null, - currentUserProducts = { - cp: allLocalStorageProducts[mpid] - ? allLocalStorageProducts[mpid].cp - : [], - }; + const key = mpInstance._Store.storageName; + let allLocalStorageProducts = self.getAllUserProductsFromLS(); + let localStorageData = self.getLocalStorage() || {}; + const currentUser = mpInstance.Identity.getCurrentUser(); + const mpid = currentUser ? currentUser.getMPID() : null; + const currentUserProducts = { + cp: allLocalStorageProducts[mpid] + ? allLocalStorageProducts[mpid].cp + : [], + }; if (mpid) { allLocalStorageProducts = allLocalStorageProducts || {}; allLocalStorageProducts[mpid] = currentUserProducts; @@ -421,12 +419,12 @@ export default function _Persistence(mpInstance) { return null; } - let key = mpInstance._Store.storageName, - localStorageData = self.decodePersistence( - window.localStorage.getItem(key), - ), - obj = {}, - j; + const key = mpInstance._Store.storageName; + let localStorageData = self.decodePersistence( + window.localStorage.getItem(key), + ); + const obj = {}; + let j; if (localStorageData) { localStorageData = JSON.parse(localStorageData); for (j in localStorageData) { @@ -448,13 +446,10 @@ export default function _Persistence(mpInstance) { } this.expireCookies = function (cookieName) { - let date = new Date(), - expires, - domain, - cookieDomain; - - cookieDomain = self.getCookieDomain(); + const date = new Date(); + const cookieDomain = self.getCookieDomain(); + let domain; if (cookieDomain === '') { domain = ''; } else { @@ -462,19 +457,19 @@ export default function _Persistence(mpInstance) { } date.setTime(date.getTime() - 24 * 60 * 60 * 1000); - expires = '; expires=' + date.toUTCString(); + const expires = '; expires=' + date.toUTCString(); document.cookie = cookieName + '=' + '' + expires + '; path=/' + domain; }; this.getCookie = function () { - let cookies, - key = mpInstance._Store.storageName, - i, - l, - parts, - name, - cookie, - result = key ? undefined : {}; + let cookies; + let i; + let l; + let parts; + let name; + let cookie; + const key = mpInstance._Store.storageName; + let result = key ? undefined : {}; mpInstance.Logger.verbose(Messages.InformationMessages.CookieSearch); @@ -517,27 +512,24 @@ export default function _Persistence(mpInstance) { // https://go.mparticle.com/work/SQDSDKS-5022 // https://go.mparticle.com/work/SQDSDKS-6021 this.setCookie = function () { - let mpid, - currentUser = mpInstance.Identity.getCurrentUser(); + const currentUser = mpInstance.Identity.getCurrentUser(); + let mpid; if (currentUser) { mpid = currentUser.getMPID(); } - let date = new Date(), - key = mpInstance._Store.storageName, - cookies = self.getCookie() || {}, - expires = new Date( - date.getTime() + - mpInstance._Store.SDKConfig.cookieExpiration * - 24 * - 60 * - 60 * - 1000, - ).toGMTString(), - cookieDomain, - domain, - encodedCookiesWithExpirationAndPath; - - cookieDomain = self.getCookieDomain(); + const date = new Date(); + const key = mpInstance._Store.storageName; + let cookies = self.getCookie() || {}; + const expires = new Date( + date.getTime() + + mpInstance._Store.SDKConfig.cookieExpiration * + 24 * + 60 * + 60 * + 1000, + ).toGMTString(); + const cookieDomain = self.getCookieDomain(); + let domain; if (cookieDomain === '') { domain = ''; @@ -568,12 +560,13 @@ export default function _Persistence(mpInstance) { mpInstance._Store.nonCurrentUserMPIDs = {}; } - encodedCookiesWithExpirationAndPath = self.reduceAndEncodePersistence( - cookies, - expires, - domain, - mpInstance._Store.SDKConfig.maxCookieSize, - ); + const encodedCookiesWithExpirationAndPath = + self.reduceAndEncodePersistence( + cookies, + expires, + domain, + mpInstance._Store.SDKConfig.maxCookieSize, + ); mpInstance.Logger.verbose(Messages.InformationMessages.CookieSet); @@ -599,8 +592,10 @@ export default function _Persistence(mpInstance) { domain, maxCookieSize, ) { - let encodedCookiesWithExpirationAndPath, - currentSessionMPIDs = persistence.gs.csm ? persistence.gs.csm : []; + let encodedCookiesWithExpirationAndPath; + const currentSessionMPIDs = persistence.gs.csm + ? persistence.gs.csm + : []; // Comment 1 above if (!currentSessionMPIDs.length) { for (const key in persistence) { @@ -731,7 +726,7 @@ export default function _Persistence(mpInstance) { this.encodePersistence = function (persistence) { persistence = JSON.parse(persistence); - for (var key in persistence.gs) { + for (const key in persistence.gs) { if (persistence.gs.hasOwnProperty(key)) { if (Base64CookieKeys[key]) { if (persistence.gs[key]) { @@ -764,7 +759,7 @@ export default function _Persistence(mpInstance) { for (const mpid in persistence) { if (persistence.hasOwnProperty(mpid)) { if (!SDKv2NonMPIDCookieKeys[mpid]) { - for (key in persistence[mpid]) { + for (const key in persistence[mpid]) { if (persistence[mpid].hasOwnProperty(key)) { if (Base64CookieKeys[key]) { if ( @@ -799,7 +794,7 @@ export default function _Persistence(mpInstance) { mpInstance._Helpers.isObject(persistence) && Object.keys(persistence).length ) { - for (var key in persistence.gs) { + for (const key in persistence.gs) { if (persistence.gs.hasOwnProperty(key)) { if (Base64CookieKeys[key]) { persistence.gs[key] = JSON.parse( @@ -816,7 +811,7 @@ export default function _Persistence(mpInstance) { for (const mpid in persistence) { if (persistence.hasOwnProperty(mpid)) { if (!SDKv2NonMPIDCookieKeys[mpid]) { - for (key in persistence[mpid]) { + for (const key in persistence[mpid]) { if (persistence[mpid].hasOwnProperty(key)) { if (Base64CookieKeys[key]) { if (persistence[mpid][key].length) { @@ -865,10 +860,10 @@ export default function _Persistence(mpInstance) { // "domain.co.uk" -> success, return // "subdomain.domain.co.uk" -> skipped, because already found this.getDomain = function (doc, locationHostname) { - let i, - testParts, - mpTest = 'mptest=cookie', - hostname = locationHostname.split('.'); + let i; + let testParts; + const mpTest = 'mptest=cookie'; + const hostname = locationHostname.split('.'); for (i = hostname.length - 1; i >= 0; i--) { testParts = hostname.slice(i).join('.'); doc.cookie = mpTest + ';domain=.' + testParts + ';'; @@ -885,10 +880,10 @@ export default function _Persistence(mpInstance) { }; this.getCartProducts = function (mpid) { - let allCartProducts, - cartProductsString = localStorage.getItem( - mpInstance._Store.prodStorageName, - ); + let allCartProducts; + const cartProductsString = localStorage.getItem( + mpInstance._Store.prodStorageName, + ); if (cartProductsString) { allCartProducts = JSON.parse(Base64.decode(cartProductsString)); if ( @@ -953,21 +948,21 @@ export default function _Persistence(mpInstance) { // https://go.mparticle.com/work/SQDSDKS-6021 this.savePersistence = function (persistence) { - let encodedPersistence = self.encodePersistence( - JSON.stringify(persistence), - ), - date = new Date(), - key = mpInstance._Store.storageName, - expires = new Date( - date.getTime() + - mpInstance._Store.SDKConfig.cookieExpiration * - 24 * - 60 * - 60 * - 1000, - ).toGMTString(), - cookieDomain = self.getCookieDomain(), - domain; + const encodedPersistence = self.encodePersistence( + JSON.stringify(persistence), + ); + const date = new Date(); + const key = mpInstance._Store.storageName; + const expires = new Date( + date.getTime() + + mpInstance._Store.SDKConfig.cookieExpiration * + 24 * + 60 * + 60 * + 1000, + ).toGMTString(); + const cookieDomain = self.getCookieDomain(); + let domain; if (cookieDomain === '') { domain = '';