Skip to content
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
29 changes: 28 additions & 1 deletion examples/events/custom-event-override.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
## event overrides

For any event with a set `customContext`, the collector overrides joins fields set in the relevant contexts with fields in `customContext`. The use case for overrides is when a developer wants to reuse and extend contexts set by other parts of the page in already supporte events.
For any event with a set `customContext`, the collector overrides joins fields set in the relevant contexts with fields in `customContext`. The use case for overrides is when a developer wants to reuse and extend contexts set by other parts of the page in already supported events.

Event overrides are only applicable when forwarding to AEP. They are not applied to Adobe Commerce and Sensei analytics events. Additional info in [README](../../packages/storefront-events-collector/README.md)

> [!NOTE]
> When augmenting `productListItems` with custom attributes in AEP event payloads, match products using SKU. This requirement does not apply to `product-page-view` events.


### 🔧 Usage

```javascript
Expand Down Expand Up @@ -75,3 +79,26 @@ mse.publish.pageView({
},
});
```

### Example 4 - adding custom context to productListItems with events with multiple products

```javascript
const mse = window.magentoStorefrontEvents;

mse.context.setCustom({
productListItems: [
{
SKU: "24-WB01", //Match SKU to override correct product in event payload
productCategory: "Hand Bag", //Custom attribute added to event payload
name: "Strive Handbag (CustomName)" //Override existing attribute with custom value in event payload
},
{
SKU: "24-MB04",
productCategory: "Backpack Bag",
name: "Strive Backpack (CustomName)"
},
],
});

mse.publish.shoppingCartView();
```
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ const aepHandler = async (event: Event): Promise<void> => {
let payload: BeaconSchema = {};
if (customContext && Object.keys(customContext as BeaconSchema).length !== 0) {
// override payload on custom context
payload = customContext as BeaconSchema;
payload = { ...customContext } as BeaconSchema;
}

payload.userAccount = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ const aepHandler = async (event: Event): Promise<void> => {
let payload: BeaconSchema = {};
if (customContext && Object.keys(customContext as BeaconSchema).length !== 0) {
// override payload on custom context
payload = customContext as BeaconSchema;
payload = { ...customContext } as BeaconSchema;
}

payload.commerce = payload.commerce || {};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ const aepHandler = async (event: Event): Promise<void> => {
let payload: BeaconSchema = {};
if (customContext && Object.keys(customContext as BeaconSchema).length !== 0) {
// override payload on custom context
payload = customContext as BeaconSchema;
payload = { ...customContext } as BeaconSchema;
}

payload.web = payload.web || {};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ const aepHandler = async (event: Event): Promise<void> => {
let payload: BeaconSchema = {};
if (customContext && Object.keys(customContext as BeaconSchema).length !== 0) {
// override payload on custom context
payload = customContext as BeaconSchema;
payload = { ...customContext } as BeaconSchema;
}

payload.commerce = payload.commerce || {};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ const aepHandler = async (event: Event): Promise<void> => {
let payload: BeaconSchema = {};
if (customContext && Object.keys(customContext as BeaconSchema).length !== 0) {
// override payload on custom context
payload = customContext as BeaconSchema;
payload = { ...customContext } as BeaconSchema;
}

payload.commerce = payload.commerce || {};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ const aepHandler = async (event: Event): Promise<void> => {
let payload: BeaconSchema = {};
if (customContext && Object.keys(customContext as BeaconSchema).length !== 0) {
// override payload on custom context
payload = customContext as BeaconSchema;
payload = { ...customContext } as BeaconSchema;
}

const productListItemFromCustomContext: ProductListItem | undefined = payload.productListItems?.length
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ const handler = async (event: Event): Promise<void> => {
let payload: BeaconSchema = {};
if (customContext && Object.keys(customContext as BeaconSchema).length !== 0) {
// override payload on custom context
payload = customContext as BeaconSchema;
payload = { ...customContext } as BeaconSchema;
}

payload.commerce = payload.commerce || {};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ const handler = async (event: Event): Promise<void> => {
let payload: BeaconSchema = {};
if (customContext && Object.keys(customContext as BeaconSchema).length !== 0) {
// override payload on custom context
payload = customContext as BeaconSchema;
payload = { ...customContext } as BeaconSchema;
}

payload.commerce = payload.commerce || {};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ const handler = async (event: Event): Promise<void> => {
let payload: BeaconSchema = {};
if (customContext && Object.keys(customContext as BeaconSchema).length !== 0) {
// override payload on custom context
payload = customContext as BeaconSchema;
payload = { ...customContext } as BeaconSchema;
}

payload.commerce = payload.commerce || {};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ const aepHandler = async (event: Event): Promise<void> => {
let payload: BeaconSchema = {};
if (customContext && Object.keys(customContext as BeaconSchema).length !== 0) {
// override payload on custom context
payload = customContext as BeaconSchema;
payload = { ...customContext } as BeaconSchema;
}

payload.commerce = payload.commerce || {};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ const handler = async (event: Event): Promise<void> => {

if (customContext && Object.keys(customContext as BeaconSchema).length !== 0) {
// override payload on custom context
payload = customContext as BeaconSchema;
payload = { ...customContext } as BeaconSchema;
}
const sortFromCtx: SearchSort[] = (searchInputCtx?.data.sort as SearchSort[]) ?? [];

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ const handler = async (event: Event): Promise<void> => {
let payload: BeaconSchema = {};
if (customContext && Object.keys(customContext as BeaconSchema).length !== 0) {
// override payload on custom context
payload = customContext as BeaconSchema;
payload = { ...customContext } as BeaconSchema;
}

payload.siteSearch = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ const handler = async (event: Event): Promise<void> => {
let payload: BeaconSchema = {};
if (customContext && Object.keys(customContext as BeaconSchema).length !== 0) {
// override payload on custom context
payload = customContext as BeaconSchema;
payload = { ...customContext } as BeaconSchema;
}

payload.commerce = payload.commerce || {};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ const handler = async (event: Event): Promise<void> => {
let payload: BeaconSchema = {};
if (customContext && Object.keys(customContext as BeaconSchema).length !== 0) {
// override payload on custom context
payload = customContext as BeaconSchema;
payload = { ...customContext } as BeaconSchema;
}

payload.commerce = payload.commerce || {};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ const aepHandler = async (event: Event): Promise<void> => {
let payload: BeaconSchema = {};
if (customContext && Object.keys(customContext as BeaconSchema).length !== 0) {
// override payload on custom context
payload = customContext as BeaconSchema;
payload = { ...customContext } as BeaconSchema;
}

payload.commerce = payload.commerce || {};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ const createAccountPayload = (customContext: any, accountContext: sdkSchemas.Acc
let payload: BeaconSchema = {};
if (customContext && Object.keys(customContext as BeaconSchema).length !== 0) {
// override payload on custom context
payload = customContext as BeaconSchema;
payload = { ...customContext } as BeaconSchema;
}

payload.person = payload.person || {};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,19 +28,19 @@ const createProductListItems = (

if (requisitionListItemsContext) {
requisitionListItemsContext.items?.map((item) => {
const productListItemFromCustomContext = productListFromCustomContextMap.get(item.sku);
const requisitionListItem = {
SKU: item.sku,
name: productListItemFromCustomContext?.name || item.name,
quantity: productListItemFromCustomContext?.quantity || Number(item.quantity),
priceTotal:
productListItemFromCustomContext?.priceTotal ||
formatPrice((Number(item.pricing?.regularPrice) || 0) * Number(item.quantity)),
currencyCode:
productListItemFromCustomContext?.currencyCode ||
(item.pricing?.currencyCode ?? storefrontContext.storeViewCurrencyCode),
selectedOptions: productListItemFromCustomContext?.selectedOptions || item.selectedOptions,
};
const requisitionListItem = productListFromCustomContextMap.get(item.sku) || {};

// custom SKU is not supported as it is used as identification for merging
requisitionListItem.SKU = item.sku;
requisitionListItem.name = requisitionListItem?.name || item.name;
requisitionListItem.quantity = requisitionListItem?.quantity || Number(item.quantity);
requisitionListItem.priceTotal =
requisitionListItem?.priceTotal ||
formatPrice((Number(item.pricing?.regularPrice) || 0) * Number(item.quantity));
requisitionListItem.currencyCode =
requisitionListItem?.currencyCode ||
(item.pricing?.currencyCode ?? storefrontContext.storeViewCurrencyCode);
requisitionListItem.selectedOptions = requisitionListItem?.selectedOptions || item.selectedOptions;
returnList.push(requisitionListItem);
});
} else {
Expand All @@ -53,26 +53,21 @@ const createProductListItems = (
});
});

const productListItemFromCustomContext = productListFromCustomContextMap.get(item.product?.sku);
const productListItem = productListFromCustomContextMap.get(item.product?.sku) || {};

const productListItem: ProductListItem = {
SKU: item.product?.sku,
name: productListItemFromCustomContext?.name || item.product?.name,
quantity: productListItemFromCustomContext?.quantity || item.quantity,
priceTotal:
productListItemFromCustomContext?.priceTotal ||
formatPrice(item.prices?.price?.value * item.quantity) ||
0,
productImageUrl: productListItemFromCustomContext?.productImageUrl || item.product.mainImageUrl,
currencyCode:
productListItemFromCustomContext?.currencyCode ||
(item.prices?.price?.currency ?? storefrontContext.storeViewCurrencyCode),
discountAmount:
productListItemFromCustomContext?.discountAmount ||
item.discountAmount ||
getDiscountAmount(item.product),
selectedOptions: productListItemFromCustomContext?.selectedOptions || selectedOptions,
};
// custom SKU is not supported as it is used as identification for merging
productListItem.SKU = item.product?.sku;
productListItem.name = productListItem.name || item.product?.name;
productListItem.quantity = productListItem?.quantity || item.quantity;
productListItem.priceTotal =
productListItem?.priceTotal || formatPrice(item.prices?.price?.value * item.quantity) || 0;
productListItem.productImageUrl = productListItem?.productImageUrl || item.product.mainImageUrl;
productListItem.currencyCode =
productListItem?.currencyCode ||
(item.prices?.price?.currency ?? storefrontContext.storeViewCurrencyCode);
productListItem.discountAmount =
productListItem?.discountAmount || item.discountAmount || getDiscountAmount(item.product);
productListItem.selectedOptions = productListItem?.selectedOptions || selectedOptions;

returnList.push(productListItem);
});
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
jest.mock("../../../src/alloy");
import { Event } from "@adobe/magento-storefront-events-sdk/dist/types/types/events";
import { sendEvent } from "../../../src/alloy";
import { shoppingCartViewHandlerAEP } from "../../../src/handlers";
import { mockEvent } from "../../utils/mocks";

const AEPevent = { ...mockEvent };
delete AEPevent.eventInfo.customContext;

test("correctly structures AEP event and calls alloy.sendEvent", () => {
shoppingCartViewHandlerAEP(mockEvent);

expect(sendEvent).toHaveBeenCalledTimes(1);

expect(sendEvent).toHaveBeenCalledWith(
{
commerce: {
cart: {
cartID: "111111",
},
productListViews: {
value: 1,
},
commerceScope: {
environmentID: "aaaaaa",
storeCode: "magento",
storeViewCode: "default",
websiteCode: "website",
},
order: {
discountAmount: 0,
},
},
productListItems: [
{
SKU: "ts001",
name: "T-Shirt",
quantity: 1,
priceTotal: 20,
productImageUrl: undefined,
currencyCode: "USD",
discountAmount: 0,
selectedOptions: [],
},
{
SKU: "h001",
name: "Hoodie",
quantity: 1,
priceTotal: 50,
productImageUrl: undefined,
currencyCode: "USD",
discountAmount: 0,
selectedOptions: [],
},
],
_id: undefined,
eventType: "commerce.productListViews",
},
mockEvent,
);
});

test("correctly structures AEP event with customContext and calls alloy.sendEvent", () => {
const customContext = {
commerce: {
order: {
couponCode: "couponCode123",
},
},
productListItems: [
{
SKU: "ts001",
name: "Custom Product Name",
categoryId: "customCat001",
},
],
};
const mockedAEPevent = {
event: "shopping-cart-view",
eventInfo: {
...AEPevent.eventInfo,
customContext,
},
} as Event;

shoppingCartViewHandlerAEP(mockedAEPevent);

expect(sendEvent).toHaveBeenCalledTimes(1);

expect(sendEvent).toHaveBeenCalledWith(
{
commerce: {
cart: {
cartID: "111111",
},
productListViews: {
value: 1,
},
commerceScope: {
environmentID: "aaaaaa",
storeCode: "magento",
storeViewCode: "default",
websiteCode: "website",
},
order: {
discountAmount: 0,
couponCode: customContext.commerce.order.couponCode,
},
},
productListItems: [
{
SKU: "ts001",
name: customContext.productListItems[0].name,
quantity: 1,
priceTotal: 20,
productImageUrl: undefined,
currencyCode: "USD",
discountAmount: 0,
selectedOptions: [],
categoryId: customContext.productListItems[0].categoryId,
},
{
SKU: "h001",
name: "Hoodie",
quantity: 1,
priceTotal: 50,
productImageUrl: undefined,
currencyCode: "USD",
discountAmount: 0,
selectedOptions: [],
},
],
_id: undefined,
eventType: "commerce.productListViews",
},
mockedAEPevent,
);
});