From 83ee3cefde202f8b9080759aa2e18b02b22a3596 Mon Sep 17 00:00:00 2001 From: shrouti1507 Date: Thu, 18 Apr 2024 19:40:45 +0530 Subject: [PATCH 1/2] feat: supporting add to cart for criteo --- .../integrations/Criteo/constants.ts | 2 +- .../src/integrations/Criteo/browser.js | 10 +++-- .../src/integrations/Criteo/utils.js | 37 +++++++++++++++++-- 3 files changed, 41 insertions(+), 8 deletions(-) diff --git a/packages/analytics-js-common/src/constants/integrations/Criteo/constants.ts b/packages/analytics-js-common/src/constants/integrations/Criteo/constants.ts index b73d86aef7..855bb6f276 100644 --- a/packages/analytics-js-common/src/constants/integrations/Criteo/constants.ts +++ b/packages/analytics-js-common/src/constants/integrations/Criteo/constants.ts @@ -10,7 +10,7 @@ const CNameMapping = { criteo: NAME, }; -const supportedEvents = ['product viewed', 'cart viewed', 'order completed', 'product list viewed']; +const supportedEvents = ['product viewed', 'cart viewed', 'order completed', 'product list viewed', 'product added']; export { NAME, diff --git a/packages/analytics-js-integrations/src/integrations/Criteo/browser.js b/packages/analytics-js-integrations/src/integrations/Criteo/browser.js index 4dba6d01f9..388a165d46 100644 --- a/packages/analytics-js-integrations/src/integrations/Criteo/browser.js +++ b/packages/analytics-js-integrations/src/integrations/Criteo/browser.js @@ -14,6 +14,7 @@ import { handleProductView, generateExtraData, handleCommonFields, + handleProductAdded, } from './utils'; import { getHashFromArrayWithDuplicate } from '../../utils/commonUtils'; @@ -76,7 +77,7 @@ class Criteo { }; finalPayload.push(homeEvent); } else { - logger.error('Home page is not detected'); + logger.warn('Home page is not detected'); return; } @@ -99,7 +100,7 @@ class Criteo { } if (!properties || Object.keys(properties).length === 0) { - logger.error('Either properties object is missing or empty in the track call'); + logger.warn('Either properties object is missing or empty in the track call'); return; } @@ -107,7 +108,7 @@ class Criteo { const trimmedEvent = event.toLowerCase().trim(); if (!supportedEvents.includes(trimmedEvent) && !eventMapping[trimmedEvent]) { - logger.error(`event ${trimmedEvent} is not supported`); + logger.warn(`event ${trimmedEvent} is not supported`); return; } let events = []; @@ -129,6 +130,9 @@ class Criteo { case 'product list viewed': handleListView(rudderElement.message, finalPayload, this.OPERATOR_LIST); break; + case 'product added': + handleProductAdded(rudderElement.message, finalPayload) + break; default: break; } diff --git a/packages/analytics-js-integrations/src/integrations/Criteo/utils.js b/packages/analytics-js-integrations/src/integrations/Criteo/utils.js index 03cc94a4c8..8e89f6d316 100644 --- a/packages/analytics-js-integrations/src/integrations/Criteo/utils.js +++ b/packages/analytics-js-integrations/src/integrations/Criteo/utils.js @@ -73,7 +73,7 @@ const handleProductView = (message, finalPayload) => { } finalPayload.push(viewItemObject); } else { - logger.error('product_id is a mandatory field to use for Product Tag'); + logger.warn('product_id is a mandatory field to use for Product Tag'); } // Final example payload supported by destination @@ -185,6 +185,33 @@ const processViewedCartEvent = (finalPayload, productInfo) => { finalPayload.push(viewBasketObject); }; +/** + * Adds a product to the cart and updates the final payload. + * + * @param {Object} properties - The properties of the event. + * @param {Array} finalPayload - The final payload array to be updated. + * @param {Array} productInfo - The information of the product to be added to the cart. + * @returns {void} + */ +const handleProductAdded = (message,finalPayload) => { + const buildProductObject = (properties) => + [ + { + id: String(properties.product_id), + price: parseFloat(properties.price), + quantity: parseInt(properties.quantity, 10), + } + ] + + const {properties} = message; + const addToCartObject = { + event: 'addToCart', + currency: properties.currency, + item: validateProduct(properties, 0) ? buildProductObject(properties) : [] , + }; + finalPayload.push(addToCartObject); +}; + /** * Handles events * @param {*} message @@ -197,7 +224,7 @@ const handlingEventDuo = (message, finalPayload) => { const productInfo = getProductInfo(properties); if (productInfo.length === 0) { - logger.error( + logger.warn( 'None of the products had sufficient information or information is wrongly formatted', ); return; @@ -294,11 +321,11 @@ const handleListView = (message, finalPayload, OPERATOR_LIST) => { } }); if (productIdList.length === 0) { - logger.error('None of the product information had product_id'); + logger.warn('None of the product information had product_id'); return; } } else { - logger.error('The payload should consist of at least one product information'); + logger.warn('The payload should consist of at least one product information'); return; } @@ -343,4 +370,6 @@ export { handleProductView, generateExtraData, handleCommonFields, + getProductInfo, + handleProductAdded }; From 21ea0080e7c8ef42d11c2fa82e5698edcabbf523 Mon Sep 17 00:00:00 2001 From: shrouti1507 Date: Mon, 22 Apr 2024 10:31:55 +0530 Subject: [PATCH 2/2] fix: adding test cases --- .../integrations/Criteo/utils.test.js | 127 ++++++++++++++++++ 1 file changed, 127 insertions(+) create mode 100644 packages/analytics-js-integrations/__tests__/integrations/Criteo/utils.test.js diff --git a/packages/analytics-js-integrations/__tests__/integrations/Criteo/utils.test.js b/packages/analytics-js-integrations/__tests__/integrations/Criteo/utils.test.js new file mode 100644 index 0000000000..dfc5a2ad2d --- /dev/null +++ b/packages/analytics-js-integrations/__tests__/integrations/Criteo/utils.test.js @@ -0,0 +1,127 @@ +import { handleProductAdded } from '../../../src/integrations/Criteo/utils'; + +describe('handleProductAdded', () => { + // The function correctly extracts the 'properties' object from the 'message' parameter. + it('should correctly extract properties object from message parameter', () => { + const message = { + properties: { + product_id: '123', + price: '9.99', + quantity: '5', + currency: 'USD', + }, + }; + const finalPayload = []; + + handleProductAdded(message, finalPayload); + + expect(finalPayload.length).toBe(1); + expect(finalPayload[0].event).toBe('addToCart'); + expect(finalPayload[0].currency).toBe('USD'); + expect(finalPayload[0].item.length).toBe(1); + expect(finalPayload[0].item[0].id).toBe('123'); + expect(finalPayload[0].item[0].price).toBe(9.99); + expect(finalPayload[0].item[0].quantity).toBe(5); + }); + + // When the 'message' parameter is undefined, the function throws an error. + it('should throw an error when message parameter is undefined', () => { + const message = undefined; + const finalPayload = []; + + expect(() => { + handleProductAdded(message, finalPayload); + }).toThrow(); + }); + + // When the 'properties' object is valid, the function creates an 'addToCartObject' with the correct structure. + it('should create addToCartObject with correct structure when properties object is valid', () => { + const message = { + properties: { + product_id: '123', + price: '9.99', + quantity: '5', + currency: 'USD', + }, + }; + const finalPayload = []; + + handleProductAdded(message, finalPayload); + + expect(finalPayload.length).toBe(1); + expect(finalPayload[0].event).toBe('addToCart'); + expect(finalPayload[0].currency).toBe('USD'); + expect(finalPayload[0].item.length).toBe(1); + expect(finalPayload[0].item[0].id).toBe('123'); + expect(finalPayload[0].item[0].price).toBe(9.99); + expect(finalPayload[0].item[0].quantity).toBe(5); + }); + + // When the product is valid, the function adds the product object to the 'item' property of the 'addToCartObject'. + it("should add product object to 'item' property when product is valid", () => { + const message = { + properties: { + product_id: '123', + price: '9.99', + quantity: '5', + currency: 'USD', + }, + }; + const finalPayload = []; + + handleProductAdded(message, finalPayload); + + expect(finalPayload.length).toBe(1); + expect(finalPayload[0].event).toBe('addToCart'); + expect(finalPayload[0].currency).toBe('USD'); + expect(finalPayload[0].item.length).toBe(1); + expect(finalPayload[0].item[0].id).toBe('123'); + expect(finalPayload[0].item[0].price).toBe(9.99); + expect(finalPayload[0].item[0].quantity).toBe(5); + }); + + // The function correctly pushes the 'addToCartObject' to the 'finalPayload' array. + it("should correctly push 'addToCartObject' to 'finalPayload' array", () => { + const message = { + properties: { + product_id: '123', + price: '9.99', + quantity: '5', + currency: 'USD', + }, + }; + const finalPayload = []; + + handleProductAdded(message, finalPayload); + + expect(finalPayload.length).toBe(1); + expect(finalPayload[0].event).toBe('addToCart'); + expect(finalPayload[0].currency).toBe('USD'); + expect(finalPayload[0].item.length).toBe(1); + expect(finalPayload[0].item[0].id).toBe('123'); + expect(finalPayload[0].item[0].price).toBe(9.99); + expect(finalPayload[0].item[0].quantity).toBe(5); + }); + + // When the 'properties' object is missing the 'currency' property, the function creates an 'addToCartObject' without the 'currency' property. + it("should create 'addToCartObject' without 'currency' property when 'properties' object is missing 'currency'", () => { + const message = { + properties: { + product_id: '123', + price: '9.99', + quantity: '5', + }, + }; + const finalPayload = []; + + handleProductAdded(message, finalPayload); + + expect(finalPayload.length).toBe(1); + expect(finalPayload[0].event).toBe('addToCart'); + expect(finalPayload[0].currency).toBeUndefined(); + expect(finalPayload[0].item.length).toBe(1); + expect(finalPayload[0].item[0].id).toBe('123'); + expect(finalPayload[0].item[0].price).toBe(9.99); + expect(finalPayload[0].item[0].quantity).toBe(5); + }); + }); \ No newline at end of file