Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: supporting add to cart for criteo #1696

Merged
merged 3 commits into from
Apr 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
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'];

Check warning on line 13 in packages/analytics-js-common/src/constants/integrations/Criteo/constants.ts

View check run for this annotation

Codecov / codecov/patch

packages/analytics-js-common/src/constants/integrations/Criteo/constants.ts#L13

Added line #L13 was not covered by tests

export {
NAME,
Expand Down
Original file line number Diff line number Diff line change
@@ -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);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
handleProductView,
generateExtraData,
handleCommonFields,
handleProductAdded,
} from './utils';
import { getHashFromArrayWithDuplicate } from '../../utils/commonUtils';

Expand Down Expand Up @@ -76,7 +77,7 @@
};
finalPayload.push(homeEvent);
} else {
logger.error('Home page is not detected');
logger.warn('Home page is not detected');

Check warning on line 80 in packages/analytics-js-integrations/src/integrations/Criteo/browser.js

View check run for this annotation

Codecov / codecov/patch

packages/analytics-js-integrations/src/integrations/Criteo/browser.js#L80

Added line #L80 was not covered by tests
return;
}

Expand All @@ -99,15 +100,15 @@
}

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');

Check warning on line 103 in packages/analytics-js-integrations/src/integrations/Criteo/browser.js

View check run for this annotation

Codecov / codecov/patch

packages/analytics-js-integrations/src/integrations/Criteo/browser.js#L103

Added line #L103 was not covered by tests
return;
}

const eventMapping = getHashFromArrayWithDuplicate(this.eventsToStandard);
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`);

Check warning on line 111 in packages/analytics-js-integrations/src/integrations/Criteo/browser.js

View check run for this annotation

Codecov / codecov/patch

packages/analytics-js-integrations/src/integrations/Criteo/browser.js#L111

Added line #L111 was not covered by tests
return;
}
let events = [];
Expand All @@ -129,6 +130,9 @@
case 'product list viewed':
handleListView(rudderElement.message, finalPayload, this.OPERATOR_LIST);
break;
case 'product added':
handleProductAdded(rudderElement.message, finalPayload)
break;

Check warning on line 135 in packages/analytics-js-integrations/src/integrations/Criteo/browser.js

View check run for this annotation

Codecov / codecov/patch

packages/analytics-js-integrations/src/integrations/Criteo/browser.js#L134-L135

Added lines #L134 - L135 were not covered by tests
default:
break;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@
}
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');

Check warning on line 76 in packages/analytics-js-integrations/src/integrations/Criteo/utils.js

View check run for this annotation

Codecov / codecov/patch

packages/analytics-js-integrations/src/integrations/Criteo/utils.js#L76

Added line #L76 was not covered by tests
}

// Final example payload supported by destination
Expand Down Expand Up @@ -185,6 +185,33 @@
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) : [] ,
};
ItsSudip marked this conversation as resolved.
Show resolved Hide resolved
finalPayload.push(addToCartObject);
};

/**
* Handles events
* @param {*} message
Expand All @@ -197,7 +224,7 @@
const productInfo = getProductInfo(properties);

if (productInfo.length === 0) {
logger.error(
logger.warn(

Check warning on line 227 in packages/analytics-js-integrations/src/integrations/Criteo/utils.js

View check run for this annotation

Codecov / codecov/patch

packages/analytics-js-integrations/src/integrations/Criteo/utils.js#L227

Added line #L227 was not covered by tests
'None of the products had sufficient information or information is wrongly formatted',
);
return;
Expand Down Expand Up @@ -294,11 +321,11 @@
}
});
if (productIdList.length === 0) {
logger.error('None of the product information had product_id');
logger.warn('None of the product information had product_id');

Check warning on line 324 in packages/analytics-js-integrations/src/integrations/Criteo/utils.js

View check run for this annotation

Codecov / codecov/patch

packages/analytics-js-integrations/src/integrations/Criteo/utils.js#L324

Added line #L324 was not covered by tests
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');

Check warning on line 328 in packages/analytics-js-integrations/src/integrations/Criteo/utils.js

View check run for this annotation

Codecov / codecov/patch

packages/analytics-js-integrations/src/integrations/Criteo/utils.js#L328

Added line #L328 was not covered by tests
return;
}

Expand Down Expand Up @@ -343,4 +370,6 @@
handleProductView,
generateExtraData,
handleCommonFields,
getProductInfo,
handleProductAdded
};