diff --git a/src/events.interfaces.ts b/src/events.interfaces.ts index 0674e47a8..71bef989f 100644 --- a/src/events.interfaces.ts +++ b/src/events.interfaces.ts @@ -8,6 +8,7 @@ import { BaseEvent, SDKEvent, SDKEventCustomFlags, + SDKImpression, SDKProduct, SDKProductImpression, SDKPromotion, @@ -45,11 +46,11 @@ export interface IEvents { ): void; logEvent(event: BaseEvent, eventOptions?: SDKEventOptions): void; logImpressionEvent( - impression: SDKProductImpression, + impression: SDKImpression | SDKImpression[] | SDKProductImpression | SDKProductImpression[], attrs?: SDKEventAttrs, customFlags?: SDKEventCustomFlags, eventOptions?: SDKEventOptions - ); + ): void; logOptOut(): void; logProductActionEvent( productActionType: valueof, @@ -61,7 +62,7 @@ export interface IEvents { ): void; logPromotionEvent( promotionType: valueof, - promotion: SDKPromotion, + promotion: SDKPromotion | SDKPromotion[], attrs?: SDKEventAttrs, customFlags?: SDKEventCustomFlags, eventOptions?: SDKEventOptions diff --git a/src/events.js b/src/events.ts similarity index 55% rename from src/events.js rename to src/events.ts index 73969b5df..f728ae9e0 100644 --- a/src/events.js +++ b/src/events.ts @@ -1,16 +1,39 @@ -import Types from './types'; +import Types, { EventType, ProductActionType, PromotionActionType } from './types'; import Constants from './constants'; +import { IEvents } from './events.interfaces'; +import { IMParticleWebSDKInstance } from './mp-instance'; +import { + BaseEvent, + SDKEvent, + SDKEventCustomFlags, + SDKImpression, + SDKProduct, + SDKProductActionType, + SDKProductImpression, + SDKPromotion, +} from './sdkRuntimeModels'; +import { SDKEventAttrs, SDKEventOptions, TransactionAttributes } from '@mparticle/web-sdk'; +import { valueof } from './utils'; + +interface DOMHandlerElement extends HTMLElement { + href?: string; + target?: string; + submit?: () => void; + attachEvent?: (event: string, handler: EventListener) => void; +} -var Messages = Constants.Messages; +const Messages = Constants.Messages; -export default function Events(mpInstance) { - var self = this; - this.logEvent = function(event, options) { +export default function Events( + this: IEvents, + mpInstance: IMParticleWebSDKInstance +): void { + this.logEvent = function(event: BaseEvent, options?: SDKEventOptions): void { mpInstance.Logger.verbose( 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( @@ -19,25 +42,25 @@ export default function Events(mpInstance) { } }; - this.startTracking = function(callback) { - if (!mpInstance._Store.isTracking) { - if ('geolocation' in navigator) { - mpInstance._Store.watchPositionId = navigator.geolocation.watchPosition( - successTracking, - errorTracking - ); - } - } else { - var position = { + this.startTracking = function(callback: ((position?: GeolocationPosition | { coords: { latitude: number | string; longitude: number | string } }) => void) | null): void { + if (mpInstance._Store.isTracking) { + const position = { coords: { latitude: mpInstance._Store.currentPosition.lat, longitude: mpInstance._Store.currentPosition.lng, }, }; triggerCallback(callback, position); + } else { + if ('geolocation' in navigator) { + mpInstance._Store.watchPositionId = navigator.geolocation.watchPosition( + successTracking, + errorTracking + ); + } } - function successTracking(position) { + function successTracking(position: GeolocationPosition): void { mpInstance._Store.currentPosition = { lat: position.coords.latitude, lng: position.coords.longitude, @@ -50,14 +73,17 @@ export default function Events(mpInstance) { mpInstance._Store.isTracking = true; } - function errorTracking() { + function errorTracking(): void { triggerCallback(callback); // prevents callback from being fired multiple times callback = null; mpInstance._Store.isTracking = false; } - function triggerCallback(callback, position) { + function triggerCallback( + callback: ((position?: GeolocationPosition | { coords: { latitude: number | string; longitude: number | string } }) => void) | null, + position?: GeolocationPosition | { coords: { latitude: number | string; longitude: number | string } } + ): void { if (callback) { try { if (position) { @@ -69,13 +95,13 @@ export default function Events(mpInstance) { mpInstance.Logger.error( 'Error invoking the callback passed to startTrackingLocation.' ); - mpInstance.Logger.error(e); + mpInstance.Logger.error(e instanceof Error ? e.message : String(e)); } } } }; - this.stopTracking = function() { + this.stopTracking = function(): void { if (mpInstance._Store.isTracking) { navigator.geolocation.clearWatch(mpInstance._Store.watchPositionId); mpInstance._Store.currentPosition = null; @@ -83,24 +109,29 @@ export default function Events(mpInstance) { } }; - this.logOptOut = function() { + this.logOptOut = function(): void { mpInstance.Logger.verbose( 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() { - self.logEvent({ messageType: Types.MessageType.AppStateTransition }); + this.logAST = (): void => { + this.logEvent({ messageType: Types.MessageType.AppStateTransition }); }; - this.logCheckoutEvent = function(step, option, attrs, customFlags) { - var event = mpInstance._Ecommerce.createCommerceEventObject( + this.logCheckoutEvent = ( + step: number, + option?: string, + attrs?: SDKEventAttrs, + customFlags?: SDKEventCustomFlags + ): void => { + const event = mpInstance._Ecommerce.createCommerceEventObject( customFlags ); @@ -116,26 +147,26 @@ export default function Events(mpInstance) { ProductList: [], }; - self.logCommerceEvent(event, attrs); + this.logCommerceEvent(event, attrs); } }; - this.logProductActionEvent = function( - productActionType, - product, - customAttrs, - customFlags, - transactionAttributes, - options - ) { - var event = mpInstance._Ecommerce.createCommerceEventObject( + this.logProductActionEvent = ( + productActionType: valueof, + product: SDKProduct | SDKProduct[], + customAttrs?: SDKEventAttrs, + customFlags?: SDKEventCustomFlags, + transactionAttributes?: TransactionAttributes, + options?: SDKEventOptions + ): void => { + const event = mpInstance._Ecommerce.createCommerceEventObject( customFlags, options ); - var productList = Array.isArray(product) ? product : [product]; + const productList: SDKProduct[] = Array.isArray(product) ? product : [product]; - productList.forEach(function(product) { + productList.forEach(function(product: SDKProduct) { if (product.TotalAmount) { product.TotalAmount = mpInstance._Ecommerce.sanitizeAmount( product.TotalAmount, @@ -163,35 +194,36 @@ export default function Events(mpInstance) { }); if (event) { - event.EventCategory = mpInstance._Ecommerce.convertProductActionToEventType( + // TODO(SDKE-1106): Remove `as Function` casts when ecommerce.js is migrated to TS + event.EventCategory = (mpInstance._Ecommerce.convertProductActionToEventType as Function)( productActionType ); event.EventName += mpInstance._Ecommerce.getProductActionEventName( productActionType ); event.ProductAction = { - ProductActionType: productActionType, + ProductActionType: productActionType as SDKProductActionType, ProductList: productList, }; if (mpInstance._Helpers.isObject(transactionAttributes)) { - mpInstance._Ecommerce.convertTransactionAttributesToProductAction( + (mpInstance._Ecommerce.convertTransactionAttributesToProductAction as Function)( transactionAttributes, event.ProductAction ); } - self.logCommerceEvent(event, customAttrs, options); + this.logCommerceEvent(event, customAttrs, options); } }; - this.logPurchaseEvent = function( - transactionAttributes, - product, - attrs, - customFlags - ) { - var event = mpInstance._Ecommerce.createCommerceEventObject( + this.logPurchaseEvent = ( + transactionAttributes: TransactionAttributes, + product: SDKProduct | SDKProduct[], + attrs?: SDKEventAttrs, + customFlags?: SDKEventCustomFlags + ): void => { + const event = mpInstance._Ecommerce.createCommerceEventObject( customFlags ); @@ -203,32 +235,32 @@ export default function Events(mpInstance) { event.ProductAction = { ProductActionType: Types.ProductActionType.Purchase, }; - event.ProductAction.ProductList = mpInstance._Ecommerce.buildProductList( + event.ProductAction.ProductList = (mpInstance._Ecommerce.buildProductList as Function)( event, product ); - mpInstance._Ecommerce.convertTransactionAttributesToProductAction( + (mpInstance._Ecommerce.convertTransactionAttributesToProductAction as Function)( transactionAttributes, event.ProductAction ); - self.logCommerceEvent(event, attrs); + this.logCommerceEvent(event, attrs); } }; - this.logRefundEvent = function( - transactionAttributes, - product, - attrs, - customFlags - ) { + this.logRefundEvent = ( + transactionAttributes: TransactionAttributes, + product: SDKProduct | SDKProduct[], + attrs?: SDKEventAttrs, + customFlags?: SDKEventCustomFlags + ): void => { if (!transactionAttributes) { mpInstance.Logger.error(Messages.ErrorMessages.TransactionRequired); return; } - var event = mpInstance._Ecommerce.createCommerceEventObject( + const event = mpInstance._Ecommerce.createCommerceEventObject( customFlags ); @@ -240,28 +272,28 @@ export default function Events(mpInstance) { event.ProductAction = { ProductActionType: Types.ProductActionType.Refund, }; - event.ProductAction.ProductList = mpInstance._Ecommerce.buildProductList( + event.ProductAction.ProductList = (mpInstance._Ecommerce.buildProductList as Function)( event, product ); - mpInstance._Ecommerce.convertTransactionAttributesToProductAction( + (mpInstance._Ecommerce.convertTransactionAttributesToProductAction as Function)( transactionAttributes, event.ProductAction ); - self.logCommerceEvent(event, attrs); + this.logCommerceEvent(event, attrs); } }; - this.logPromotionEvent = function( - promotionType, - promotion, - attrs, - customFlags, - eventOptions - ) { - var event = mpInstance._Ecommerce.createCommerceEventObject( + this.logPromotionEvent = ( + promotionType: valueof, + promotion: SDKPromotion | SDKPromotion[], + attrs?: SDKEventAttrs, + customFlags?: SDKEventCustomFlags, + eventOptions?: SDKEventOptions + ): void => { + const event = mpInstance._Ecommerce.createCommerceEventObject( customFlags ); @@ -269,7 +301,7 @@ export default function Events(mpInstance) { event.EventName += mpInstance._Ecommerce.getPromotionActionEventName( promotionType ); - event.EventCategory = mpInstance._Ecommerce.convertPromotionActionToEventType( + event.EventCategory = (mpInstance._Ecommerce.convertPromotionActionToEventType as Function)( promotionType ); event.PromotionAction = { @@ -279,43 +311,56 @@ export default function Events(mpInstance) { : [promotion], }; - self.logCommerceEvent(event, attrs, eventOptions); + this.logCommerceEvent(event, attrs, eventOptions); } }; - this.logImpressionEvent = function( - impression, - attrs, - customFlags, - options - ) { - var event = mpInstance._Ecommerce.createCommerceEventObject( + this.logImpressionEvent = ( + impression: SDKImpression | SDKImpression[] | SDKProductImpression | SDKProductImpression[], + attrs?: SDKEventAttrs, + customFlags?: SDKEventCustomFlags, + options?: SDKEventOptions + ): void => { + const event = mpInstance._Ecommerce.createCommerceEventObject( customFlags ); if (event) { event.EventName += 'Impression'; event.EventCategory = Types.CommerceEventType.ProductImpression; - if (!Array.isArray(impression)) { - impression = [impression]; - } + const rawList = Array.isArray(impression) + ? impression + : [impression]; event.ProductImpressions = []; - impression.forEach(function(impression) { - event.ProductImpressions.push({ - ProductImpressionList: impression.Name, - ProductList: Array.isArray(impression.Product) - ? impression.Product - : [impression.Product], - }); + rawList.forEach(function(item) { + if ('Name' in item) { + const imp = item as SDKImpression; + event.ProductImpressions.push({ + ProductImpressionList: imp.Name, + ProductList: Array.isArray(imp.Product) + ? imp.Product + : [imp.Product], + }); + } else { + const imp = item as SDKProductImpression; + event.ProductImpressions.push({ + ProductImpressionList: imp.ProductImpressionList, + ProductList: imp.ProductList || [], + }); + } }); - self.logCommerceEvent(event, attrs, options); + this.logCommerceEvent(event, attrs, options); } }; - this.logCommerceEvent = function(commerceEvent, attrs, options) { + this.logCommerceEvent = function( + commerceEvent: SDKEvent, + attrs?: SDKEventAttrs, + options?: SDKEventOptions + ): void { mpInstance.Logger.verbose( Messages.InformationMessages.StartingLogCommerceEvent ); @@ -346,7 +391,7 @@ export default function Events(mpInstance) { } if (attrs) { - commerceEvent.EventAttributes = attrs; + commerceEvent.EventAttributes = attrs as Record; } mpInstance._APIClient.sendEventToServer(commerceEvent, options); @@ -361,19 +406,20 @@ export default function Events(mpInstance) { }; this.addEventHandler = function( - domEvent, - selector, - eventName, - data, - eventType - ) { - var elements = [], - handler = function(e) { - var timeoutHandler = function() { - if (element.href) { - window.location.href = element.href; - } else if (element.submit) { - element.submit(); + domEvent: string, + selector: string | Node, + eventName: ((element: HTMLLinkElement | HTMLFormElement) => string) | string, + data: ((element: HTMLLinkElement | HTMLFormElement) => SDKEventAttrs) | SDKEventAttrs, + eventType: valueof + ): void { + let elements: ArrayLike | Element[] = [], + handler = (e: Event): void => { + const el = element as DOMHandlerElement; + const timeoutHandler = function(): void { + if (el.href) { + globalThis.location.href = el.href; + } else if (el.submit) { + el.submit(); } }; @@ -381,27 +427,27 @@ export default function Events(mpInstance) { 'DOM event triggered, handling event' ); - self.logEvent({ + this.logEvent({ messageType: Types.MessageType.PageEvent, name: typeof eventName === 'function' - ? eventName(element) + ? eventName(el as HTMLLinkElement) : eventName, - data: typeof data === 'function' ? data(element) : data, - eventType: eventType || Types.EventType.Other, + data: typeof data === 'function' ? data(el as HTMLLinkElement) : data, + eventType: (eventType || Types.EventType.Other) as number, }); // TODO: Handle middle-clicks and special keys (ctrl, alt, etc) if ( - (element.href && element.target !== '_blank') || - element.submit + (el.href && el.target !== '_blank') || + el.submit ) { // Give xmlhttprequest enough time to execute before navigating a link or submitting form if (e.preventDefault) { e.preventDefault(); } else { - e.returnValue = false; + (e as { returnValue: boolean }).returnValue = false; } setTimeout( @@ -410,8 +456,8 @@ export default function Events(mpInstance) { ); } }, - element, - i; + element: Element, + i: number; if (!selector) { mpInstance.Logger.error("Can't bind event, selector is required"); @@ -422,7 +468,7 @@ export default function Events(mpInstance) { if (typeof selector === 'string') { elements = document.querySelectorAll(selector); } else if (selector.nodeType) { - elements = [selector]; + elements = [selector as Element]; } if (elements.length) { @@ -436,16 +482,14 @@ export default function Events(mpInstance) { for (i = 0; i < elements.length; i++) { element = elements[i]; + const el = element as DOMHandlerElement; - if (element.addEventListener) { - // Modern browsers - element.addEventListener(domEvent, handler, false); - } else if (element.attachEvent) { - // IE < 9 - element.attachEvent('on' + domEvent, handler); + if (el.addEventListener) { + el.addEventListener(domEvent, handler, false); + } else if (el.attachEvent) { + el.attachEvent('on' + domEvent, handler); } else { - // All other browsers - element['on' + domEvent] = handler; + el['on' + domEvent] = handler; } } } else { diff --git a/src/sdkRuntimeModels.ts b/src/sdkRuntimeModels.ts index e31084228..e42560ebc 100644 --- a/src/sdkRuntimeModels.ts +++ b/src/sdkRuntimeModels.ts @@ -112,7 +112,7 @@ export interface SDKShoppingCart { } export interface SDKPromotionAction { - PromotionActionType: string; + PromotionActionType: string | valueof; PromotionList?: SDKPromotion[]; } diff --git a/src/serverModel.ts b/src/serverModel.ts index c21663c9a..4bda3a8d7 100644 --- a/src/serverModel.ts +++ b/src/serverModel.ts @@ -476,7 +476,7 @@ export default function ServerModel( }; } else if (event.PromotionAction) { dto.pm = { - an: event.PromotionAction.PromotionActionType, + an: event.PromotionAction.PromotionActionType as string, pl: event.PromotionAction.PromotionList.map(function( promotion ) { diff --git a/src/store.ts b/src/store.ts index 4bd1617e1..a050e52c4 100644 --- a/src/store.ts +++ b/src/store.ts @@ -96,6 +96,7 @@ export interface SDKConfig { workspaceToken?: string; requiredWebviewBridgeName?: string; isLoggingEnabled?: boolean; + timeout?: number; } function createSDKConfig(config: SDKInitConfig): SDKConfig { diff --git a/test/src/tests-event-logging.js b/test/src/tests-event-logging.ts similarity index 94% rename from test/src/tests-event-logging.js rename to test/src/tests-event-logging.ts index 69a47be79..3dbad0288 100644 --- a/test/src/tests-event-logging.js +++ b/test/src/tests-event-logging.ts @@ -9,6 +9,28 @@ import { MPConfig, MessageType, } from './config/constants'; +import { IMParticleInstanceManager } from '../../src/sdkRuntimeModels'; + +declare global { + interface Window { + mParticle: IMParticleInstanceManager; + } + namespace Should { + interface Assertion { + not: Assertion; + be: Assertion; + have: Assertion; + ok(): void; + } + } + function Should(obj: unknown): Should.Assertion; + // geomock.js custom property + interface Geolocation { + shouldFail: boolean; + } +} + +const mParticle = window.mParticle as IMParticleInstanceManager; const { findEventFromRequest, findBatch, getIdentityEvent, waitForCondition, fetchMockSuccess, hasIdentifyReturned } = Utils; @@ -209,7 +231,7 @@ describe('event logging', function() { it('should log an error', async () => { await waitForCondition(hasIdentifyReturned); - mParticle.logError('my error'); + (mParticle.logError as Function)('my error'); const errorEvent = findEventFromRequest(fetchMock.calls(), 'my error'); @@ -226,7 +248,7 @@ describe('event logging', function() { const error = new Error('my error'); error.stack = 'my stacktrace'; - mParticle.logError(error); + (mParticle.logError as Function)(error); const errorEvent = findEventFromRequest(fetchMock.calls(), 'my error'); @@ -248,7 +270,7 @@ describe('event logging', function() { const error = new Error('my error'); error.stack = 'my stacktrace'; - mParticle.logError(error, { location: 'my path', myData: 'my data' }); + (mParticle.logError as Function)(error, { location: 'my path', myData: 'my data' }); const errorEvent = findEventFromRequest(fetchMock.calls(), 'my error'); @@ -269,7 +291,7 @@ describe('event logging', function() { await waitForCondition(hasIdentifyReturned); const bond = sinon.spy(mParticle.getInstance().Logger, 'warning'); - mParticle.logError('my error', { + (mParticle.logError as Function)('my error', { invalid: ['my invalid attr'], valid: 10, }); @@ -442,7 +464,7 @@ describe('event logging', function() { it('should not log a PageView event if there are invalid attrs', async () => { await waitForCondition(hasIdentifyReturned); - mParticle.logPageView('test1', 'invalid', null); + (mParticle.logPageView as Function)('test1', 'invalid', null); const pageViewEvent = findEventFromRequest( fetchMock.calls(), 'test1' @@ -454,7 +476,7 @@ describe('event logging', function() { it('should not log an event that has an invalid customFlags', async () => { await waitForCondition(hasIdentifyReturned); - mParticle.logPageView('test', null, 'invalid'); + (mParticle.logPageView as Function)('test', null, 'invalid'); const pageViewEvent = findEventFromRequest( fetchMock.calls(), @@ -477,7 +499,7 @@ describe('event logging', function() { pageViewEvent.data.screen_name.should.equal('PageView'); fetchMock.resetHistory(); - mParticle.logPageView({ test: 'test' }); + (mParticle.logPageView as Function)({ test: 'test' }); fetchMock.calls().length.should.equal(1); const pageViewEvent2 = findEventFromRequest( fetchMock.calls(), @@ -486,7 +508,7 @@ describe('event logging', function() { pageViewEvent2.data.screen_name.should.equal('PageView'); fetchMock.resetHistory(); - mParticle.logPageView([1, 2, 3]); + (mParticle.logPageView as Function)([1, 2, 3]); fetchMock.calls().length.should.equal(1); const pageViewEvent3 = findEventFromRequest( fetchMock.calls(), @@ -510,7 +532,7 @@ describe('event logging', function() { await waitForCondition(hasIdentifyReturned); fetchMock.resetHistory(); - mParticle.logEvent(); + (mParticle.logEvent as Function)(); fetchMock.calls().should.have.lengthOf(0); }); @@ -520,7 +542,7 @@ describe('event logging', function() { fetchMock.resetHistory(); - mParticle.logEvent('test', 100); + (mParticle.logEvent as Function)('test', 100); fetchMock.calls().should.have.lengthOf(0); }); @@ -528,7 +550,7 @@ describe('event logging', function() { it('event attributes must be object', async () => { await waitForCondition(hasIdentifyReturned); - mParticle.logEvent('Test Event', null, 1); + (mParticle.logEvent as Function)('Test Event', null, 1); const testEvent = findEventFromRequest(fetchMock.calls(), 'Test Event'); @@ -626,7 +648,7 @@ describe('event logging', function() { ); expect(identityCalls.length).to.equal(1); - const data = JSON.parse(identityCalls[0][1].body); + const data = JSON.parse(String(identityCalls[0][1].body)); data.should.have.properties( 'client_sdk', 'environment', @@ -870,7 +892,7 @@ describe('event logging', function() { }) let currentPosition; - function callback(position) { + function callback(position?: GeolocationPosition) { currentPosition = position; } const clock = sinon.useFakeTimers(); @@ -938,7 +960,7 @@ describe('event logging', function() { window.mParticle.logEvent('Test Event'); - const batch = JSON.parse(fetchMock.lastOptions().body); + const batch = JSON.parse(String(fetchMock.lastOptions().body)); batch.application_info.should.have.property( 'application_name', @@ -960,7 +982,7 @@ describe('event logging', function() { ); }) - const batch = JSON.parse(fetchMock.lastOptions().body); + const batch = JSON.parse(String(fetchMock.lastOptions().body)); batch.events[0].data.should.have.property('is_first_run', true); await waitForCondition(() => { @@ -970,7 +992,7 @@ describe('event logging', function() { }) mParticle.init(apiKey, mParticle.config); - const batch2 = JSON.parse(fetchMock.lastOptions().body); + const batch2 = JSON.parse(String(fetchMock.lastOptions().body)); batch2.events[0].data.should.have.property('is_first_run', false); delete window.mParticle.config.flags; @@ -992,7 +1014,7 @@ describe('event logging', function() { }); - const batch = JSON.parse(fetchMock.lastOptions().body); + const batch = JSON.parse(String(fetchMock.lastOptions().body)); batch.events[0].data.should.have.property('launch_referral'); batch.events[0].data.launch_referral.should.startWith( 'http://localhost' @@ -1018,7 +1040,7 @@ describe('event logging', function() { window.mParticle.logEvent('Test Event'); - const batch = JSON.parse(fetchMock.lastOptions().body); + const batch = JSON.parse(String(fetchMock.lastOptions().body)); batch.application_info.should.have.property( 'application_name', 'another name' @@ -1047,7 +1069,7 @@ describe('event logging', function() { }); window.mParticle.logEvent('Test Event'); - const batch = JSON.parse(fetchMock.lastOptions().body); + const batch = JSON.parse(String(fetchMock.lastOptions().body)); batch.should.have.property('context'); batch.context.should.have.property('data_plan'); @@ -1074,7 +1096,7 @@ describe('event logging', function() { }); window.mParticle.logEvent('Test Event'); - const batch = JSON.parse(fetchMock.lastOptions().body); + const batch = JSON.parse(String(fetchMock.lastOptions().body)); batch.should.have.property('context'); batch.context.should.have.property('data_plan'); @@ -1101,7 +1123,7 @@ describe('event logging', function() { }); window.mParticle.logEvent('Test Event'); - const batch = JSON.parse(fetchMock.lastOptions().body); + const batch = JSON.parse(String(fetchMock.lastOptions().body)); batch.should.not.have.property('context'); @@ -1114,7 +1136,7 @@ describe('event logging', function() { mParticle.config.logLevel = 'verbose'; mParticle.config.logger = { - error: function(msg) { + error: function(msg: string) { if (!errorMessage) { errorMessage = msg; } @@ -1139,7 +1161,7 @@ describe('event logging', function() { 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); + const batch = JSON.parse(String(fetchMock.lastOptions().body)); batch.should.not.have.property('context'); delete window.mParticle.config.flags; }); @@ -1189,7 +1211,7 @@ describe('event logging', function() { window.mParticle.logEvent('Test Event'); - const batch = JSON.parse(fetchMock.lastOptions().body); + const batch = JSON.parse(String(fetchMock.lastOptions().body)); batch.should.have.property('consent_state'); batch.consent_state.should.have.properties(['gdpr', 'ccpa']); @@ -1272,7 +1294,7 @@ describe('event logging', function() { const customAttributes = { sale: true }; const customFlags = { 'Google.Category': 'travel' }; - mParticle.eCommerce.logProductAction( + (mParticle.eCommerce.logProductAction as Function)( mParticle.ProductActionType.Purchase, [product1, product2], customAttributes, @@ -1280,7 +1302,7 @@ describe('event logging', function() { transactionAttributes ); - const batch = JSON.parse(fetchMock.lastOptions().body); + const batch = JSON.parse(String(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); @@ -1301,7 +1323,7 @@ describe('event logging', function() { mParticle.getInstance()._Store.identityCallInFlight === false ); }); - const product1 = mParticle.eCommerce.createProduct( + const product1 = (mParticle.eCommerce.createProduct as Function)( 'iphone', 'iphoneSKU', 'string', @@ -1312,7 +1334,7 @@ describe('event logging', function() { 'string', 'coupon' ); - const product2 = mParticle.eCommerce.createProduct( + const product2 = (mParticle.eCommerce.createProduct as Function)( 'galaxy', 'galaxySKU', 'string', @@ -1333,7 +1355,7 @@ describe('event logging', function() { const customAttributes = { sale: true }; const customFlags = { 'Google.Category': 'travel' }; - mParticle.eCommerce.logProductAction( + (mParticle.eCommerce.logProductAction as Function)( mParticle.ProductActionType.Purchase, [product1, product2], customAttributes, @@ -1341,7 +1363,7 @@ describe('event logging', function() { transactionAttributes ); - const batch = JSON.parse(fetchMock.lastOptions().body); + const batch = JSON.parse(String(fetchMock.lastOptions().body)); ( batch.events[0].data.product_action.products[0].position === null ).should.equal(true);