From 5767cdc7b380adfb650c689413a33f5ab1f0ecd1 Mon Sep 17 00:00:00 2001 From: Jaissica Date: Tue, 25 Nov 2025 13:56:10 -0500 Subject: [PATCH 1/9] extend product attribute mapping to AddToCart and Checkout event --- src/FacebookEventForwarder.js | 18 ++-- test/tests.js | 153 +++++++++++++++++++++++++++++++++- 2 files changed, 164 insertions(+), 7 deletions(-) diff --git a/src/FacebookEventForwarder.js b/src/FacebookEventForwarder.js index 7a4bd60..a39a7aa 100755 --- a/src/FacebookEventForwarder.js +++ b/src/FacebookEventForwarder.js @@ -216,6 +216,16 @@ var name = 'Facebook', } else if (event.ProductAction.ProductActionType == mParticle.ProductActionType.AddToCart){ eventName = ADD_TO_CART_EVENT_NAME; + if (event.ProductAction.TransactionId) { + params['order_id'] = event.ProductAction.TransactionId; + } + + // Build contents array for Purchase events + var contents = buildProductContents(event.ProductAction.ProductList); + if (contents && contents.length > 0) { + params['contents'] = contents; + } + } else{ eventName = VIEW_CONTENT_EVENT_NAME; @@ -244,11 +254,9 @@ var name = 'Facebook', } // Build contents array for Purchase events - if (event.ProductAction.ProductActionType == mParticle.ProductActionType.Purchase) { - var contents = buildProductContents(event.ProductAction.ProductList); - if (contents && contents.length > 0) { - params['contents'] = contents; - } + var contents = buildProductContents(event.ProductAction.ProductList); + if (contents && contents.length > 0) { + params['contents'] = contents; } } else if (event.ProductAction.ProductActionType == mParticle.ProductActionType.RemoveFromCart) { diff --git a/test/tests.js b/test/tests.js index b0e0763..b130031 100755 --- a/test/tests.js +++ b/test/tests.js @@ -371,6 +371,8 @@ describe('Facebook Forwarder', function () { window.fbqObj.params.should.have.property('eventAttr1', 'value1'); window.fbqObj.params.should.have.property('eventAttr2', 'value2'); window.fbqObj.eventData.should.have.property('eventID', SOURCE_MESSAGE_ID); + window.fbqObj.params.should.have.property('order_id', 123); + window.fbqObj.params.should.have.property('contents'); done(); }); @@ -439,7 +441,8 @@ describe('Facebook Forwarder', function () { window.fbqObj.params.should.have.property('checkout_step', 1); window.fbqObj.params.should.have.property('num_items', 9); window.fbqObj.eventData.should.have.property('eventID', SOURCE_MESSAGE_ID); - + window.fbqObj.params.should.have.property('order_id', 123); + window.fbqObj.params.should.have.property('contents'); done(); }); @@ -481,7 +484,8 @@ describe('Facebook Forwarder', function () { window.fbqObj.params.should.have.property('content_name', 'eCommerce - AddToCart'); window.fbqObj.params.should.have.property('content_ids', ['12345']); window.fbqObj.eventData.should.have.property('eventID', SOURCE_MESSAGE_ID); - window.fbqObj.params.should.not.have.property('contents'); + window.fbqObj.params.should.have.property('contents'); + window.fbqObj.params.should.have.property('order_id', 123); done(); }); @@ -540,6 +544,8 @@ describe('Facebook Forwarder', function () { window.fbqObj.params.should.have.property('content_name', 'eCommerce - AddToCart'); window.fbqObj.params.should.have.property('content_ids', ['12345', '888', '666']); window.fbqObj.eventData.should.have.property('eventID', SOURCE_MESSAGE_ID); + window.fbqObj.params.should.have.property('order_id', 123); + window.fbqObj.params.should.have.property('contents'); done(); }); @@ -581,6 +587,8 @@ describe('Facebook Forwarder', function () { window.fbqObj.params.should.have.property('content_name', 'eCommerce - RemoveFromCart'); window.fbqObj.params.should.have.property('content_ids', ['12345']); window.fbqObj.eventData.should.have.property('eventID', SOURCE_MESSAGE_ID); + window.fbqObj.params.should.not.have.property('order_id'); + window.fbqObj.params.should.not.have.property('contents'); done(); }); @@ -621,6 +629,8 @@ describe('Facebook Forwarder', function () { window.fbqObj.params.should.have.property('content_name', 'eCommerce - RemoveFromCart'); window.fbqObj.params.should.have.property('content_ids', ['12345']); window.fbqObj.eventData.should.have.property('eventID', SOURCE_MESSAGE_ID); + window.fbqObj.params.should.not.have.property('order_id'); + window.fbqObj.params.should.not.have.property('contents'); done(); }); @@ -685,6 +695,8 @@ describe('Facebook Forwarder', function () { window.fbqObj.params.should.have.property('eventAttr1', 'value1'); window.fbqObj.params.should.have.property('eventAttr2', 'value2'); window.fbqObj.eventData.should.have.property('eventID', SOURCE_MESSAGE_ID); + window.fbqObj.params.should.not.have.property('order_id'); + window.fbqObj.params.should.not.have.property('contents'); done(); }); @@ -732,6 +744,8 @@ describe('Facebook Forwarder', function () { window.fbqObj.params.should.have.property('eventAttr1', 'value1'); window.fbqObj.params.should.have.property('eventAttr2', 'value2'); window.fbqObj.eventData.should.have.property('eventID', SOURCE_MESSAGE_ID); + window.fbqObj.params.should.not.have.property('order_id'); + window.fbqObj.params.should.not.have.property('contents'); done(); }); @@ -778,6 +792,8 @@ describe('Facebook Forwarder', function () { window.fbqObj.params.should.have.property('eventAttr1', 'value1'); window.fbqObj.params.should.have.property('eventAttr2', 'value2'); window.fbqObj.eventData.should.have.property('eventID', SOURCE_MESSAGE_ID); + window.fbqObj.params.should.not.have.property('order_id'); + window.fbqObj.params.should.not.have.property('contents'); done(); }); @@ -824,6 +840,8 @@ describe('Facebook Forwarder', function () { window.fbqObj.params.should.have.property('eventAttr1', 'value1'); window.fbqObj.params.should.have.property('eventAttr2', 'value2'); window.fbqObj.eventData.should.have.property('eventID', SOURCE_MESSAGE_ID); + window.fbqObj.params.should.not.have.property('order_id'); + window.fbqObj.params.should.not.have.property('contents'); done(); }); @@ -924,5 +942,136 @@ describe('Facebook Forwarder', function () { done(); }); + + it('should build contents array with mapped attributes for AddToCart events', function (done) { + // Initialize with product attribute mapping + mParticle.forwarder.init({ + pixelCode: 'test-pixel-code', + "productAttributeMapping":"[{"jsmap":"3373707","map":"Name","maptype":"ProductAttributeSelector.Name","value":"custom_name"},{"jsmap":"93997959","map":"Brand","maptype":"ProductAttributeSelector.Name","value":"custom_brand"},{"jsmap":"106934601","map":"Price","maptype":"ProductAttributeSelector.Name","value":"custom_price"},{"jsmap":"50511102","map":"Category","maptype":"ProductAttributeSelector.Name","value":"custom_category"},{"jsmap":"94842723","map":"category","maptype":"ProductAttributeSelector.Name","value":"custom_attribute_category"}]" + }, reportService.cb, true); + + mParticle.forwarder.process({ + EventName: 'eCommerce - AddToCart', + EventDataType: MessageType.Commerce, + ProductAction: { + ProductActionType: ProductActionType.AddToCart, + ProductList: [ + { + Sku: 'sku-12', + Name: 'iPhone', + Brand: 'Apple', + Category: 'electronics', + Variant: 'blue', + Price: 1000.99, + Quantity: 1, + Attributes: { + category: 'phones' + } + }, + { + Sku: 'sku-34', + Name: 'Watch', + Brand: 'Samsung', + Price: 450.99, + Quantity: 2 + } + ], + TransactionId: 123 + }, + CurrencyCode: 'USD', + SourceMessageId: SOURCE_MESSAGE_ID, + }); + + checkBasicProperties('track'); + window.fbqObj.should.have.property('eventName', 'AddToCart'); + window.fbqObj.params.should.have.property('contents'); + window.fbqObj.params.contents.length.should.equal(2); + window.fbqObj.params.should.have.property('order_id', 123); + + var firstProduct = window.fbqObj.params.contents[0]; + // Standard Facebook fields + firstProduct.should.have.property('id', 'sku-12'); + firstProduct.should.have.property('name', 'iPhone'); + firstProduct.should.have.property('brand', 'Apple'); + firstProduct.should.have.property('item_price', 1000.99); + firstProduct.should.have.property('quantity', 1); + + // Mapped standard fields + firstProduct.should.have.property('custom_name', 'iPhone'); + firstProduct.should.have.property('custom_brand', 'Apple'); + firstProduct.should.have.property('custom_price', 1000.99); + firstProduct.should.have.property('custom_category', 'electronics'); + + // Mapped custom attribute + firstProduct.should.have.property('custom_attribute_category', 'phones'); + + done(); + }); + + it('should build contents array with mapped attributes for Checkout events', function (done) { + // Initialize with product attribute mapping + mParticle.forwarder.init({ + pixelCode: 'test-pixel-code', + "productAttributeMapping":"[{"jsmap":"3373707","map":"Name","maptype":"ProductAttributeSelector.Name","value":"custom_name"},{"jsmap":"93997959","map":"Brand","maptype":"ProductAttributeSelector.Name","value":"custom_brand"},{"jsmap":"106934601","map":"Price","maptype":"ProductAttributeSelector.Name","value":"custom_price"},{"jsmap":"50511102","map":"Category","maptype":"ProductAttributeSelector.Name","value":"custom_category"},{"jsmap":"94842723","map":"category","maptype":"ProductAttributeSelector.Name","value":"custom_attribute_category"}]" + }, reportService.cb, true); + + mParticle.forwarder.process({ + EventName: 'eCommerce - Checkout', + EventDataType: MessageType.Commerce, + ProductAction: { + ProductActionType: ProductActionType.Checkout, + ProductList: [ + { + Sku: 'sku-12', + Name: 'iPhone', + Brand: 'Apple', + Category: 'electronics', + Variant: 'blue', + Price: 1000.99, + Quantity: 1, + Attributes: { + category: 'phones' + } + }, + { + Sku: 'sku-34', + Name: 'Watch', + Brand: 'Samsung', + Price: 450.99, + Quantity: 2 + } + ], + TransactionId: 123, + TotalAmount: 1902.97 + }, + CurrencyCode: 'USD', + SourceMessageId: SOURCE_MESSAGE_ID, + }); + + checkBasicProperties('track'); + window.fbqObj.should.have.property('eventName', 'InitiateCheckout'); + window.fbqObj.params.should.have.property('contents'); + window.fbqObj.params.contents.length.should.equal(2); + window.fbqObj.params.should.have.property('order_id', 123); + + var firstProduct = window.fbqObj.params.contents[0]; + // Standard Facebook fields + firstProduct.should.have.property('id', 'sku-12'); + firstProduct.should.have.property('name', 'iPhone'); + firstProduct.should.have.property('brand', 'Apple'); + firstProduct.should.have.property('item_price', 1000.99); + firstProduct.should.have.property('quantity', 1); + + // Mapped standard fields + firstProduct.should.have.property('custom_name', 'iPhone'); + firstProduct.should.have.property('custom_brand', 'Apple'); + firstProduct.should.have.property('custom_price', 1000.99); + firstProduct.should.have.property('custom_category', 'electronics'); + + // Mapped custom attribute + firstProduct.should.have.property('custom_attribute_category', 'phones'); + + done(); + }); }); }); From c4160d3b993ed807919fcabd51d15b9f793a4449 Mon Sep 17 00:00:00 2001 From: Jaissica Date: Tue, 25 Nov 2025 16:22:36 -0500 Subject: [PATCH 2/9] update comment for buildProductContents --- src/FacebookEventForwarder.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/FacebookEventForwarder.js b/src/FacebookEventForwarder.js index a39a7aa..6f440b4 100755 --- a/src/FacebookEventForwarder.js +++ b/src/FacebookEventForwarder.js @@ -220,7 +220,7 @@ var name = 'Facebook', params['order_id'] = event.ProductAction.TransactionId; } - // Build contents array for Purchase events + // Build contents array for AddToCart events var contents = buildProductContents(event.ProductAction.ProductList); if (contents && contents.length > 0) { params['contents'] = contents; @@ -253,7 +253,7 @@ var name = 'Facebook', params['order_id'] = event.ProductAction.TransactionId; } - // Build contents array for Purchase events + // Build contents array for Purchase/Checkout events var contents = buildProductContents(event.ProductAction.ProductList); if (contents && contents.length > 0) { params['contents'] = contents; From 91eec1a057950639c260ae3e4bffb81141415b3a Mon Sep 17 00:00:00 2001 From: Jaissica Date: Wed, 26 Nov 2025 09:44:02 -0500 Subject: [PATCH 3/9] declare contents variable at function scope to avoid redeclaration --- src/FacebookEventForwarder.js | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/FacebookEventForwarder.js b/src/FacebookEventForwarder.js index 6f440b4..064508b 100755 --- a/src/FacebookEventForwarder.js +++ b/src/FacebookEventForwarder.js @@ -168,6 +168,7 @@ var name = 'Facebook', var eventName, totalValue, + contents, params = cloneEventAttributes(event), eventID = createEventId(event); params['currency'] = event.CurrencyCode || 'USD'; @@ -216,15 +217,15 @@ var name = 'Facebook', } else if (event.ProductAction.ProductActionType == mParticle.ProductActionType.AddToCart){ eventName = ADD_TO_CART_EVENT_NAME; - if (event.ProductAction.TransactionId) { - params['order_id'] = event.ProductAction.TransactionId; - } - - // Build contents array for AddToCart events - var contents = buildProductContents(event.ProductAction.ProductList); - if (contents && contents.length > 0) { - params['contents'] = contents; - } + if (event.ProductAction.TransactionId) { + params['order_id'] = event.ProductAction.TransactionId; + } + + // Build contents array for AddToCart events + contents = buildProductContents(event.ProductAction.ProductList); + if (contents && contents.length > 0) { + params['contents'] = contents; + } } else{ @@ -254,7 +255,7 @@ var name = 'Facebook', } // Build contents array for Purchase/Checkout events - var contents = buildProductContents(event.ProductAction.ProductList); + contents = buildProductContents(event.ProductAction.ProductList); if (contents && contents.length > 0) { params['contents'] = contents; } From 908bcc0f728ca2773c965251b5179cd1fef9e487 Mon Sep 17 00:00:00 2001 From: Jaissica Date: Wed, 26 Nov 2025 09:56:25 -0500 Subject: [PATCH 4/9] fix indentation in AddToCart if block --- src/FacebookEventForwarder.js | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/FacebookEventForwarder.js b/src/FacebookEventForwarder.js index 064508b..fde1fc5 100755 --- a/src/FacebookEventForwarder.js +++ b/src/FacebookEventForwarder.js @@ -217,16 +217,15 @@ var name = 'Facebook', } else if (event.ProductAction.ProductActionType == mParticle.ProductActionType.AddToCart){ eventName = ADD_TO_CART_EVENT_NAME; - if (event.ProductAction.TransactionId) { - params['order_id'] = event.ProductAction.TransactionId; - } - - // Build contents array for AddToCart events - contents = buildProductContents(event.ProductAction.ProductList); - if (contents && contents.length > 0) { - params['contents'] = contents; - } + if (event.ProductAction.TransactionId) { + params['order_id'] = event.ProductAction.TransactionId; + } + // Build contents array for AddToCart events + contents = buildProductContents(event.ProductAction.ProductList); + if (contents && contents.length > 0) { + params['contents'] = contents; + } } else{ eventName = VIEW_CONTENT_EVENT_NAME; From b8d502d76e538c4aa6bfed438ad2e9c504158ba9 Mon Sep 17 00:00:00 2001 From: Jaissica Date: Tue, 9 Dec 2025 17:58:12 -0500 Subject: [PATCH 5/9] add sendProductNamesAsContents setting to use product names array for content_name --- src/FacebookEventForwarder.js | 65 +++++++- test/tests.js | 294 +++++++++++++++++++++++++++++++++- 2 files changed, 347 insertions(+), 12 deletions(-) diff --git a/src/FacebookEventForwarder.js b/src/FacebookEventForwarder.js index fde1fc5..46ebe40 100755 --- a/src/FacebookEventForwarder.js +++ b/src/FacebookEventForwarder.js @@ -165,12 +165,13 @@ var name = 'Facebook', event.ProductAction.ProductList && event.ProductAction.ProductActionType && SupportedCommerceTypes.indexOf(event.ProductAction.ProductActionType) > -1) { - var eventName, totalValue, contents, params = cloneEventAttributes(event), - eventID = createEventId(event); + eventID = createEventId(event), + sendProductNamesAsContents = settings.sendProductNamesasContents || false; + params['currency'] = event.CurrencyCode || 'USD'; if (event.EventName) { @@ -217,10 +218,14 @@ var name = 'Facebook', } else if (event.ProductAction.ProductActionType == mParticle.ProductActionType.AddToCart){ eventName = ADD_TO_CART_EVENT_NAME; - if (event.ProductAction.TransactionId) { - params['order_id'] = event.ProductAction.TransactionId; + + // Set product names as content_name if enabled + if (sendProductNamesAsContents) { + setProductNamesAsContentName(params, event.ProductAction.ProductList); } + setOrderId(params, event.ProductAction.TransactionId); + // Build contents array for AddToCart events contents = buildProductContents(event.ProductAction.ProductList); if (contents && contents.length > 0) { @@ -248,11 +253,14 @@ var name = 'Facebook', return sum; }, 0); params['num_items'] = num_items; - - if (event.ProductAction.TransactionId) { - params['order_id'] = event.ProductAction.TransactionId; - } + // Set product names as content_name if enabled + if (sendProductNamesAsContents) { + setProductNamesAsContentName(params, event.ProductAction.ProductList); + } + + setOrderId(params, event.ProductAction.TransactionId); + // Build contents array for Purchase/Checkout events contents = buildProductContents(event.ProductAction.ProductList); if (contents && contents.length > 0) { @@ -279,6 +287,19 @@ var name = 'Facebook', params['value'] = totalValue; + // Set product names as content_name if enabled + if (sendProductNamesAsContents) { + setProductNamesAsContentName(params, event.ProductAction.ProductList); + } + + setOrderId(params, event.ProductAction.TransactionId); + + // Build contents array for RemoveFromCart events + contents = buildProductContents(event.ProductAction.ProductList); + if (contents && contents.length > 0) { + params['contents'] = contents; + } + fbq('trackCustom', eventName || 'customEvent', params, eventID); return true; } @@ -415,6 +436,34 @@ var name = 'Facebook', } } + /** + * Sets product names as content_name parameter + * @param {Object} params - The parameters object to modify + * @param {Array} productList - Array of products + */ + function setProductNamesAsContentName(params, productList) { + if (productList) { + params['content_name'] = productList + .filter(function(product) { + return product && product.Name; + }) + .map(function(product) { + return product.Name; + }); + } + } + + /** + * Sets order_id parameter if transaction ID exists + * @param {Object} params - The parameters object to modify + * @param {String} transactionId - The transaction ID + */ + function setOrderId(params, transactionId) { + if (transactionId) { + params['order_id'] = transactionId; + } + } + this.init = initForwarder; this.process = processEvent; }; diff --git a/test/tests.js b/test/tests.js index b130031..719deca 100755 --- a/test/tests.js +++ b/test/tests.js @@ -587,8 +587,8 @@ describe('Facebook Forwarder', function () { window.fbqObj.params.should.have.property('content_name', 'eCommerce - RemoveFromCart'); window.fbqObj.params.should.have.property('content_ids', ['12345']); window.fbqObj.eventData.should.have.property('eventID', SOURCE_MESSAGE_ID); - window.fbqObj.params.should.not.have.property('order_id'); - window.fbqObj.params.should.not.have.property('contents'); + window.fbqObj.params.should.have.property('order_id', 123); + window.fbqObj.params.should.have.property('contents'); done(); }); @@ -629,8 +629,8 @@ describe('Facebook Forwarder', function () { window.fbqObj.params.should.have.property('content_name', 'eCommerce - RemoveFromCart'); window.fbqObj.params.should.have.property('content_ids', ['12345']); window.fbqObj.eventData.should.have.property('eventID', SOURCE_MESSAGE_ID); - window.fbqObj.params.should.not.have.property('order_id'); - window.fbqObj.params.should.not.have.property('contents'); + window.fbqObj.params.should.have.property('order_id', 123); + window.fbqObj.params.should.have.property('contents'); done(); }); @@ -1073,5 +1073,291 @@ describe('Facebook Forwarder', function () { done(); }); + + it('should build contents array with mapped attributes for RemoveFromCart events', function (done) { + // Initialize with product attribute mapping + mParticle.forwarder.init({ + pixelCode: 'test-pixel-code', + "productAttributeMapping":"[{"jsmap":"3373707","map":"Name","maptype":"ProductAttributeSelector.Name","value":"custom_name"},{"jsmap":"93997959","map":"Brand","maptype":"ProductAttributeSelector.Name","value":"custom_brand"},{"jsmap":"106934601","map":"Price","maptype":"ProductAttributeSelector.Name","value":"custom_price"},{"jsmap":"50511102","map":"Category","maptype":"ProductAttributeSelector.Name","value":"custom_category"},{"jsmap":"94842723","map":"category","maptype":"ProductAttributeSelector.Name","value":"custom_attribute_category"}]" + }, reportService.cb, true); + + mParticle.forwarder.process({ + EventName: 'eCommerce - RemoveFromCart', + EventCategory: CommerceEventType.ProductRemoveFromCart, + EventDataType: MessageType.Commerce, + ProductAction: { + ProductActionType: ProductActionType.RemoveFromCart, + ProductList: [ + { + Sku: '12345', + Name: 'iPhone 6', + Category: 'Phones', + Brand: 'iPhone', + Variant: '6', + Price: 200, + CouponCode: null, + Quantity: 1, + TotalAmount: 200, + Attributes: { + category: 'phones' + } + } + ], + TransactionId: 123, + Affiliation: 'my-affiliation', + TaxAmount: 40, + ShippingAmount: 10, + TotalAmount: 205 + }, + CurrencyCode: 'USD', + SourceMessageId: SOURCE_MESSAGE_ID, + }); + + checkBasicProperties('trackCustom'); + window.fbqObj.should.have.property('eventName', 'RemoveFromCart'); + window.fbqObj.params.should.have.property('contents'); + window.fbqObj.params.contents.length.should.equal(1); + window.fbqObj.params.should.have.property('order_id', 123); + + var firstProduct = window.fbqObj.params.contents[0]; + // Standard Facebook fields + firstProduct.should.have.property('id', '12345'); + firstProduct.should.have.property('name', 'iPhone 6'); + firstProduct.should.have.property('brand', 'iPhone'); + firstProduct.should.have.property('item_price', 200); + firstProduct.should.have.property('quantity', 1); + + // Mapped standard fields + firstProduct.should.have.property('custom_name', 'iPhone 6'); + firstProduct.should.have.property('custom_brand', 'iPhone'); + firstProduct.should.have.property('custom_price', 200); + firstProduct.should.have.property('custom_category', 'Phones'); + + // Mapped custom attribute + firstProduct.should.have.property('custom_attribute_category', 'phones'); + + done(); + }); + + it('should log Purchase event with product names as contents', function (done) { + mParticle.forwarder.init({ + pixelCode: 'test-pixel-code', + sendProductNamesasContents: true + }, reportService.cb, true); + + mParticle.forwarder.process({ + EventName: 'eCommerce - Purchase', + EventDataType: MessageType.Commerce, + ProductAction: { + ProductActionType: ProductActionType.Purchase, + ProductList: [ + { + Sku: 'sku-12', + Name: 'iPhone', + Brand: 'Apple', + Category: 'electronics', + Variant: 'blue', + Price: 1000.99, + Quantity: 1, + Attributes: { + category: 'phones' + } + }, + { + Sku: 'sku-no-name', + // Name missing to test filter + Brand: 'Generic', + Price: 99.99, + Quantity: 1 + }, + { + Sku: 'sku-34', + Name: 'Watch', + Brand: 'Samsung', + Price: 450.99, + Quantity: 2 + } + ], + TransactionId: 'txn-1234', + TotalAmount: 1551.97 + }, + CurrencyCode: 'USD', + SourceMessageId: SOURCE_MESSAGE_ID, + }); + + checkBasicProperties('track'); + window.fbqObj.should.have.property('eventName', 'Purchase'); + window.fbqObj.params.should.have.property('contents'); + window.fbqObj.params.contents.length.should.equal(3); + window.fbqObj.params.contents[0].should.have.property('name', 'iPhone'); + window.fbqObj.params.contents[2].should.have.property('name', 'Watch'); + // content_name should only include products with names (filters out product without Name) + window.fbqObj.params.should.have.property('content_name', ['iPhone', 'Watch']); + window.fbqObj.params.should.have.property('order_id', 'txn-1234'); + window.fbqObj.params.should.have.property('value', 1551.97); + window.fbqObj.params.should.have.property('currency', 'USD'); + window.fbqObj.params.should.have.property('num_items', 4); + window.fbqObj.eventData.should.have.property('eventID', SOURCE_MESSAGE_ID); + + done(); + }); + + it('should log AddToCart event with product names as contents', function (done) { + mParticle.forwarder.init({ + pixelCode: 'test-pixel-code', + sendProductNamesasContents: true + }, reportService.cb, true); + + mParticle.forwarder.process({ + EventName: 'eCommerce - AddToCart', + EventCategory: CommerceEventType.ProductAddToCart, + EventDataType: MessageType.Commerce, + ProductAction: { + ProductActionType: ProductActionType.AddToCart, + ProductList: [ + { + Sku: '12345', + Name: 'iPhone 6', + Category: 'Phones', + Brand: 'iPhone', + Variant: '6', + Price: 400, + CouponCode: null, + Quantity: 1 + }, + { + Sku: '1234', + Name: 'iPhone 11', + Category: 'Phones', + Brand: 'iPhone', + Variant: '6', + Price: 500, + CouponCode: null, + Quantity: 2 + } + ], + TransactionId: 123, + Affiliation: 'my-affiliation', + TaxAmount: 40, + ShippingAmount: 10 + }, + CurrencyCode: 'USD', + SourceMessageId: SOURCE_MESSAGE_ID, + + }); + + checkBasicProperties('track'); + window.fbqObj.should.have.property('eventName', 'AddToCart'); + window.fbqObj.params.should.have.property('content_name', ['iPhone 6', 'iPhone 11']); + window.fbqObj.params.should.have.property('content_ids', ['12345', '1234']); + window.fbqObj.eventData.should.have.property('eventID', SOURCE_MESSAGE_ID); + done(); + }); + + it('should log RemoveFromCart event with product names as content_name', function (done) { + mParticle.forwarder.init({ + pixelCode: 'test-pixel-code', + sendProductNamesasContents: true + }, reportService.cb, true); + + mParticle.forwarder.process({ + EventName: 'eCommerce - RemoveFromCart', + EventCategory: CommerceEventType.ProductRemoveFromCart, + EventDataType: MessageType.Commerce, + ProductAction: { + ProductActionType: ProductActionType.RemoveFromCart, + ProductList: [ + { + Sku: '12345', + Name: 'iPhone 6', + Category: 'Phones', + Brand: 'iPhone', + Variant: '6', + Price: 200, + CouponCode: null, + Quantity: 1, + TotalAmount: 200 + } + ], + TransactionId: 123, + Affiliation: 'my-affiliation', + TaxAmount: 40, + ShippingAmount: 10, + TotalAmount: 205 + }, + CurrencyCode: 'USD', + SourceMessageId: SOURCE_MESSAGE_ID, + }); + + checkBasicProperties('trackCustom'); + window.fbqObj.should.have.property('eventName', 'RemoveFromCart'); + window.fbqObj.params.should.have.property('content_name', ['iPhone 6']); + window.fbqObj.params.should.have.property('content_ids', ['12345']); + window.fbqObj.eventData.should.have.property('eventID', SOURCE_MESSAGE_ID); + done(); + }); + + it('should log Checkout event with product names as contents', function (done) { + mParticle.forwarder.init({ + pixelCode: 'test-pixel-code', + sendProductNamesasContents: true + }, reportService.cb, true); + + mParticle.forwarder.process({ + EventName: 'eCommerce - Checkout', + EventCategory: CommerceEventType.ProductCheckout, + EventDataType: MessageType.Commerce, + ProductAction: { + ProductActionType: ProductActionType.Checkout, + ProductList: [ + { + Sku: 'sku-12', + Name: 'iPhone', + Brand: 'Apple', + Category: 'electronics', + Variant: 'blue', + Price: 1000.99, + Quantity: 1 + }, + { + Sku: 'sku-no-name', + // Name missing to test filter + Brand: 'Generic', + Price: 75.50, + Quantity: 1 + }, + { + Sku: 'sku-34', + Name: 'Watch', + Brand: 'Samsung', + Price: 450.99, + Quantity: 2 + } + ], + TransactionId: 'txn-5678', + TotalAmount: 1978.47, + CheckoutStep: 1 + }, + CurrencyCode: 'USD', + SourceMessageId: SOURCE_MESSAGE_ID, + }); + + checkBasicProperties('track'); + window.fbqObj.should.have.property('eventName', 'InitiateCheckout'); + window.fbqObj.params.should.have.property('contents'); + window.fbqObj.params.contents.length.should.equal(3); + window.fbqObj.params.contents[0].should.have.property('name', 'iPhone'); + window.fbqObj.params.contents[2].should.have.property('name', 'Watch'); + // content_name should only include products with names (filters out product without Name) + window.fbqObj.params.should.have.property('content_name', ['iPhone', 'Watch']); + window.fbqObj.params.should.have.property('order_id', 'txn-5678'); + window.fbqObj.params.should.have.property('value', 1978.47); + window.fbqObj.params.should.have.property('currency', 'USD'); + window.fbqObj.params.should.have.property('num_items', 4); + window.fbqObj.params.should.have.property('checkout_step', 1); + window.fbqObj.eventData.should.have.property('eventID', SOURCE_MESSAGE_ID); + + done(); + }); }); }); From f16445fbf3a5ebea1af5b4c29a5dca21850e65ad Mon Sep 17 00:00:00 2001 From: Jaissica Date: Wed, 10 Dec 2025 16:36:20 -0500 Subject: [PATCH 6/9] removed helper setOrderId and updated return type for setProductNamesAsContentName --- src/FacebookEventForwarder.js | 62 +++++++++++++++++++---------------- 1 file changed, 34 insertions(+), 28 deletions(-) diff --git a/src/FacebookEventForwarder.js b/src/FacebookEventForwarder.js index 46ebe40..f83c3ed 100755 --- a/src/FacebookEventForwarder.js +++ b/src/FacebookEventForwarder.js @@ -221,10 +221,15 @@ var name = 'Facebook', // Set product names as content_name if enabled if (sendProductNamesAsContents) { - setProductNamesAsContentName(params, event.ProductAction.ProductList); + var productNames = buildProductNames(event.ProductAction.ProductList); + if (productNames && productNames.length > 0) { + params['content_name'] = productNames; + } } - setOrderId(params, event.ProductAction.TransactionId); + if (event.ProductAction.TransactionId) { + params['order_id'] = event.ProductAction.TransactionId; + } // Build contents array for AddToCart events contents = buildProductContents(event.ProductAction.ProductList); @@ -256,10 +261,15 @@ var name = 'Facebook', // Set product names as content_name if enabled if (sendProductNamesAsContents) { - setProductNamesAsContentName(params, event.ProductAction.ProductList); + var productNames = buildProductNames(event.ProductAction.ProductList); + if (productNames && productNames.length > 0) { + params['content_name'] = productNames; + } } - setOrderId(params, event.ProductAction.TransactionId); + if (event.ProductAction.TransactionId) { + params['order_id'] = event.ProductAction.TransactionId; + } // Build contents array for Purchase/Checkout events contents = buildProductContents(event.ProductAction.ProductList); @@ -289,10 +299,15 @@ var name = 'Facebook', // Set product names as content_name if enabled if (sendProductNamesAsContents) { - setProductNamesAsContentName(params, event.ProductAction.ProductList); + var productNames = buildProductNames(event.ProductAction.ProductList); + if (productNames && productNames.length > 0) { + params['content_name'] = productNames; + } } - setOrderId(params, event.ProductAction.TransactionId); + if (event.ProductAction.TransactionId) { + params['order_id'] = event.ProductAction.TransactionId; + } // Build contents array for RemoveFromCart events contents = buildProductContents(event.ProductAction.ProductList); @@ -437,31 +452,22 @@ var name = 'Facebook', } /** - * Sets product names as content_name parameter - * @param {Object} params - The parameters object to modify + * Builds array of product names from product list * @param {Array} productList - Array of products + * @returns {Array} Array of product names */ - function setProductNamesAsContentName(params, productList) { - if (productList) { - params['content_name'] = productList - .filter(function(product) { - return product && product.Name; - }) - .map(function(product) { - return product.Name; - }); - } - } - - /** - * Sets order_id parameter if transaction ID exists - * @param {Object} params - The parameters object to modify - * @param {String} transactionId - The transaction ID - */ - function setOrderId(params, transactionId) { - if (transactionId) { - params['order_id'] = transactionId; + function buildProductNames(productList) { + if (!productList || productList.length === 0) { + return []; } + + return productList + .filter(function(product) { + return product && product.Name; + }) + .map(function(product) { + return product.Name; + }); } this.init = initForwarder; From 3730e9567e277a2578ed834ea80e192d6b87c6c7 Mon Sep 17 00:00:00 2001 From: Jaissica Date: Wed, 10 Dec 2025 16:45:39 -0500 Subject: [PATCH 7/9] declare productNames at function scope in logCommerceEvent --- src/FacebookEventForwarder.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/FacebookEventForwarder.js b/src/FacebookEventForwarder.js index f83c3ed..a3838f8 100755 --- a/src/FacebookEventForwarder.js +++ b/src/FacebookEventForwarder.js @@ -168,6 +168,7 @@ var name = 'Facebook', var eventName, totalValue, contents, + productNames, params = cloneEventAttributes(event), eventID = createEventId(event), sendProductNamesAsContents = settings.sendProductNamesasContents || false; @@ -221,7 +222,7 @@ var name = 'Facebook', // Set product names as content_name if enabled if (sendProductNamesAsContents) { - var productNames = buildProductNames(event.ProductAction.ProductList); + productNames = buildProductNames(event.ProductAction.ProductList); if (productNames && productNames.length > 0) { params['content_name'] = productNames; } @@ -261,7 +262,7 @@ var name = 'Facebook', // Set product names as content_name if enabled if (sendProductNamesAsContents) { - var productNames = buildProductNames(event.ProductAction.ProductList); + productNames = buildProductNames(event.ProductAction.ProductList); if (productNames && productNames.length > 0) { params['content_name'] = productNames; } @@ -299,7 +300,7 @@ var name = 'Facebook', // Set product names as content_name if enabled if (sendProductNamesAsContents) { - var productNames = buildProductNames(event.ProductAction.ProductList); + productNames = buildProductNames(event.ProductAction.ProductList); if (productNames && productNames.length > 0) { params['content_name'] = productNames; } From 3770ec6cf54a89915331f7c1709ce53df2c2baa6 Mon Sep 17 00:00:00 2001 From: Jaissica Date: Thu, 11 Dec 2025 10:06:44 -0500 Subject: [PATCH 8/9] extend order_id and content_name as product_names to all commerce events --- src/FacebookEventForwarder.js | 50 +++++-------------- test/tests.js | 92 +++++++++++++++++++++++++++++++++-- 2 files changed, 101 insertions(+), 41 deletions(-) diff --git a/src/FacebookEventForwarder.js b/src/FacebookEventForwarder.js index a3838f8..a4a2811 100755 --- a/src/FacebookEventForwarder.js +++ b/src/FacebookEventForwarder.js @@ -168,7 +168,6 @@ var name = 'Facebook', var eventName, totalValue, contents, - productNames, params = cloneEventAttributes(event), eventID = createEventId(event), sendProductNamesAsContents = settings.sendProductNamesasContents || false; @@ -190,6 +189,19 @@ var name = 'Facebook', params['content_ids'] = productSkus; } + // Override content_name with product names array if setting enabled + if (sendProductNamesAsContents) { + var productNames = buildProductNames(event.ProductAction.ProductList); + if (productNames && productNames.length > 0) { + params['content_name'] = productNames; + } + } + + // Set order_id if TransactionId exists + if (event.ProductAction.TransactionId) { + params['order_id'] = event.ProductAction.TransactionId; + } + if (event.ProductAction.ProductActionType == mParticle.ProductActionType.AddToWishlist || event.ProductAction.ProductActionType == mParticle.ProductActionType.Checkout) { var eventCategory = getEventCategoryString(event); @@ -219,18 +231,6 @@ var name = 'Facebook', } else if (event.ProductAction.ProductActionType == mParticle.ProductActionType.AddToCart){ eventName = ADD_TO_CART_EVENT_NAME; - - // Set product names as content_name if enabled - if (sendProductNamesAsContents) { - productNames = buildProductNames(event.ProductAction.ProductList); - if (productNames && productNames.length > 0) { - params['content_name'] = productNames; - } - } - - if (event.ProductAction.TransactionId) { - params['order_id'] = event.ProductAction.TransactionId; - } // Build contents array for AddToCart events contents = buildProductContents(event.ProductAction.ProductList); @@ -259,18 +259,6 @@ var name = 'Facebook', return sum; }, 0); params['num_items'] = num_items; - - // Set product names as content_name if enabled - if (sendProductNamesAsContents) { - productNames = buildProductNames(event.ProductAction.ProductList); - if (productNames && productNames.length > 0) { - params['content_name'] = productNames; - } - } - - if (event.ProductAction.TransactionId) { - params['order_id'] = event.ProductAction.TransactionId; - } // Build contents array for Purchase/Checkout events contents = buildProductContents(event.ProductAction.ProductList); @@ -297,18 +285,6 @@ var name = 'Facebook', } params['value'] = totalValue; - - // Set product names as content_name if enabled - if (sendProductNamesAsContents) { - productNames = buildProductNames(event.ProductAction.ProductList); - if (productNames && productNames.length > 0) { - params['content_name'] = productNames; - } - } - - if (event.ProductAction.TransactionId) { - params['order_id'] = event.ProductAction.TransactionId; - } // Build contents array for RemoveFromCart events contents = buildProductContents(event.ProductAction.ProductList); diff --git a/test/tests.js b/test/tests.js index 719deca..43a72d0 100755 --- a/test/tests.js +++ b/test/tests.js @@ -695,7 +695,7 @@ describe('Facebook Forwarder', function () { window.fbqObj.params.should.have.property('eventAttr1', 'value1'); window.fbqObj.params.should.have.property('eventAttr2', 'value2'); window.fbqObj.eventData.should.have.property('eventID', SOURCE_MESSAGE_ID); - window.fbqObj.params.should.not.have.property('order_id'); + window.fbqObj.params.should.have.property('order_id', 123); window.fbqObj.params.should.not.have.property('contents'); done(); @@ -744,7 +744,7 @@ describe('Facebook Forwarder', function () { window.fbqObj.params.should.have.property('eventAttr1', 'value1'); window.fbqObj.params.should.have.property('eventAttr2', 'value2'); window.fbqObj.eventData.should.have.property('eventID', SOURCE_MESSAGE_ID); - window.fbqObj.params.should.not.have.property('order_id'); + window.fbqObj.params.should.have.property('order_id', 123); window.fbqObj.params.should.not.have.property('contents'); done(); @@ -792,7 +792,7 @@ describe('Facebook Forwarder', function () { window.fbqObj.params.should.have.property('eventAttr1', 'value1'); window.fbqObj.params.should.have.property('eventAttr2', 'value2'); window.fbqObj.eventData.should.have.property('eventID', SOURCE_MESSAGE_ID); - window.fbqObj.params.should.not.have.property('order_id'); + window.fbqObj.params.should.have.property('order_id', 123); window.fbqObj.params.should.not.have.property('contents'); done(); @@ -840,7 +840,7 @@ describe('Facebook Forwarder', function () { window.fbqObj.params.should.have.property('eventAttr1', 'value1'); window.fbqObj.params.should.have.property('eventAttr2', 'value2'); window.fbqObj.eventData.should.have.property('eventID', SOURCE_MESSAGE_ID); - window.fbqObj.params.should.not.have.property('order_id'); + window.fbqObj.params.should.have.property('order_id', 123); window.fbqObj.params.should.not.have.property('contents'); done(); @@ -1357,6 +1357,90 @@ describe('Facebook Forwarder', function () { window.fbqObj.params.should.have.property('checkout_step', 1); window.fbqObj.eventData.should.have.property('eventID', SOURCE_MESSAGE_ID); + done(); + }); + + it('should log AddToWishlist event with product names as contents', function (done) { + mParticle.forwarder.init({ + pixelCode: 'test-pixel-code', + sendProductNamesasContents: true + }, reportService.cb, true); + + mParticle.forwarder.process({ + EventName: 'eCommerce - AddToWishlist', + EventCategory: CommerceEventType.ProductAddToWishlist, + EventDataType: MessageType.Commerce, + ProductAction: { + ProductActionType: ProductActionType.AddToWishlist, + ProductList: [ + { + Sku: 'sku-111', + Name: 'Laptop', + Category: 'Electronics', + Brand: 'Dell', + Price: 1200, + Quantity: 1 + }, + { + Sku: 'sku-222', + Name: 'Mouse', + Category: 'Accessories', + Brand: 'Logitech', + Price: 50, + Quantity: 1 + } + ], + TransactionId: 456 + }, + CurrencyCode: 'USD', + SourceMessageId: SOURCE_MESSAGE_ID, + }); + + checkBasicProperties('track'); + window.fbqObj.should.have.property('eventName', 'AddToWishlist'); + window.fbqObj.params.should.have.property('content_name', ['Laptop', 'Mouse']); + window.fbqObj.params.should.have.property('order_id', 456); + window.fbqObj.params.should.have.property('content_ids', ['sku-111', 'sku-222']); + window.fbqObj.params.should.not.have.property('contents'); + window.fbqObj.eventData.should.have.property('eventID', SOURCE_MESSAGE_ID); + done(); + }); + + it('should log ViewDetail event with product names as contents', function (done) { + mParticle.forwarder.init({ + pixelCode: 'test-pixel-code', + sendProductNamesasContents: true + }, reportService.cb, true); + + mParticle.forwarder.process({ + EventName: 'eCommerce - ViewDetail', + EventCategory: CommerceEventType.ProductViewDetail, + EventDataType: MessageType.Commerce, + ProductAction: { + ProductActionType: ProductActionType.ViewDetail, + ProductList: [ + { + Sku: 'sku-999', + Name: 'Tablet', + Category: 'Electronics', + Brand: 'Samsung', + Price: 800, + Quantity: 1 + } + ], + TransactionId: 789 + }, + CurrencyCode: 'USD', + SourceMessageId: SOURCE_MESSAGE_ID, + }); + + checkBasicProperties('track'); + window.fbqObj.should.have.property('eventName', 'ViewContent'); + window.fbqObj.params.should.have.property('content_name', ['Tablet']); + window.fbqObj.params.should.have.property('order_id', 789); + window.fbqObj.params.should.have.property('content_ids', ['sku-999']); + window.fbqObj.params.should.not.have.property('contents'); + window.fbqObj.eventData.should.have.property('eventID', SOURCE_MESSAGE_ID); done(); }); }); From 03cee495d7e44f4ed975fe3e9d28f4aee33e7aa0 Mon Sep 17 00:00:00 2001 From: Jaissica Date: Thu, 11 Dec 2025 15:46:40 -0500 Subject: [PATCH 9/9] extend custom product attribute mapping to all ecommerce events --- src/FacebookEventForwarder.js | 25 ++---- test/tests.js | 154 ++++++++++++++++++++++++++++++++-- 2 files changed, 154 insertions(+), 25 deletions(-) diff --git a/src/FacebookEventForwarder.js b/src/FacebookEventForwarder.js index a4a2811..359d5ef 100755 --- a/src/FacebookEventForwarder.js +++ b/src/FacebookEventForwarder.js @@ -167,7 +167,6 @@ var name = 'Facebook', SupportedCommerceTypes.indexOf(event.ProductAction.ProductActionType) > -1) { var eventName, totalValue, - contents, params = cloneEventAttributes(event), eventID = createEventId(event), sendProductNamesAsContents = settings.sendProductNamesasContents || false; @@ -202,6 +201,12 @@ var name = 'Facebook', params['order_id'] = event.ProductAction.TransactionId; } + // Build contents array + var contents = buildProductContents(event.ProductAction.ProductList); + if (contents && contents.length > 0) { + params['contents'] = contents; + } + if (event.ProductAction.ProductActionType == mParticle.ProductActionType.AddToWishlist || event.ProductAction.ProductActionType == mParticle.ProductActionType.Checkout) { var eventCategory = getEventCategoryString(event); @@ -231,12 +236,6 @@ var name = 'Facebook', } else if (event.ProductAction.ProductActionType == mParticle.ProductActionType.AddToCart){ eventName = ADD_TO_CART_EVENT_NAME; - - // Build contents array for AddToCart events - contents = buildProductContents(event.ProductAction.ProductList); - if (contents && contents.length > 0) { - params['contents'] = contents; - } } else{ eventName = VIEW_CONTENT_EVENT_NAME; @@ -259,12 +258,6 @@ var name = 'Facebook', return sum; }, 0); params['num_items'] = num_items; - - // Build contents array for Purchase/Checkout events - contents = buildProductContents(event.ProductAction.ProductList); - if (contents && contents.length > 0) { - params['contents'] = contents; - } } else if (event.ProductAction.ProductActionType == mParticle.ProductActionType.RemoveFromCart) { eventName = REMOVE_FROM_CART_EVENT_NAME; @@ -285,12 +278,6 @@ var name = 'Facebook', } params['value'] = totalValue; - - // Build contents array for RemoveFromCart events - contents = buildProductContents(event.ProductAction.ProductList); - if (contents && contents.length > 0) { - params['contents'] = contents; - } fbq('trackCustom', eventName || 'customEvent', params, eventID); return true; diff --git a/test/tests.js b/test/tests.js index 43a72d0..a8b9bf5 100755 --- a/test/tests.js +++ b/test/tests.js @@ -696,7 +696,14 @@ describe('Facebook Forwarder', function () { window.fbqObj.params.should.have.property('eventAttr2', 'value2'); window.fbqObj.eventData.should.have.property('eventID', SOURCE_MESSAGE_ID); window.fbqObj.params.should.have.property('order_id', 123); - window.fbqObj.params.should.not.have.property('contents'); + window.fbqObj.params.should.have.property('contents'); + window.fbqObj.params.contents.length.should.equal(3); + window.fbqObj.params.contents[0].should.have.property('id', '12345'); + window.fbqObj.params.contents[0].should.have.property('quantity', 2); + window.fbqObj.params.contents[1].should.have.property('id', '888'); + window.fbqObj.params.contents[1].should.have.property('quantity', 1); + window.fbqObj.params.contents[2].should.have.property('id', '666'); + window.fbqObj.params.contents[2].should.have.property('quantity', 1); done(); }); @@ -745,7 +752,10 @@ describe('Facebook Forwarder', function () { window.fbqObj.params.should.have.property('eventAttr2', 'value2'); window.fbqObj.eventData.should.have.property('eventID', SOURCE_MESSAGE_ID); window.fbqObj.params.should.have.property('order_id', 123); - window.fbqObj.params.should.not.have.property('contents'); + window.fbqObj.params.should.have.property('contents'); + window.fbqObj.params.contents.length.should.equal(1); + window.fbqObj.params.contents[0].should.have.property('id', '12345'); + window.fbqObj.params.contents[0].should.have.property('quantity', 1); done(); }); @@ -793,7 +803,10 @@ describe('Facebook Forwarder', function () { window.fbqObj.params.should.have.property('eventAttr2', 'value2'); window.fbqObj.eventData.should.have.property('eventID', SOURCE_MESSAGE_ID); window.fbqObj.params.should.have.property('order_id', 123); - window.fbqObj.params.should.not.have.property('contents'); + window.fbqObj.params.should.have.property('contents'); + window.fbqObj.params.contents.length.should.equal(1); + window.fbqObj.params.contents[0].should.have.property('id', '145'); + window.fbqObj.params.contents[0].should.have.property('quantity', 1); done(); }); @@ -841,7 +854,10 @@ describe('Facebook Forwarder', function () { window.fbqObj.params.should.have.property('eventAttr2', 'value2'); window.fbqObj.eventData.should.have.property('eventID', SOURCE_MESSAGE_ID); window.fbqObj.params.should.have.property('order_id', 123); - window.fbqObj.params.should.not.have.property('contents'); + window.fbqObj.params.should.have.property('contents'); + window.fbqObj.params.contents.length.should.equal(1); + window.fbqObj.params.contents[0].should.have.property('id', '12345'); + window.fbqObj.params.contents[0].should.have.property('quantity', 1); done(); }); @@ -1139,6 +1155,124 @@ describe('Facebook Forwarder', function () { done(); }); + it('should build contents array with mapped attributes for AddToWishlist events', function (done) { + // Initialize with product attribute mapping + mParticle.forwarder.init({ + pixelCode: 'test-pixel-code', + "productAttributeMapping":"[{"jsmap":"3373707","map":"Name","maptype":"ProductAttributeSelector.Name","value":"custom_name"},{"jsmap":"93997959","map":"Brand","maptype":"ProductAttributeSelector.Name","value":"custom_brand"},{"jsmap":"106934601","map":"Price","maptype":"ProductAttributeSelector.Name","value":"custom_price"},{"jsmap":"50511102","map":"Category","maptype":"ProductAttributeSelector.Name","value":"custom_category"},{"jsmap":"94842723","map":"category","maptype":"ProductAttributeSelector.Name","value":"custom_attribute_category"}]" + }, reportService.cb, true); + + mParticle.forwarder.process({ + EventName: 'eCommerce - AddToWishlist', + EventCategory: CommerceEventType.ProductAddToWishlist, + EventDataType: MessageType.Commerce, + ProductAction: { + ProductActionType: ProductActionType.AddToWishlist, + ProductList: [ + { + Sku: 'wishlist-sku', + Name: 'Designer Bag', + Category: 'Accessories', + Brand: 'Gucci', + Variant: 'Black', + Price: 2500, + Quantity: 1, + Attributes: { + category: 'luxury' + } + } + ], + TransactionId: 789 + }, + CurrencyCode: 'USD', + SourceMessageId: SOURCE_MESSAGE_ID, + }); + + checkBasicProperties('track'); + window.fbqObj.should.have.property('eventName', 'AddToWishlist'); + window.fbqObj.params.should.have.property('contents'); + window.fbqObj.params.contents.length.should.equal(1); + window.fbqObj.params.should.have.property('order_id', 789); + + var firstProduct = window.fbqObj.params.contents[0]; + // Standard Facebook fields + firstProduct.should.have.property('id', 'wishlist-sku'); + firstProduct.should.have.property('name', 'Designer Bag'); + firstProduct.should.have.property('brand', 'Gucci'); + firstProduct.should.have.property('item_price', 2500); + firstProduct.should.have.property('quantity', 1); + + // Mapped standard fields + firstProduct.should.have.property('custom_name', 'Designer Bag'); + firstProduct.should.have.property('custom_brand', 'Gucci'); + firstProduct.should.have.property('custom_price', 2500); + firstProduct.should.have.property('custom_category', 'Accessories'); + + // Mapped custom attribute + firstProduct.should.have.property('custom_attribute_category', 'luxury'); + + done(); + }); + + it('should build contents array with mapped attributes for ViewDetail events', function (done) { + // Initialize with product attribute mapping + mParticle.forwarder.init({ + pixelCode: 'test-pixel-code', + "productAttributeMapping":"[{"jsmap":"3373707","map":"Name","maptype":"ProductAttributeSelector.Name","value":"custom_name"},{"jsmap":"93997959","map":"Brand","maptype":"ProductAttributeSelector.Name","value":"custom_brand"},{"jsmap":"106934601","map":"Price","maptype":"ProductAttributeSelector.Name","value":"custom_price"},{"jsmap":"50511102","map":"Category","maptype":"ProductAttributeSelector.Name","value":"custom_category"},{"jsmap":"94842723","map":"category","maptype":"ProductAttributeSelector.Name","value":"custom_attribute_category"}]" + }, reportService.cb, true); + + mParticle.forwarder.process({ + EventName: 'eCommerce - ViewDetail', + EventCategory: CommerceEventType.ProductViewDetail, + EventDataType: MessageType.Commerce, + ProductAction: { + ProductActionType: ProductActionType.ViewDetail, + ProductList: [ + { + Sku: 'view-sku-999', + Name: 'Laptop Pro', + Category: 'Electronics', + Brand: 'Apple', + Variant: '16-inch', + Price: 3000, + Quantity: 1, + Attributes: { + category: 'computers' + } + } + ], + TransactionId: 999 + }, + CurrencyCode: 'USD', + SourceMessageId: SOURCE_MESSAGE_ID, + }); + + checkBasicProperties('track'); + window.fbqObj.should.have.property('eventName', 'ViewContent'); + window.fbqObj.params.should.have.property('contents'); + window.fbqObj.params.contents.length.should.equal(1); + window.fbqObj.params.should.have.property('order_id', 999); + + var firstProduct = window.fbqObj.params.contents[0]; + // Standard Facebook fields + firstProduct.should.have.property('id', 'view-sku-999'); + firstProduct.should.have.property('name', 'Laptop Pro'); + firstProduct.should.have.property('brand', 'Apple'); + firstProduct.should.have.property('item_price', 3000); + firstProduct.should.have.property('quantity', 1); + + // Mapped standard fields + firstProduct.should.have.property('custom_name', 'Laptop Pro'); + firstProduct.should.have.property('custom_brand', 'Apple'); + firstProduct.should.have.property('custom_price', 3000); + firstProduct.should.have.property('custom_category', 'Electronics'); + + // Mapped custom attribute + firstProduct.should.have.property('custom_attribute_category', 'computers'); + + done(); + }); + it('should log Purchase event with product names as contents', function (done) { mParticle.forwarder.init({ pixelCode: 'test-pixel-code', @@ -1401,7 +1535,12 @@ describe('Facebook Forwarder', function () { window.fbqObj.params.should.have.property('content_name', ['Laptop', 'Mouse']); window.fbqObj.params.should.have.property('order_id', 456); window.fbqObj.params.should.have.property('content_ids', ['sku-111', 'sku-222']); - window.fbqObj.params.should.not.have.property('contents'); + window.fbqObj.params.should.have.property('contents'); + window.fbqObj.params.contents.length.should.equal(2); + window.fbqObj.params.contents[0].should.have.property('id', 'sku-111'); + window.fbqObj.params.contents[0].should.have.property('quantity', 1); + window.fbqObj.params.contents[1].should.have.property('id', 'sku-222'); + window.fbqObj.params.contents[1].should.have.property('quantity', 1); window.fbqObj.eventData.should.have.property('eventID', SOURCE_MESSAGE_ID); done(); }); @@ -1439,7 +1578,10 @@ describe('Facebook Forwarder', function () { window.fbqObj.params.should.have.property('content_name', ['Tablet']); window.fbqObj.params.should.have.property('order_id', 789); window.fbqObj.params.should.have.property('content_ids', ['sku-999']); - window.fbqObj.params.should.not.have.property('contents'); + window.fbqObj.params.should.have.property('contents'); + window.fbqObj.params.contents.length.should.equal(1); + window.fbqObj.params.contents[0].should.have.property('id', 'sku-999'); + window.fbqObj.params.contents[0].should.have.property('quantity', 1); window.fbqObj.eventData.should.have.property('eventID', SOURCE_MESSAGE_ID); done(); });