Skip to content

Commit a2b1668

Browse files
jcalcabenrwalter215anthouladevpatil7
authored
Experience Platform Connector extension (#3885)
* 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 (#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 (#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 (#3892) * Make changes based on feedback Co-authored-by: Ryan Walter <r.walter215@gmail.com> Co-authored-by: Anthoula Wojczak <anthoula@users.noreply.github.com> Co-authored-by: Devagouda <40405790+dpatil-magento@users.noreply.github.com>
1 parent 80db006 commit a2b1668

File tree

65 files changed

+5271
-20
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

65 files changed

+5271
-20
lines changed

jest.config.js

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -315,7 +315,14 @@ const jestConfig = {
315315
),
316316
configureProject('pwa-theme-venia', 'Venia Theme', () => ({
317317
testEnvironment: 'node'
318-
}))
318+
})),
319+
configureProject(
320+
'extensions/experience-platform-connector',
321+
'Experience platform connector',
322+
() => ({
323+
testEnvironment: 'node'
324+
})
325+
)
319326
],
320327
// Include files with zero tests in overall coverage analysis by specifying
321328
// coverage paths manually.
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
module.exports = targets => {
2+
const { talons } = targets.of('@magento/peregrine');
3+
const { specialFeatures } = targets.of('@magento/pwa-buildpack');
4+
5+
specialFeatures.tap(flags => {
6+
/**
7+
* Wee need to activate esModules, cssModules and GQL Queries to allow build pack to load our extension
8+
* {@link https://magento.github.io/pwa-studio/pwa-buildpack/reference/configure-webpack/#special-flags}.
9+
*/
10+
flags[targets.name] = {
11+
esModules: true
12+
};
13+
});
14+
15+
talons.tap(({ App, Header, SearchBar }) => {
16+
App.useApp.wrapWith('@magento/experience-platform-connector');
17+
Header.useAccountMenu.wrapWith(
18+
'@magento/experience-platform-connector/src/wrappers/wrapUseAccountMenu'
19+
);
20+
SearchBar.useAutocomplete.wrapWith(
21+
'@magento/experience-platform-connector/src/wrappers/wrapUseAutocomplete'
22+
);
23+
});
24+
};
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
{
2+
"name": "@magento/experience-platform-connector",
3+
"version": "0.0.1",
4+
"publishConfig": {
5+
"access": "public"
6+
},
7+
"description": "Sends storefront events to the Adobe Experience Platform",
8+
"main": "./src/main.js",
9+
"scripts": {
10+
"clean": " "
11+
},
12+
"repository": "github:magento/pwa-studio",
13+
"license": "(OSL-3.0 OR AFL-3.0)",
14+
"dependencies": {
15+
"@adobe/magento-storefront-event-collector": "~1.1.13",
16+
"@adobe/magento-storefront-events-sdk": "~1.1.13"
17+
},
18+
"devDependencies": {},
19+
"peerDependencies": {
20+
"@apollo/client": "~3.6.6",
21+
"@magento/peregrine": "~12.3.0",
22+
"@magento/pwa-buildpack": "~11.2.0",
23+
"react": "~17.0.1"
24+
},
25+
"pwa-studio": {
26+
"targets": {
27+
"intercept": "./intercept"
28+
}
29+
}
30+
}
Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
// Jest Snapshot v1, https://goo.gl/fbAQLP
2+
3+
exports[`getFormattedProducts() returns correctly formatted data 1`] = `
4+
Array [
5+
Object {
6+
"configurableOptions": Array [
7+
Object {
8+
"id": 157,
9+
"optionLabel": "Fashion Color",
10+
"valueId": "Y29uZmlndXJhYmxlLzE1Ny8zMQ==",
11+
"valueLabel": "Peach",
12+
},
13+
Object {
14+
"id": 190,
15+
"optionLabel": "Fashion Size",
16+
"valueId": "Y29uZmlndXJhYmxlLzE5MC80Mw==",
17+
"valueLabel": "L",
18+
},
19+
],
20+
"formattedPrice": "",
21+
"id": "MjQ2Ng==",
22+
"prices": Object {
23+
"__typename": "CartItemPrices",
24+
"price": Object {
25+
"__typename": "Money",
26+
"currency": "USD",
27+
"value": 78,
28+
},
29+
"row_total": Object {
30+
"__typename": "Money",
31+
"value": 78,
32+
},
33+
"total_item_discount": Object {
34+
"__typename": "Money",
35+
"value": 0,
36+
},
37+
},
38+
"product": Object {
39+
"canonicalUrl": "rowena-skirt",
40+
"mainImageUrl": "https://master-7rqtwti-mfwmkrjfqvbjk.us-4.magentosite.cloud/media/catalog/product/cache/609faca36a4bc16a754bc2f43c184970/v/s/vsk02-ll_main_2.jpg",
41+
"name": "Rowena Skirt",
42+
"pricing": Object {
43+
"currencyCode": "USD",
44+
"maximalPrice": 78,
45+
"minimalPrice": 78,
46+
"regularPrice": 78,
47+
},
48+
"productType": "ConfigurableProduct",
49+
"sku": "VSK02",
50+
},
51+
"quantity": 1,
52+
},
53+
Object {
54+
"configurableOptions": null,
55+
"formattedPrice": "",
56+
"id": "MjQ4Mg==",
57+
"prices": Object {
58+
"__typename": "CartItemPrices",
59+
"price": Object {
60+
"__typename": "Money",
61+
"currency": "USD",
62+
"value": 68,
63+
},
64+
"row_total": Object {
65+
"__typename": "Money",
66+
"value": 136,
67+
},
68+
"total_item_discount": Object {
69+
"__typename": "Money",
70+
"value": 0,
71+
},
72+
},
73+
"product": Object {
74+
"canonicalUrl": "silver-cirque-earrings",
75+
"mainImageUrl": "https://master-7rqtwti-mfwmkrjfqvbjk.us-4.magentosite.cloud/media/catalog/product/cache/609faca36a4bc16a754bc2f43c184970/v/a/va17-si_main.jpg",
76+
"name": "Silver Cirque Earrings",
77+
"pricing": Object {
78+
"currencyCode": "USD",
79+
"maximalPrice": 68,
80+
"minimalPrice": 68,
81+
"regularPrice": 68,
82+
},
83+
"productType": "SimpleProduct",
84+
"sku": "VA17-SI-NA",
85+
},
86+
"quantity": 2,
87+
},
88+
Object {
89+
"configurableOptions": Array [
90+
Object {
91+
"id": 157,
92+
"optionLabel": "Fashion Color",
93+
"valueId": "Y29uZmlndXJhYmxlLzE1Ny8zMQ==",
94+
"valueLabel": "Peach",
95+
},
96+
Object {
97+
"id": 190,
98+
"optionLabel": "Fashion Size",
99+
"valueId": "Y29uZmlndXJhYmxlLzE5MC80NA==",
100+
"valueLabel": "M",
101+
},
102+
],
103+
"formattedPrice": "",
104+
"id": "MjQ4Mw==",
105+
"prices": Object {
106+
"__typename": "CartItemPrices",
107+
"price": Object {
108+
"__typename": "Money",
109+
"currency": "USD",
110+
"value": 48,
111+
},
112+
"row_total": Object {
113+
"__typename": "Money",
114+
"value": 144,
115+
},
116+
"total_item_discount": Object {
117+
"__typename": "Money",
118+
"value": 0,
119+
},
120+
},
121+
"product": Object {
122+
"canonicalUrl": "antonia-infinity-scarf",
123+
"mainImageUrl": "https://master-7rqtwti-mfwmkrjfqvbjk.us-4.magentosite.cloud/media/catalog/product/cache/609faca36a4bc16a754bc2f43c184970/v/a/va04-ll_main_2.jpg",
124+
"name": "Antonia Infinity Scarf",
125+
"pricing": Object {
126+
"currencyCode": "USD",
127+
"maximalPrice": 48,
128+
"minimalPrice": 48,
129+
"regularPrice": 48,
130+
},
131+
"productType": "ConfigurableProduct",
132+
"sku": "VA04",
133+
},
134+
"quantity": 3,
135+
},
136+
]
137+
`;
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import { getCartTotal, getCurrency, getFormattedProducts } from '../utils';
2+
3+
import mockEvent from '../handlers/__tests__/__mocks__/cartPageView';
4+
5+
describe('getCartTotal', () => {
6+
it('returns the correct sum for a populated array', () => {
7+
const total = getCartTotal(mockEvent.payload.products);
8+
9+
expect(total).toEqual(358);
10+
});
11+
12+
it('returns zero for an empty array', () => {
13+
const total = getCartTotal([]);
14+
15+
expect(total).toEqual(0);
16+
});
17+
18+
it('returns zero for a null parameter', () => {
19+
const total = getCartTotal();
20+
21+
expect(total).toEqual(0);
22+
});
23+
});
24+
25+
describe('getCurrency()', () => {
26+
it('returns the correct currency code from the first array entry', () => {
27+
const currency = getCurrency(mockEvent.payload.products);
28+
29+
expect(currency).toMatchInlineSnapshot(`"USD"`);
30+
});
31+
32+
it('returns null if the array is empty or null', () => {
33+
expect(getCurrency([])).toBeNull();
34+
expect(getCurrency()).toBeNull();
35+
});
36+
});
37+
38+
describe('getFormattedProducts()', () => {
39+
it('returns correctly formatted data', () => {
40+
const formattedData = getFormattedProducts(mockEvent.payload.products);
41+
42+
expect(formattedData).toMatchSnapshot();
43+
});
44+
45+
it('returns an empty array when given an empty array', () => {
46+
expect(getFormattedProducts([])).toEqual([]);
47+
});
48+
49+
it('returns null when given a null value', () => {
50+
expect(getFormattedProducts()).toBeNull();
51+
});
52+
});
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import { default as addToCartHandler } from './handlers/addToCart';
2+
import { default as categoryPageViewHandler } from './handlers/categoryPageView';
3+
import { default as completeCheckoutHandler } from './handlers/completeCheckout';
4+
import { default as createAccountHandler } from './handlers/createAccount';
5+
import { default as editAccountHandler } from './handlers/editAccount';
6+
import { default as pageViewHandler } from './handlers/pageView';
7+
import { default as placeOrderHandler } from './handlers/placeOrder';
8+
import { default as productPageViewHandler } from './handlers/productPageView';
9+
import { default as searchRequestSentHandler } from './handlers/searchRequestSent';
10+
import { default as searchResponseReceivedHandler } from './handlers/searchResponseReceived';
11+
import { default as shoppingCartPageViewHandler } from './handlers/shoppingCartPageView';
12+
import { default as shoppingMiniCartViewHandler } from './handlers/shoppingMiniCartView';
13+
import { default as startCheckoutHandler } from './handlers/startCheckout';
14+
import { default as signInHandler } from './handlers/signIn';
15+
16+
export default [
17+
addToCartHandler,
18+
categoryPageViewHandler,
19+
completeCheckoutHandler,
20+
createAccountHandler,
21+
editAccountHandler,
22+
pageViewHandler,
23+
placeOrderHandler,
24+
productPageViewHandler,
25+
searchRequestSentHandler,
26+
searchResponseReceivedHandler,
27+
shoppingCartPageViewHandler,
28+
shoppingMiniCartViewHandler,
29+
startCheckoutHandler,
30+
signInHandler
31+
];
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import handlers from './config';
2+
3+
export default (sdk, event) => {
4+
handlers.forEach(({ canHandle, handle }) => {
5+
if (canHandle(event)) {
6+
handle(sdk, event);
7+
}
8+
});
9+
};
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
export const addConfigurableProductEvent = {
2+
type: 'CART_ADD_ITEM',
3+
payload: {
4+
cartId: 'kAR5Gg6uPC6J5wGY0ebecyKfX905epmU',
5+
sku: 'VSK03',
6+
name: 'Johanna Skirt',
7+
priceTotal: 78,
8+
currencyCode: 'USD',
9+
discountAmount: 0,
10+
selectedOptions: [
11+
{
12+
attribute: 'Fashion Color',
13+
value: 'Peach'
14+
},
15+
{
16+
attribute: 'Fashion Size',
17+
value: 'M'
18+
}
19+
],
20+
quantity: 1
21+
}
22+
};
23+
24+
export const addSimpleProductEvent = {
25+
type: 'CART_ADD_ITEM',
26+
payload: {
27+
cartId: 'kAR5Gg6uPC6J5wGY0ebecyKfX905epmU',
28+
sku: 'VA15-SI-NA',
29+
name: 'Silver Sol Earrings',
30+
priceTotal: 48,
31+
currencyCode: 'USD',
32+
discountAmount: 0,
33+
selectedOptions: [],
34+
quantity: 1
35+
}
36+
};

0 commit comments

Comments
 (0)