diff --git a/src/ecommerce.js b/src/ecommerce.ts similarity index 69% rename from src/ecommerce.js rename to src/ecommerce.ts index 1650a168d..c635c088d 100644 --- a/src/ecommerce.js +++ b/src/ecommerce.ts @@ -1,19 +1,48 @@ import Types from './types'; import Constants from './constants'; import { extend } from './utils'; - -var Messages = Constants.Messages; - -export default function Ecommerce(mpInstance) { - var self = this; +import { IECommerce } from './ecommerce.interfaces'; +import { IMParticleWebSDKInstance } from './mp-instance'; +import { + ProductAction, + Product, + Promotion, + CommerceEvent, +} from '@mparticle/event-models'; +import { + SDKEventAttrs, + SDKEventOptions, + TransactionAttributes, +} from '@mparticle/web-sdk'; +import { + SDKEvent, + SDKEventCustomFlags, + SDKProduct, + SDKProductAction, + SDKProductImpression, + SDKPromotion, + SDKShoppingCart, +} from './sdkRuntimeModels'; +import { valueof } from './utils'; +import { ProductActionType, PromotionActionType } from './types'; + +const Messages = Constants.Messages; + +export default function Ecommerce( + this: IECommerce, + mpInstance: IMParticleWebSDKInstance +): void { + const self = this; + const _self = self as { [K in keyof IECommerce]: Function }; // https://go.mparticle.com/work/SQDSDKS-4801 - this.convertTransactionAttributesToProductAction = function( - transactionAttributes, - productAction - ) { + _self.convertTransactionAttributesToProductAction = function( + this: IECommerce, + transactionAttributes: TransactionAttributes & { Step?: number; Option?: string }, + productAction: ProductAction & SDKProductAction + ): void { if (transactionAttributes.hasOwnProperty('Id')) { - productAction.TransactionId = transactionAttributes.Id; + productAction.TransactionId = transactionAttributes.Id as string; } if (transactionAttributes.hasOwnProperty('Affiliation')) { productAction.Affiliation = transactionAttributes.Affiliation; @@ -23,19 +52,19 @@ export default function Ecommerce(mpInstance) { } if (transactionAttributes.hasOwnProperty('Revenue')) { productAction.TotalAmount = this.sanitizeAmount( - transactionAttributes.Revenue, + transactionAttributes.Revenue as number, 'Revenue' ); } if (transactionAttributes.hasOwnProperty('Shipping')) { productAction.ShippingAmount = this.sanitizeAmount( - transactionAttributes.Shipping, + transactionAttributes.Shipping as string, 'Shipping' ); } if (transactionAttributes.hasOwnProperty('Tax')) { productAction.TaxAmount = this.sanitizeAmount( - transactionAttributes.Tax, + transactionAttributes.Tax as number, 'Tax' ); } @@ -47,7 +76,9 @@ export default function Ecommerce(mpInstance) { } }; - this.getProductActionEventName = function(productActionType) { + this.getProductActionEventName = function( + productActionType: valueof + ): string { switch (productActionType) { case Types.ProductActionType.AddToCart: return 'AddToCart'; @@ -75,7 +106,9 @@ export default function Ecommerce(mpInstance) { } }; - this.getPromotionActionEventName = function(promotionActionType) { + this.getPromotionActionEventName = function( + promotionActionType: valueof + ): string { switch (promotionActionType) { case Types.PromotionActionType.PromotionClick: return 'PromotionClick'; @@ -86,7 +119,9 @@ export default function Ecommerce(mpInstance) { } }; - this.convertProductActionToEventType = function(productActionType) { + _self.convertProductActionToEventType = function( + productActionType: valueof + ): number | null { switch (productActionType) { case Types.ProductActionType.AddToCart: return Types.CommerceEventType.ProductAddToCart; @@ -123,7 +158,9 @@ export default function Ecommerce(mpInstance) { } }; - this.convertPromotionActionToEventType = function(promotionActionType) { + _self.convertPromotionActionToEventType = function( + promotionActionType: valueof + ): number | null { switch (promotionActionType) { case Types.PromotionActionType.PromotionClick: return Types.CommerceEventType.PromotionClick; @@ -139,14 +176,20 @@ export default function Ecommerce(mpInstance) { } }; - this.generateExpandedEcommerceName = function(eventName, plusOne) { + this.generateExpandedEcommerceName = function( + eventName: string, + plusOne: boolean + ): string { return ( 'eCommerce - ' + eventName + ' - ' + (plusOne ? 'Total' : 'Item') ); }; // https://go.mparticle.com/work/SQDSDKS-4801 - this.extractProductAttributes = function(attributes, product) { + _self.extractProductAttributes = function( + attributes: Record, + product: Product & SDKProduct + ): void { if (product.CouponCode) { attributes['Coupon Code'] = product.CouponCode; } @@ -178,15 +221,21 @@ export default function Ecommerce(mpInstance) { }; // https://go.mparticle.com/work/SQDSDKS-4801 - this.extractTransactionId = function(attributes, productAction) { + _self.extractTransactionId = function( + attributes: Record, + productAction: ProductAction & SDKProductAction + ): void { if (productAction.TransactionId) { attributes['Transaction Id'] = productAction.TransactionId; } }; // https://go.mparticle.com/work/SQDSDKS-4801 - this.extractActionAttributes = function(attributes, productAction) { - self.extractTransactionId(attributes, productAction); + _self.extractActionAttributes = function( + attributes: Record, + productAction: ProductAction & SDKProductAction + ): void { + (self.extractTransactionId as Function)(attributes, productAction); if (productAction.Affiliation) { attributes['Affiliation'] = productAction.Affiliation; @@ -218,7 +267,10 @@ export default function Ecommerce(mpInstance) { }; // https://go.mparticle.com/work/SQDSDKS-4801 - this.extractPromotionAttributes = function(attributes, promotion) { + _self.extractPromotionAttributes = function( + attributes: Record, + promotion: Promotion & SDKPromotion + ): void { if (promotion.Id) { attributes['Id'] = promotion.Id; } @@ -236,7 +288,10 @@ export default function Ecommerce(mpInstance) { } }; - this.buildProductList = function(event, product) { + _self.buildProductList = function( + event: SDKEvent, + product: (Product & SDKProduct) | (Product & SDKProduct)[] + ): (Product & SDKProduct)[] { if (product) { if (Array.isArray(product)) { return product; @@ -245,21 +300,21 @@ export default function Ecommerce(mpInstance) { return [product]; } - return event.ShoppingCart.ProductList; + return event.ShoppingCart.ProductList as (Product & SDKProduct)[]; }; this.createProduct = function( - name, - sku, - price, - quantity, - variant, - category, - brand, - position, - couponCode, - attributes - ) { + name: string, + sku: string | number, + price: string | number, + quantity?: string | number, + variant?: string, + category?: string, + brand?: string, + position?: number, + couponCode?: string, + attributes?: SDKEventAttrs + ): SDKProduct | null { attributes = mpInstance._Helpers.sanitizeAttributes(attributes, name); if (typeof name !== 'string') { @@ -298,34 +353,42 @@ export default function Ecommerce(mpInstance) { return { Name: name, - Sku: sku, - Price: price, - Quantity: quantity, + Sku: sku as string, + Price: price as number, + Quantity: quantity as number, Brand: brand, Variant: variant, Category: category, Position: position, CouponCode: couponCode, - TotalAmount: quantity * price, + TotalAmount: (quantity as number) * (price as number), Attributes: attributes, }; }; - this.createPromotion = function(id, creative, name, position) { + _self.createPromotion = function( + id: string | number, + creative?: string, + name?: string, + position?: number + ) { if (!mpInstance._Helpers.Validators.isStringOrNumber(id)) { mpInstance.Logger.error(Messages.ErrorMessages.PromotionIdRequired); return null; } return { - Id: id, + Id: id as string, Creative: creative, Name: name, Position: position, }; }; - this.createImpression = function(name, product) { + _self.createImpression = function( + name: string, + product: Product + ): { Name: string; Product: Product } | null { if (typeof name !== 'string') { mpInstance.Logger.error( 'Name is required when creating an impression.' @@ -347,13 +410,13 @@ export default function Ecommerce(mpInstance) { }; this.createTransactionAttributes = function( - id, - affiliation, - couponCode, - revenue, - shipping, - tax - ) { + id: string | number, + affiliation?: string, + couponCode?: string, + revenue?: string | number, + shipping?: string | number, + tax?: number + ): TransactionAttributes | null { if (!mpInstance._Helpers.Validators.isStringOrNumber(id)) { mpInstance.Logger.error( Messages.ErrorMessages.TransactionIdRequired @@ -365,20 +428,26 @@ export default function Ecommerce(mpInstance) { Id: id, Affiliation: affiliation, CouponCode: couponCode, - Revenue: revenue, - Shipping: shipping, + Revenue: revenue as number, + Shipping: shipping as string, Tax: tax, }; }; - this.expandProductImpression = function(commerceEvent) { - var appEvents = []; + _self.expandProductImpression = function( + commerceEvent: CommerceEvent & SDKEvent + ): SDKEvent[] { + const appEvents: SDKEvent[] = []; if (!commerceEvent.ProductImpressions) { return appEvents; } - commerceEvent.ProductImpressions.forEach(function(productImpression) { + commerceEvent.ProductImpressions.forEach(function( + productImpression: SDKProductImpression + ) { if (productImpression.ProductList) { - productImpression.ProductList.forEach(function(product) { + productImpression.ProductList.forEach(function( + product: SDKProduct + ) { let attributes = extend( false, {}, @@ -390,14 +459,19 @@ export default function Ecommerce(mpInstance) { product.Attributes[attribute]; } } - self.extractProductAttributes(attributes, product); + (self.extractProductAttributes as Function)( + attributes, + product + ); if (productImpression.ProductImpressionList) { attributes['Product Impression List'] = productImpression.ProductImpressionList; } - var appEvent = mpInstance._ServerModel.createEventObject({ + const appEvent = mpInstance._ServerModel.createEventObject({ messageType: Types.MessageType.PageEvent, - name: self.generateExpandedEcommerceName('Impression'), + name: (self.generateExpandedEcommerceName as Function)( + 'Impression' + ), data: attributes, eventType: Types.EventType.Transaction, }); @@ -409,30 +483,36 @@ export default function Ecommerce(mpInstance) { return appEvents; }; - this.expandCommerceEvent = function(event) { + _self.expandCommerceEvent = function( + event: CommerceEvent & SDKEvent + ): SDKEvent[] | null { if (!event) { return null; } - return self - .expandProductAction(event) - .concat(self.expandPromotionAction(event)) - .concat(self.expandProductImpression(event)); + return (self.expandProductAction as Function)(event) + .concat((self.expandPromotionAction as Function)(event)) + .concat((self.expandProductImpression as Function)(event)); }; - this.expandPromotionAction = function(commerceEvent) { - var appEvents = []; + _self.expandPromotionAction = function( + commerceEvent: CommerceEvent & SDKEvent + ): SDKEvent[] { + const appEvents: SDKEvent[] = []; if (!commerceEvent.PromotionAction) { return appEvents; } - var promotions = commerceEvent.PromotionAction.PromotionList; - promotions.forEach(function(promotion) { + const promotions = commerceEvent.PromotionAction.PromotionList; + promotions.forEach(function(promotion: SDKPromotion) { let attributes = extend(false, {}, commerceEvent.EventAttributes); - self.extractPromotionAttributes(attributes, promotion); + (self.extractPromotionAttributes as Function)( + attributes, + promotion + ); - var appEvent = mpInstance._ServerModel.createEventObject({ + const appEvent = mpInstance._ServerModel.createEventObject({ messageType: Types.MessageType.PageEvent, - name: self.generateExpandedEcommerceName( - Types.PromotionActionType.getExpansionName( + name: (self.generateExpandedEcommerceName as Function)( + (Types.PromotionActionType.getExpansionName as Function)( commerceEvent.PromotionAction.PromotionActionType ) ), @@ -444,12 +524,14 @@ export default function Ecommerce(mpInstance) { return appEvents; }; - this.expandProductAction = function(commerceEvent) { - var appEvents = []; + _self.expandProductAction = function( + commerceEvent: CommerceEvent & SDKEvent + ): SDKEvent[] { + const appEvents: SDKEvent[] = []; if (!commerceEvent.ProductAction) { return appEvents; } - var shouldExtractActionAttributes = false; + let shouldExtractActionAttributes = false; if ( commerceEvent.ProductAction.ProductActionType === Types.ProductActionType.Purchase || @@ -461,14 +543,14 @@ export default function Ecommerce(mpInstance) { .ProductList ? commerceEvent.ProductAction.ProductList.length : 0; - self.extractActionAttributes( + (self.extractActionAttributes as Function)( attributes, 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( @@ -484,34 +566,34 @@ 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) { + products.forEach(function(product: SDKProduct) { let attributes = extend( false, commerceEvent.EventAttributes, product.Attributes ); if (shouldExtractActionAttributes) { - self.extractActionAttributes( + (self.extractActionAttributes as Function)( attributes, commerceEvent.ProductAction ); } else { - self.extractTransactionId( + (self.extractTransactionId as Function)( attributes, commerceEvent.ProductAction ); } - self.extractProductAttributes(attributes, product); + (self.extractProductAttributes as Function)(attributes, product); - var productEvent = mpInstance._ServerModel.createEventObject({ + const productEvent = mpInstance._ServerModel.createEventObject({ messageType: Types.MessageType.PageEvent, - name: self.generateExpandedEcommerceName( + name: (self.generateExpandedEcommerceName as Function)( Types.ProductActionType.getExpansionName( commerceEvent.ProductAction.ProductActionType ) @@ -525,10 +607,13 @@ export default function Ecommerce(mpInstance) { return appEvents; }; - this.createCommerceEventObject = function(customFlags, options) { - var baseEvent; + this.createCommerceEventObject = function( + customFlags: SDKEventCustomFlags, + options?: SDKEventOptions + ): SDKEvent | null { + let baseEvent: SDKEvent; // https://go.mparticle.com/work/SQDSDKS-4801 - var { extend } = mpInstance._Helpers; + const { extend } = mpInstance._Helpers; mpInstance.Logger.verbose( Messages.InformationMessages.StartingLogCommerceEvent @@ -537,12 +622,13 @@ export default function Ecommerce(mpInstance) { if (mpInstance._Helpers.canLog()) { baseEvent = mpInstance._ServerModel.createEventObject({ messageType: Types.MessageType.Commerce, - sourceMessageId: options?.sourceMessageId, + sourceMessageId: (options as { sourceMessageId?: string }) + ?.sourceMessageId, }); baseEvent.EventName = 'eCommerce - '; baseEvent.CurrencyCode = mpInstance._Store.currencyCode; - baseEvent.ShoppingCart = []; + baseEvent.ShoppingCart = {} as SDKShoppingCart; baseEvent.CustomFlags = extend(baseEvent.CustomFlags, customFlags); return baseEvent; @@ -556,9 +642,12 @@ export default function Ecommerce(mpInstance) { }; // sanitizes any non number, non string value to 0 - this.sanitizeAmount = function(amount, category) { + this.sanitizeAmount = function( + amount: string | number, + category: string + ): number { if (!mpInstance._Helpers.Validators.isStringOrNumber(amount)) { - var message = [ + const message = [ category, 'must be of type number. A', typeof amount, diff --git a/test/src/tests-eCommerce.js b/test/src/tests-eCommerce.ts similarity index 87% rename from test/src/tests-eCommerce.js rename to test/src/tests-eCommerce.ts index 78d951b83..e6b20f32a 100644 --- a/test/src/tests-eCommerce.js +++ b/test/src/tests-eCommerce.ts @@ -2,12 +2,25 @@ import Utils from './config/utils'; import sinon from 'sinon'; import fetchMock from 'fetch-mock/esm/client'; import { urls, apiKey, MPConfig, testMPID, ProductActionType, PromotionActionType } from './config/constants'; + +declare function Should(value: unknown): Should.Assertion; +declare namespace Should { + interface Assertion { + be: Assertion; + not: Assertion; + ok(): void; + true: boolean; + } +} + const { waitForCondition, fetchMockSuccess, hasIdentifyReturned } = Utils; const forwarderDefaultConfiguration = Utils.forwarderDefaultConfiguration, findEventFromRequest = Utils.findEventFromRequest, MockForwarder = Utils.MockForwarder; +const mParticle = window.mParticle; + describe('eCommerce', function() { beforeEach(function() { mParticle._resetForTests(MPConfig); @@ -62,7 +75,7 @@ describe('eCommerce', function() { it('should log ecommerce event', async () => { await waitForCondition(hasIdentifyReturned); - const product = mParticle.eCommerce.createProduct( + const product = (mParticle.eCommerce.createProduct as Function)( 'iPhone', '12345', '400', @@ -83,7 +96,7 @@ describe('eCommerce', function() { 200 ); - mParticle.eCommerce.logPurchase(transactionAttributes, product); + (mParticle.eCommerce.logPurchase as Function)(transactionAttributes, product); const purchaseEvent = findEventFromRequest(fetchMock.calls(), 'purchase'); @@ -113,22 +126,21 @@ describe('eCommerce', function() { }); it('should not log an ecommerce event if there is a typo in the product action type', () => { - // 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( + const product = (mParticle.eCommerce.createProduct as Function)( '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 + (mParticle.eCommerce.logProductAction as Function)( + (ProductActionType as Record).Typo, [product] ); fetchMock.calls().length.should.equal(0); }); it('should log badly formed ecommerce event', async () => { - const product = mParticle.eCommerce.createProduct( + const product = (mParticle.eCommerce.createProduct as Function)( 'iPhone', '12345', Infinity, @@ -140,7 +152,7 @@ describe('eCommerce', function() { 'my-coupon-code', { customkey: 'customvalue' } ), - transactionAttributes = mParticle.eCommerce.createTransactionAttributes( + transactionAttributes = (mParticle.eCommerce.createTransactionAttributes as Function)( '12345', 'test-affiliation', 'coupon-code', @@ -150,7 +162,7 @@ describe('eCommerce', function() { ); await waitForCondition(hasIdentifyReturned); - mParticle.eCommerce.logPurchase(transactionAttributes, product); + (mParticle.eCommerce.logPurchase as Function)(transactionAttributes, product); const purchaseEvent = findEventFromRequest(fetchMock.calls(), 'purchase'); @@ -180,7 +192,7 @@ describe('eCommerce', function() { }); it('should log identical events for logPurchase and logProductAction with product action type of `purchase`', async () => { - const product = mParticle.eCommerce.createProduct( + const product = (mParticle.eCommerce.createProduct as Function)( 'iPhone', '12345', '400', @@ -202,12 +214,12 @@ describe('eCommerce', function() { ); await waitForCondition(hasIdentifyReturned); - mParticle.eCommerce.logPurchase(transactionAttributes, product); + (mParticle.eCommerce.logPurchase as Function)(transactionAttributes, product); const purchaseEvent1 = findEventFromRequest(fetchMock.calls(), 'purchase'); fetchMock.resetHistory(); - mParticle.eCommerce.logProductAction(mParticle.ProductActionType.Purchase, product, null, null, transactionAttributes) + mParticle.eCommerce.logProductAction(ProductActionType.Purchase, product, null, null, transactionAttributes) const purchaseEvent2 = findEventFromRequest(fetchMock.calls(), 'purchase'); const { product_action: productAction1 } = purchaseEvent1.data; @@ -244,7 +256,7 @@ describe('eCommerce', function() { ); await waitForCondition(hasIdentifyReturned); - mParticle.eCommerce.logPurchase(transactionAttributes, [ + (mParticle.eCommerce.logPurchase as Function)(transactionAttributes, [ product1, product2, ]); @@ -265,7 +277,7 @@ describe('eCommerce', function() { ); await waitForCondition(hasIdentifyReturned); - mParticle.eCommerce.logRefund(transactionAttributes, [ + (mParticle.eCommerce.logRefund as Function)(transactionAttributes, [ product1, product2, ]); @@ -303,8 +315,8 @@ describe('eCommerce', function() { ); await waitForCondition(hasIdentifyReturned); - mParticle.eCommerce.logPromotion( - mParticle.PromotionType.PromotionClick, + (mParticle.eCommerce.logPromotion as Function)( + PromotionActionType.PromotionClick, promotion ); @@ -336,8 +348,8 @@ describe('eCommerce', function() { ); await waitForCondition(hasIdentifyReturned); - mParticle.eCommerce.logPromotion( - mParticle.PromotionType.PromotionClick, + (mParticle.eCommerce.logPromotion as Function)( + PromotionActionType.PromotionClick, [promotion1, promotion2] ); @@ -367,8 +379,8 @@ describe('eCommerce', function() { ); await waitForCondition(hasIdentifyReturned); - mParticle.eCommerce.logPromotion( - mParticle.PromotionType.PromotionClick, + (mParticle.eCommerce.logPromotion as Function)( + PromotionActionType.PromotionClick, promotion, {}, {}, { shouldUploadEvent: false } @@ -380,7 +392,7 @@ describe('eCommerce', function() { it('should create impression', () => { const product = mParticle.eCommerce.createProduct('iPhone', '12345', 400), - impression = mParticle.eCommerce.createImpression( + impression = (mParticle.eCommerce.createImpression as Function)( 'impression-name', product ); @@ -392,13 +404,13 @@ describe('eCommerce', function() { it('should log impression event', async () => { const product = mParticle.eCommerce.createProduct('iPhone', '12345', 400), - impression = mParticle.eCommerce.createImpression( + impression = (mParticle.eCommerce.createImpression as Function)( 'impression-name', product ); await waitForCondition(hasIdentifyReturned); - mParticle.eCommerce.logImpression(impression); + (mParticle.eCommerce.logImpression as Function)(impression); const impressionEvent = findEventFromRequest(fetchMock.calls(), 'impression'); Should(impressionEvent).be.ok(); @@ -412,12 +424,12 @@ describe('eCommerce', function() { it('should allow an impression to bypass server upload', async () => { await waitForCondition(hasIdentifyReturned); const product = mParticle.eCommerce.createProduct('iPhone', '12345', 400), - impression = mParticle.eCommerce.createImpression( + impression = (mParticle.eCommerce.createImpression as Function)( 'impression-name', product ); - mParticle.eCommerce.logImpression(impression, null, null, { shouldUploadEvent: false }); + (mParticle.eCommerce.logImpression as Function)(impression, null, null, { shouldUploadEvent: false }); const impressionEvent = findEventFromRequest(fetchMock.calls(), 'impression'); @@ -427,7 +439,7 @@ describe('eCommerce', function() { it('should log multiple impression when an array of impressions is passed', async () => { await waitForCondition(hasIdentifyReturned); const product = mParticle.eCommerce.createProduct('iPhone', '12345', 400), - impression = mParticle.eCommerce.createImpression( + impression = (mParticle.eCommerce.createImpression as Function)( 'impression-name1', product ), @@ -436,12 +448,12 @@ describe('eCommerce', function() { '23456', 200 ), - impression2 = mParticle.eCommerce.createImpression( + impression2 = (mParticle.eCommerce.createImpression as Function)( 'impression-name2', product2 ); - mParticle.eCommerce.logImpression([impression, impression2]); + (mParticle.eCommerce.logImpression as Function)([impression, impression2]); const impressionEvent = findEventFromRequest(fetchMock.calls(), 'impression'); @@ -478,7 +490,7 @@ describe('eCommerce', function() { 200 ); - mParticle.eCommerce.logRefund(transactionAttributes, product); + (mParticle.eCommerce.logRefund as Function)(transactionAttributes, product); const refundEvent = findEventFromRequest(fetchMock.calls(), 'refund'); @@ -507,7 +519,7 @@ describe('eCommerce', function() { it('should log identical events for logRefund and logProductAction with a product action of `refund`', async () => { await waitForCondition(hasIdentifyReturned); - const product = mParticle.eCommerce.createProduct( + const product = (mParticle.eCommerce.createProduct as Function)( 'iPhone', '12345', '400', @@ -528,13 +540,13 @@ describe('eCommerce', function() { 200 ); - mParticle.eCommerce.logRefund(transactionAttributes, product); + (mParticle.eCommerce.logRefund as Function)(transactionAttributes, product); const refundEvent1 = findEventFromRequest(fetchMock.calls(), 'refund'); fetchMock.resetHistory(); - mParticle.eCommerce.logProductAction(mParticle.ProductActionType.Refund, product, null, null, transactionAttributes) + mParticle.eCommerce.logProductAction(ProductActionType.Refund, product, null, null, transactionAttributes) const refundEvent2 = findEventFromRequest(fetchMock.calls(), 'refund'); @@ -561,7 +573,7 @@ describe('eCommerce', function() { it('should allow a product action to bypass server upload', async () => { await waitForCondition(hasIdentifyReturned); - const product = mParticle.eCommerce.createProduct( + const product = (mParticle.eCommerce.createProduct as Function)( 'iPhone', '12345', '400', @@ -583,7 +595,7 @@ describe('eCommerce', function() { ); mParticle.eCommerce.logProductAction( - mParticle.ProductActionType.Purchase, + ProductActionType.Purchase, product, null, null, @@ -600,7 +612,7 @@ describe('eCommerce', function() { await waitForCondition(hasIdentifyReturned); const bond = sinon.spy(mParticle.getInstance().Logger, 'warning'); - mParticle.eCommerce.logCheckout(1, 'Visa'); + (mParticle.eCommerce.logCheckout as Function)(1, 'Visa'); const checkoutEvent = findEventFromRequest(fetchMock.calls(), 'checkout'); @@ -624,7 +636,7 @@ describe('eCommerce', function() { 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 as Function)(ProductActionType.Checkout, [product1, product2], null, null, {Step: 4, Option: 'Visa'}); const checkoutEvent = findEventFromRequest(fetchMock.calls(), 'checkout'); @@ -644,7 +656,7 @@ describe('eCommerce', function() { await waitForCondition(hasIdentifyReturned); const product = mParticle.eCommerce.createProduct('iPhone', '12345', 400); - mParticle.eCommerce.logProductAction( + (mParticle.eCommerce.logProductAction as Function)( ProductActionType.CheckoutOption, product, { color: 'blue' } @@ -669,7 +681,7 @@ describe('eCommerce', function() { await waitForCondition(hasIdentifyReturned); const product = mParticle.eCommerce.createProduct('iPhone', '12345', 400); - mParticle.eCommerce.logProductAction( + (mParticle.eCommerce.logProductAction as Function)( ProductActionType.ViewDetail, product ); @@ -685,11 +697,11 @@ describe('eCommerce', function() { }); it('should fail to create product if name not a string', () => { - const product = mParticle.eCommerce.createProduct(null); - const product2 = mParticle.eCommerce.createProduct(undefined); - const product3 = mParticle.eCommerce.createProduct(['product']); - const product4 = mParticle.eCommerce.createProduct(123); - const product5 = mParticle.eCommerce.createProduct({ key: 'value' }); + const product = (mParticle.eCommerce.createProduct as Function)(null); + const product2 = (mParticle.eCommerce.createProduct as Function)(undefined); + const product3 = (mParticle.eCommerce.createProduct as Function)(['product']); + const product4 = (mParticle.eCommerce.createProduct as Function)(123); + const product5 = (mParticle.eCommerce.createProduct as Function)({ key: 'value' }); Should(product).not.be.ok(); Should(product2).not.be.ok(); @@ -699,12 +711,12 @@ describe('eCommerce', function() { }); it('should fail to create product if sku not a string or a number', () => { - const product = mParticle.eCommerce.createProduct('test', null); - const product2 = mParticle.eCommerce.createProduct('test', { + const product = (mParticle.eCommerce.createProduct as Function)('test', null); + const product2 = (mParticle.eCommerce.createProduct as Function)('test', { key: 'value', }); - const product3 = mParticle.eCommerce.createProduct('test', []); - const product4 = mParticle.eCommerce.createProduct('test', undefined); + const product3 = (mParticle.eCommerce.createProduct as Function)('test', []); + const product4 = (mParticle.eCommerce.createProduct as Function)('test', undefined); Should(product).not.be.ok(); Should(product2).not.be.ok(); @@ -713,10 +725,10 @@ describe('eCommerce', function() { }); it('should fail to create product if price not a string or number', () => { - const product = mParticle.eCommerce.createProduct('test', 'sku', null); - const product2 = mParticle.eCommerce.createProduct('test', 'sku', null); - const product3 = mParticle.eCommerce.createProduct('test', 'sku', null); - const product4 = mParticle.eCommerce.createProduct('test', 'sku', null); + const product = (mParticle.eCommerce.createProduct as Function)('test', 'sku', null); + const product2 = (mParticle.eCommerce.createProduct as Function)('test', 'sku', null); + const product3 = (mParticle.eCommerce.createProduct as Function)('test', 'sku', null); + const product4 = (mParticle.eCommerce.createProduct as Function)('test', 'sku', null); Should(product).not.be.ok(); Should(product2).not.be.ok(); @@ -725,13 +737,13 @@ describe('eCommerce', function() { }); it('should fail to create impression if name is not specified', () => { - const impression = mParticle.eCommerce.createImpression(null); + const impression = (mParticle.eCommerce.createImpression as Function)(null); Should(impression).not.be.ok(); }); it('should fail to create impression if product is not specified', () => { - const impression = mParticle.eCommerce.createImpression('name', null); + const impression = (mParticle.eCommerce.createImpression as Function)('name', null); Should(impression).not.be.ok(); }); @@ -756,7 +768,7 @@ describe('eCommerce', function() { 200 ); - mParticle.eCommerce.logPurchase(transactionAttributes, product); + (mParticle.eCommerce.logPurchase as Function)(transactionAttributes, product); const purchaseEvent = findEventFromRequest(fetchMock.calls(), 'purchase'); purchaseEvent.data.product_action.products[0].should.not.have.property('position'); @@ -777,10 +789,10 @@ describe('eCommerce', function() { ); }); mParticle.eCommerce.setCurrencyCode('foo-currency'); - const productAttributes = {}; + const productAttributes: Record = {}; productAttributes['foo-attribute-key'] = 'foo-product-attribute-value'; - const eventAttributes = {}; + const eventAttributes: Record = {}; eventAttributes['foo-event-attribute-key'] = 'foo-event-attribute-value'; @@ -805,7 +817,7 @@ describe('eCommerce', function() { 10, 8 ); - mParticle.eCommerce.logPurchase( + (mParticle.eCommerce.logPurchase as Function)( transactionAttributes, product, false, @@ -814,7 +826,7 @@ describe('eCommerce', function() { window.MockForwarder1.instance.receivedEvent.should.have.property( 'ProductAction' ); - const expandedEvents = mParticle.eCommerce.expandCommerceEvent( + const expandedEvents = (mParticle.eCommerce.expandCommerceEvent as Function)( window.MockForwarder1.instance.receivedEvent ); expandedEvents.should.be.instanceof(Array).and.have.lengthOf(2); @@ -826,7 +838,7 @@ describe('eCommerce', function() { ); plusOneEvent.should.have.property( 'EventCategory', - mParticle.EventType.Transaction + (mParticle.EventType as Record).Transaction ); let attributes = plusOneEvent.EventAttributes; attributes.should.have.property('Transaction Id', 'foo-transaction-id'); @@ -849,7 +861,7 @@ describe('eCommerce', function() { ); productEvent.should.have.property( 'EventCategory', - mParticle.EventType.Transaction + (mParticle.EventType as Record).Transaction ); attributes = productEvent.EventAttributes; attributes.should.not.have.property('Affiliation'); @@ -885,10 +897,10 @@ describe('eCommerce', function() { mParticle.getInstance()._Store.identityCallInFlight === false ); }); - const productAttributes = {}; + const productAttributes: Record = {}; productAttributes['foo-attribute-key'] = 'foo-product-attribute-value'; - const eventAttributes = {}; + const eventAttributes: Record = {}; eventAttributes['foo-event-attribute-key'] = 'foo-event-attribute-value'; @@ -913,7 +925,7 @@ describe('eCommerce', function() { 10, 8 ); - mParticle.eCommerce.logRefund( + (mParticle.eCommerce.logRefund as Function)( transactionAttributes, product, false, @@ -922,7 +934,7 @@ describe('eCommerce', function() { window.MockForwarder1.instance.receivedEvent.should.have.property( 'ProductAction' ); - const expandedEvents = mParticle.eCommerce.expandCommerceEvent( + const expandedEvents = (mParticle.eCommerce.expandCommerceEvent as Function)( window.MockForwarder1.instance.receivedEvent ); expandedEvents.should.be.instanceof(Array).and.have.lengthOf(2); @@ -955,10 +967,10 @@ describe('eCommerce', function() { mParticle.getInstance()._Store.identityCallInFlight === false ); }); - const productAttributes = {}; + const productAttributes: Record = {}; productAttributes['foo-attribute-key'] = 'foo-product-attribute-value'; - const eventAttributes = {}; + const eventAttributes: Record = {}; eventAttributes['foo-event-attribute-key'] = 'foo-event-attribute-value'; @@ -975,15 +987,15 @@ describe('eCommerce', function() { productAttributes ); - mParticle.eCommerce.logProductAction( - mParticle.ProductActionType.RemoveFromWishlist, + (mParticle.eCommerce.logProductAction as Function)( + ProductActionType.RemoveFromWishlist, product, eventAttributes ); window.MockForwarder1.instance.receivedEvent.should.have.property( 'ProductAction' ); - const expandedEvents = mParticle.eCommerce.expandCommerceEvent( + const expandedEvents = (mParticle.eCommerce.expandCommerceEvent as Function)( window.MockForwarder1.instance.receivedEvent ); expandedEvents.should.be.instanceof(Array).and.have.lengthOf(1); @@ -995,7 +1007,7 @@ describe('eCommerce', function() { ); productEvent.should.have.property( 'EventCategory', - mParticle.EventType.Transaction + (mParticle.EventType as Record).Transaction ); const attributes = productEvent.EventAttributes; @@ -1027,13 +1039,13 @@ describe('eCommerce', function() { ); }); - const eventAttributes = {}; + const eventAttributes: Record = {}; eventAttributes['foo-event-attribute-key'] = 'foo-event-attribute-value'; eventAttributes['Checkout Step'] = 'foo-step'; eventAttributes['Checkout Options'] = 'foo-options'; - const productAttributes = {}; + const productAttributes: Record = {}; productAttributes['foo-attribute-key'] = 'foo-product-attribute-value'; const product = mParticle.eCommerce.createProduct( @@ -1051,13 +1063,13 @@ describe('eCommerce', function() { mParticle.eCommerce.Cart.add(product, true); - mParticle.eCommerce.logProductAction(mParticle.ProductActionType.Checkout, [product], eventAttributes); + (mParticle.eCommerce.logProductAction as Function)(ProductActionType.Checkout, [product], eventAttributes); window.MockForwarder1.instance.receivedEvent.should.have.property( 'ProductAction' ); - const expandedEvents = mParticle.eCommerce.expandCommerceEvent( + const expandedEvents = (mParticle.eCommerce.expandCommerceEvent as Function)( window.MockForwarder1.instance.receivedEvent ); expandedEvents.should.be.instanceof(Array).and.have.lengthOf(1); @@ -1069,7 +1081,7 @@ describe('eCommerce', function() { ); productEvent.should.have.property( 'EventCategory', - mParticle.EventType.Transaction + (mParticle.EventType as Record).Transaction ); const attributes = productEvent.EventAttributes; @@ -1103,7 +1115,7 @@ describe('eCommerce', function() { ); }); - const eventAttributes = {}; + const eventAttributes: Record = {}; eventAttributes['foo-event-attribute-key'] = 'foo-event-attribute-value'; @@ -1114,15 +1126,15 @@ describe('eCommerce', function() { 5 ); - mParticle.eCommerce.logPromotion( - mParticle.PromotionType.PromotionClick, + (mParticle.eCommerce.logPromotion as Function)( + PromotionActionType.PromotionClick, promotion, eventAttributes ); window.MockForwarder1.instance.receivedEvent.should.have.property( 'PromotionAction' ); - const expandedEvents = mParticle.eCommerce.expandCommerceEvent( + const expandedEvents = (mParticle.eCommerce.expandCommerceEvent as Function)( window.MockForwarder1.instance.receivedEvent ); @@ -1135,7 +1147,7 @@ describe('eCommerce', function() { ); promotionEvent.should.have.property( 'EventCategory', - mParticle.EventType.Transaction + (mParticle.EventType as Record).Transaction ); const attributes = promotionEvent.EventAttributes; @@ -1150,7 +1162,7 @@ describe('eCommerce', function() { }); it('expand null commerce event', () => { - const expandedEvents = mParticle.eCommerce.expandCommerceEvent(null); + const expandedEvents = (mParticle.eCommerce.expandCommerceEvent as Function)(null); (expandedEvents == null).should.be.true; }); @@ -1168,10 +1180,10 @@ describe('eCommerce', function() { ); }); - const productAttributes = {}; + const productAttributes: Record = {}; productAttributes['foo-attribute-key'] = 'foo-product-attribute-value'; - const eventAttributes = {}; + const eventAttributes: Record = {}; eventAttributes['foo-event-attribute-key'] = 'foo-event-attribute-value'; @@ -1188,16 +1200,16 @@ describe('eCommerce', function() { productAttributes ); - const impression = mParticle.eCommerce.createImpression( + const impression = (mParticle.eCommerce.createImpression as Function)( 'suggested products list', product ); - mParticle.eCommerce.logImpression(impression, eventAttributes); + (mParticle.eCommerce.logImpression as Function)(impression, eventAttributes); window.MockForwarder1.instance.receivedEvent.should.have.property( 'ProductImpressions' ); - const expandedEvents = mParticle.eCommerce.expandCommerceEvent( + const expandedEvents = (mParticle.eCommerce.expandCommerceEvent as Function)( window.MockForwarder1.instance.receivedEvent ); @@ -1210,7 +1222,7 @@ describe('eCommerce', function() { ); impressionEvent.should.have.property( 'EventCategory', - mParticle.EventType.Transaction + (mParticle.EventType as Record).Transaction ); const attributes = impressionEvent.EventAttributes; @@ -1238,7 +1250,7 @@ describe('eCommerce', function() { it('should add customFlags to logCheckout events', async () => { await waitForCondition(hasIdentifyReturned); - mParticle.eCommerce.logCheckout(1, {}, {}, { interactionEvent: true }); + (mParticle.eCommerce.logCheckout as Function)(1, {}, {}, { interactionEvent: true }); const checkoutEvent = findEventFromRequest(fetchMock.calls(), 'checkout'); checkoutEvent.data.custom_flags.interactionEvent.should.equal(true); @@ -1247,8 +1259,8 @@ describe('eCommerce', function() { it('should add customFlags to logProductAction events', async () => { await waitForCondition(hasIdentifyReturned); const product = mParticle.eCommerce.createProduct('iPhone', 'sku1', 499); - mParticle.eCommerce.logProductAction( - mParticle.ProductActionType.Unknown, + (mParticle.eCommerce.logProductAction as Function)( + ProductActionType.Unknown, product, { price: 5 }, { interactionEvent: true } @@ -1287,8 +1299,8 @@ describe('eCommerce', function() { 'name' ); - mParticle.eCommerce.logPromotion( - mParticle.PromotionType.Unknown, + (mParticle.eCommerce.logPromotion as Function)( + PromotionActionType.Unknown, promotion, { shipping: 5 }, { interactionEvent: true } @@ -1303,11 +1315,11 @@ describe('eCommerce', function() { it('should add customFlags to logImpression events', async () => { await waitForCondition(hasIdentifyReturned); const product = mParticle.eCommerce.createProduct('iPhone', 'sku1', 499); - const impression = mParticle.eCommerce.createImpression( + const impression = (mParticle.eCommerce.createImpression as Function)( 'iphoneImpressionName', product ); - mParticle.eCommerce.logImpression( + (mParticle.eCommerce.logImpression as Function)( impression, { shipping: 5 }, { interactionEvent: true } @@ -1392,8 +1404,8 @@ describe('eCommerce', function() { it('should be empty when transactionAttributes is empty', () => { const mparticle = mParticle.getInstance() - const productAction = {} - mparticle._Ecommerce.convertTransactionAttributesToProductAction({}, productAction) + const productAction: Record = {} + ;(mparticle._Ecommerce.convertTransactionAttributesToProductAction as Function)({}, productAction) Object.keys(productAction).length.should.equal(0); }); @@ -1417,8 +1429,8 @@ describe('eCommerce', function() { Tax: "tax" }; - const productAction = {}; - mparticle._Ecommerce.convertTransactionAttributesToProductAction(transactionAttributes, productAction) + const productAction: Record = {}; + ;(mparticle._Ecommerce.convertTransactionAttributesToProductAction as Function)(transactionAttributes, productAction) productAction.TransactionId.should.equal("id") productAction.Affiliation.should.equal("affiliation") productAction.CouponCode.should.equal("couponCode") @@ -1431,7 +1443,7 @@ describe('eCommerce', function() { it('should allow a user to pass in a source_message_id to a commerce event', async () => { await waitForCondition(hasIdentifyReturned); - const product = mParticle.eCommerce.createProduct( + const product = (mParticle.eCommerce.createProduct as Function)( 'iPhone', '12345', '400', @@ -1453,8 +1465,8 @@ describe('eCommerce', function() { 200 ); - mParticle.eCommerce.logProductAction( - mParticle.ProductActionType.Purchase, + (mParticle.eCommerce.logProductAction as Function)( + ProductActionType.Purchase, product, null, null, @@ -1468,4 +1480,4 @@ describe('eCommerce', function() { purchaseEvent1.data.source_message_id.should.equal('foo-bar'); }); }); -}); \ No newline at end of file +});