Skip to content

Commit 0836057

Browse files
committed
chore: address comments and update the legacy file size
1 parent a30488d commit 0836057

3 files changed

Lines changed: 50 additions & 15 deletions

File tree

packages/analytics-js-integrations/.size-limit.mjs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ export default [
66
{
77
name: 'All Integrations - Legacy - CDN',
88
path: 'dist/cdn/legacy/js-integrations/*.min.js',
9-
limit: '97 KiB',
9+
limit: '98.5 KiB',
1010
},
1111
{
1212
name: 'All Integrations - Modern - CDN',

packages/analytics-js-integrations/__tests__/integrations/Braze/browser.test.js

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1413,6 +1413,38 @@ describe('track - recommended ecommerce events', () => {
14131413
expect(window.braze.logCustomEvent.mock.calls[0][1].source).toBe('ios');
14141414
});
14151415

1416+
it('honors an explicit properties.source with surrounding whitespace', () => {
1417+
const braze = buildBraze();
1418+
trackEvent(braze, 'Product Viewed', {
1419+
product_id: 'p1',
1420+
name: 'Game',
1421+
variant: 'v1',
1422+
price: 15.99,
1423+
currency: 'USD',
1424+
source: 'ios ',
1425+
});
1426+
1427+
expect(window.braze.logCustomEvent.mock.calls[0][1].source).toBe('ios');
1428+
});
1429+
1430+
it('warns and scrubs a required field provided as an empty object', () => {
1431+
const braze = buildBraze();
1432+
trackEvent(braze, 'Product Viewed', {
1433+
product_id: 'p1',
1434+
name: 'Game',
1435+
variant: 'v1',
1436+
price: 15.99,
1437+
currency: {},
1438+
});
1439+
1440+
expect(window.braze.logCustomEvent).toHaveBeenCalledTimes(1);
1441+
// empty-object required value is reported as missing...
1442+
expect(warnMock).toHaveBeenCalledTimes(1);
1443+
expect(warnMock.mock.calls[0][0]).toContain('currency');
1444+
// ...and never reaches the sent payload.
1445+
expect(window.braze.logCustomEvent.mock.calls[0][1]).not.toHaveProperty('currency');
1446+
});
1447+
14161448
it('falls through to legacy custom-event path for unmapped events (Cart Updated)', () => {
14171449
const braze = buildBraze();
14181450
trackEvent(braze, 'Cart Updated', { cart_id: 'c1', value: 10 });

packages/analytics-js-integrations/src/integrations/Braze/ecommerceUtil.js

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
import { constructPayload } from '../../utils/utils';
2-
import { removeUndefinedAndNullAndEmptyValues } from '../../utils/commonUtils';
2+
import {
3+
isDefinedAndNotNullAndNotEmpty,
4+
removeUndefinedAndNullAndEmptyValues,
5+
} from '../../utils/commonUtils';
36

47
/**
58
* Braze recommended ecommerce event names.
@@ -131,14 +134,13 @@ const PER_EVENT_MAPPING = {
131134
// ---------------------------------------------------------------------------
132135

133136
/**
134-
* Mirror `constructPayload`'s truthiness rule: `0` and `false` are valid values; only
135-
* undefined/null/empty-string count as missing.
137+
* A field counts as "resolved" iff it survives the outgoing payload scrub
138+
* (`removeUndefinedAndNullAndEmptyValues`). Reuse that exact predicate so the
139+
* missing-required-field warning can never drift from what's actually sent — e.g. a
140+
* required field of `{}`/`[]`/`''` is both stripped from the payload AND warned, while
141+
* `0`/`false`/numbers stay valid.
136142
*/
137-
const isResolvedValue = value => {
138-
if (value === 0 || value === false) return true;
139-
if (value === undefined || value === null) return false;
140-
return !(typeof value === 'string' && value.length === 0);
141-
};
143+
const isResolvedValue = isDefinedAndNotNullAndNotEmpty;
142144

143145
/**
144146
* Return the subset of `source` whose keys are not in `consumed`, with undefined/null/empty
@@ -201,10 +203,7 @@ const consumedTopLevelKeysForEvent = (brazeEvent, eventMapping, hasProducts, pro
201203
// explicit `products[]` is provided; in that case mark those keys as consumed so they
202204
// don't duplicate into event-level metadata. When `products[]` is present, the top-level
203205
// fields are untouched and must flow through to metadata.
204-
if (
205-
brazeEvent === BRAZE_ECOMMERCE_EVENTS.CART_UPDATED &&
206-
!Array.isArray(properties.products)
207-
) {
206+
if (brazeEvent === BRAZE_ECOMMERCE_EVENTS.CART_UPDATED && !Array.isArray(properties.products)) {
208207
consumedKeysFromMapping(ECOMMERCE_PRODUCT_MAPPING).forEach(key => consumed.add(key));
209208
}
210209

@@ -300,11 +299,15 @@ export const getEcommerceMapping = eventName => {
300299
/**
301300
* Derive the Braze `source` field. On the web SDK this resolves to `'web'`, unless the
302301
* event carries an explicit, valid `properties.source` (`web`/`ios`/`android`), which
303-
* takes precedence. Always returns one of Braze's enum values; never undefined.
302+
* takes precedence. The explicit value is trimmed and lowercased before matching, so
303+
* surrounding whitespace doesn't defeat it. Always returns one of Braze's enum values;
304+
* never undefined.
304305
*/
305306
export const deriveSource = message => {
306307
const properties = message.properties || {};
307-
const explicit = String(properties.source || '').toLowerCase();
308+
const explicit = String(properties.source || '')
309+
.trim()
310+
.toLowerCase();
308311
if (BRAZE_SOURCE_VALUES.indexOf(explicit) !== -1) {
309312
return explicit;
310313
}

0 commit comments

Comments
 (0)