Skip to content

Commit

Permalink
Experience Platform Connector extension (magento#3885)
Browse files Browse the repository at this point in the history
* Set up new extension and add it to template project

* Integrate the storefront events sdk and collector libraries into the extension

* Add initial event handler code

* Add rest of handlers with TODO items and move non-handler modules out of handlers directory

* Define page view handler

* Enable jest testing

* Add product page view event handling

* Add support for shopping cart view event

* Add support for category page view event

* Add support for setting the storefront context

* Add support for add to cart events

* Add support for create account event

* Add support for edit account event

* Add support for checkout events

* Add support for search requests

* Get IMS org and Datastream ID from GraphQL instead of .env file

* Fix logic for account event handling

* Fix bugs and add set context for other page view events

* Add check for gql errors

* Pwa 2743/tests (magento#3883)

* added unit tests and mocks

* added searchReqestSent unit tests/mocks

* updated unit tests

* ran prettier

* removed obsolete snapshots

* Fix broken tests

* Fix broken tests

* Fix linting issue

* [PWA-2879] Custom Beacon extension event (magento#3879)

* PWA-2879: Custom Beacon extension event

- add wrapper for useAutocomplete
- add dispatch event to wrapper
- publish Search Request Response in handler

* PWA-2879: Custom Beacon extension event

- at tests cases for Search Response Received event

* confirmed/removed TODO's (magento#3892)

* Make changes based on feedback

Co-authored-by: Ryan Walter <[email protected]>
Co-authored-by: Anthoula Wojczak <[email protected]>
Co-authored-by: Devagouda <[email protected]>
  • Loading branch information
4 people authored Jun 22, 2022
1 parent 80db006 commit a2b1668
Show file tree
Hide file tree
Showing 65 changed files with 5,271 additions and 20 deletions.
9 changes: 8 additions & 1 deletion jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -315,7 +315,14 @@ const jestConfig = {
),
configureProject('pwa-theme-venia', 'Venia Theme', () => ({
testEnvironment: 'node'
}))
})),
configureProject(
'extensions/experience-platform-connector',
'Experience platform connector',
() => ({
testEnvironment: 'node'
})
)
],
// Include files with zero tests in overall coverage analysis by specifying
// coverage paths manually.
Expand Down
24 changes: 24 additions & 0 deletions packages/extensions/experience-platform-connector/intercept.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
module.exports = targets => {
const { talons } = targets.of('@magento/peregrine');
const { specialFeatures } = targets.of('@magento/pwa-buildpack');

specialFeatures.tap(flags => {
/**
* Wee need to activate esModules, cssModules and GQL Queries to allow build pack to load our extension
* {@link https://magento.github.io/pwa-studio/pwa-buildpack/reference/configure-webpack/#special-flags}.
*/
flags[targets.name] = {
esModules: true
};
});

talons.tap(({ App, Header, SearchBar }) => {
App.useApp.wrapWith('@magento/experience-platform-connector');
Header.useAccountMenu.wrapWith(
'@magento/experience-platform-connector/src/wrappers/wrapUseAccountMenu'
);
SearchBar.useAutocomplete.wrapWith(
'@magento/experience-platform-connector/src/wrappers/wrapUseAutocomplete'
);
});
};
30 changes: 30 additions & 0 deletions packages/extensions/experience-platform-connector/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
"name": "@magento/experience-platform-connector",
"version": "0.0.1",
"publishConfig": {
"access": "public"
},
"description": "Sends storefront events to the Adobe Experience Platform",
"main": "./src/main.js",
"scripts": {
"clean": " "
},
"repository": "github:magento/pwa-studio",
"license": "(OSL-3.0 OR AFL-3.0)",
"dependencies": {
"@adobe/magento-storefront-event-collector": "~1.1.13",
"@adobe/magento-storefront-events-sdk": "~1.1.13"
},
"devDependencies": {},
"peerDependencies": {
"@apollo/client": "~3.6.6",
"@magento/peregrine": "~12.3.0",
"@magento/pwa-buildpack": "~11.2.0",
"react": "~17.0.1"
},
"pwa-studio": {
"targets": {
"intercept": "./intercept"
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`getFormattedProducts() returns correctly formatted data 1`] = `
Array [
Object {
"configurableOptions": Array [
Object {
"id": 157,
"optionLabel": "Fashion Color",
"valueId": "Y29uZmlndXJhYmxlLzE1Ny8zMQ==",
"valueLabel": "Peach",
},
Object {
"id": 190,
"optionLabel": "Fashion Size",
"valueId": "Y29uZmlndXJhYmxlLzE5MC80Mw==",
"valueLabel": "L",
},
],
"formattedPrice": "",
"id": "MjQ2Ng==",
"prices": Object {
"__typename": "CartItemPrices",
"price": Object {
"__typename": "Money",
"currency": "USD",
"value": 78,
},
"row_total": Object {
"__typename": "Money",
"value": 78,
},
"total_item_discount": Object {
"__typename": "Money",
"value": 0,
},
},
"product": Object {
"canonicalUrl": "rowena-skirt",
"mainImageUrl": "https://master-7rqtwti-mfwmkrjfqvbjk.us-4.magentosite.cloud/media/catalog/product/cache/609faca36a4bc16a754bc2f43c184970/v/s/vsk02-ll_main_2.jpg",
"name": "Rowena Skirt",
"pricing": Object {
"currencyCode": "USD",
"maximalPrice": 78,
"minimalPrice": 78,
"regularPrice": 78,
},
"productType": "ConfigurableProduct",
"sku": "VSK02",
},
"quantity": 1,
},
Object {
"configurableOptions": null,
"formattedPrice": "",
"id": "MjQ4Mg==",
"prices": Object {
"__typename": "CartItemPrices",
"price": Object {
"__typename": "Money",
"currency": "USD",
"value": 68,
},
"row_total": Object {
"__typename": "Money",
"value": 136,
},
"total_item_discount": Object {
"__typename": "Money",
"value": 0,
},
},
"product": Object {
"canonicalUrl": "silver-cirque-earrings",
"mainImageUrl": "https://master-7rqtwti-mfwmkrjfqvbjk.us-4.magentosite.cloud/media/catalog/product/cache/609faca36a4bc16a754bc2f43c184970/v/a/va17-si_main.jpg",
"name": "Silver Cirque Earrings",
"pricing": Object {
"currencyCode": "USD",
"maximalPrice": 68,
"minimalPrice": 68,
"regularPrice": 68,
},
"productType": "SimpleProduct",
"sku": "VA17-SI-NA",
},
"quantity": 2,
},
Object {
"configurableOptions": Array [
Object {
"id": 157,
"optionLabel": "Fashion Color",
"valueId": "Y29uZmlndXJhYmxlLzE1Ny8zMQ==",
"valueLabel": "Peach",
},
Object {
"id": 190,
"optionLabel": "Fashion Size",
"valueId": "Y29uZmlndXJhYmxlLzE5MC80NA==",
"valueLabel": "M",
},
],
"formattedPrice": "",
"id": "MjQ4Mw==",
"prices": Object {
"__typename": "CartItemPrices",
"price": Object {
"__typename": "Money",
"currency": "USD",
"value": 48,
},
"row_total": Object {
"__typename": "Money",
"value": 144,
},
"total_item_discount": Object {
"__typename": "Money",
"value": 0,
},
},
"product": Object {
"canonicalUrl": "antonia-infinity-scarf",
"mainImageUrl": "https://master-7rqtwti-mfwmkrjfqvbjk.us-4.magentosite.cloud/media/catalog/product/cache/609faca36a4bc16a754bc2f43c184970/v/a/va04-ll_main_2.jpg",
"name": "Antonia Infinity Scarf",
"pricing": Object {
"currencyCode": "USD",
"maximalPrice": 48,
"minimalPrice": 48,
"regularPrice": 48,
},
"productType": "ConfigurableProduct",
"sku": "VA04",
},
"quantity": 3,
},
]
`;
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { getCartTotal, getCurrency, getFormattedProducts } from '../utils';

import mockEvent from '../handlers/__tests__/__mocks__/cartPageView';

describe('getCartTotal', () => {
it('returns the correct sum for a populated array', () => {
const total = getCartTotal(mockEvent.payload.products);

expect(total).toEqual(358);
});

it('returns zero for an empty array', () => {
const total = getCartTotal([]);

expect(total).toEqual(0);
});

it('returns zero for a null parameter', () => {
const total = getCartTotal();

expect(total).toEqual(0);
});
});

describe('getCurrency()', () => {
it('returns the correct currency code from the first array entry', () => {
const currency = getCurrency(mockEvent.payload.products);

expect(currency).toMatchInlineSnapshot(`"USD"`);
});

it('returns null if the array is empty or null', () => {
expect(getCurrency([])).toBeNull();
expect(getCurrency()).toBeNull();
});
});

describe('getFormattedProducts()', () => {
it('returns correctly formatted data', () => {
const formattedData = getFormattedProducts(mockEvent.payload.products);

expect(formattedData).toMatchSnapshot();
});

it('returns an empty array when given an empty array', () => {
expect(getFormattedProducts([])).toEqual([]);
});

it('returns null when given a null value', () => {
expect(getFormattedProducts()).toBeNull();
});
});
31 changes: 31 additions & 0 deletions packages/extensions/experience-platform-connector/src/config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { default as addToCartHandler } from './handlers/addToCart';
import { default as categoryPageViewHandler } from './handlers/categoryPageView';
import { default as completeCheckoutHandler } from './handlers/completeCheckout';
import { default as createAccountHandler } from './handlers/createAccount';
import { default as editAccountHandler } from './handlers/editAccount';
import { default as pageViewHandler } from './handlers/pageView';
import { default as placeOrderHandler } from './handlers/placeOrder';
import { default as productPageViewHandler } from './handlers/productPageView';
import { default as searchRequestSentHandler } from './handlers/searchRequestSent';
import { default as searchResponseReceivedHandler } from './handlers/searchResponseReceived';
import { default as shoppingCartPageViewHandler } from './handlers/shoppingCartPageView';
import { default as shoppingMiniCartViewHandler } from './handlers/shoppingMiniCartView';
import { default as startCheckoutHandler } from './handlers/startCheckout';
import { default as signInHandler } from './handlers/signIn';

export default [
addToCartHandler,
categoryPageViewHandler,
completeCheckoutHandler,
createAccountHandler,
editAccountHandler,
pageViewHandler,
placeOrderHandler,
productPageViewHandler,
searchRequestSentHandler,
searchResponseReceivedHandler,
shoppingCartPageViewHandler,
shoppingMiniCartViewHandler,
startCheckoutHandler,
signInHandler
];
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import handlers from './config';

export default (sdk, event) => {
handlers.forEach(({ canHandle, handle }) => {
if (canHandle(event)) {
handle(sdk, event);
}
});
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
export const addConfigurableProductEvent = {
type: 'CART_ADD_ITEM',
payload: {
cartId: 'kAR5Gg6uPC6J5wGY0ebecyKfX905epmU',
sku: 'VSK03',
name: 'Johanna Skirt',
priceTotal: 78,
currencyCode: 'USD',
discountAmount: 0,
selectedOptions: [
{
attribute: 'Fashion Color',
value: 'Peach'
},
{
attribute: 'Fashion Size',
value: 'M'
}
],
quantity: 1
}
};

export const addSimpleProductEvent = {
type: 'CART_ADD_ITEM',
payload: {
cartId: 'kAR5Gg6uPC6J5wGY0ebecyKfX905epmU',
sku: 'VA15-SI-NA',
name: 'Silver Sol Earrings',
priceTotal: 48,
currencyCode: 'USD',
discountAmount: 0,
selectedOptions: [],
quantity: 1
}
};
Loading

0 comments on commit a2b1668

Please sign in to comment.