@bytem/bytem-tracker-app 0.0.16 → 0.0.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +71 -9
- package/dist/package.json +1 -1
- package/dist/src/BytemTracker.d.ts +22 -2
- package/dist/src/BytemTracker.js +99 -16
- package/dist/src/business/index.d.ts +3 -1
- package/dist/src/business/index.js +3 -1
- package/dist/src/business/trackAddToCart.d.ts +2 -0
- package/dist/src/business/trackAddToCart.js +18 -0
- package/dist/src/business/trackAddWishlist.d.ts +2 -0
- package/dist/src/business/trackAddWishlist.js +18 -0
- package/dist/src/business/trackCheckOutOrder.d.ts +1 -1
- package/dist/src/business/trackCheckOutOrder.js +9 -10
- package/dist/src/business/trackGoodsImpression.d.ts +2 -0
- package/dist/src/business/trackGoodsImpression.js +22 -0
- package/dist/src/business/trackPayOrder.js +1 -2
- package/dist/src/types.d.ts +1 -0
- package/dist/test/BytemTracker.test.js +5 -5
- package/dist/test/addToCart.test.d.ts +1 -0
- package/dist/test/addToCart.test.js +65 -0
- package/dist/test/additionalMethods.test.d.ts +1 -0
- package/dist/test/additionalMethods.test.js +72 -0
- package/dist/test/goodsImpression.test.d.ts +1 -0
- package/dist/test/goodsImpression.test.js +70 -0
- package/dist/test/setup.js +0 -7
- package/package.json +1 -1
- package/dist/src/business/trackUser.d.ts +0 -2
- package/dist/src/business/trackUser.js +0 -13
package/README.md
CHANGED
|
@@ -4,10 +4,13 @@ This is the official Bytem Tracker SDK for React Native applications.
|
|
|
4
4
|
|
|
5
5
|
## Installation
|
|
6
6
|
|
|
7
|
-
Install the package
|
|
7
|
+
Install the package using Yarn:
|
|
8
8
|
|
|
9
9
|
```bash
|
|
10
|
-
|
|
10
|
+
# need
|
|
11
|
+
yarn add @bytem/bytem-tracker-app
|
|
12
|
+
# if not
|
|
13
|
+
yarn add @react-native-async-storage/async-storage
|
|
11
14
|
```
|
|
12
15
|
|
|
13
16
|
### iOS Setup
|
|
@@ -31,7 +34,7 @@ const App = () => {
|
|
|
31
34
|
await BytemTracker.init({
|
|
32
35
|
appKey: 'your-app-key',
|
|
33
36
|
endpoint: 'https://api.bytem.com/track',
|
|
34
|
-
debug:
|
|
37
|
+
debug: false, // Enable debug logs in development
|
|
35
38
|
});
|
|
36
39
|
};
|
|
37
40
|
|
|
@@ -44,15 +47,17 @@ const App = () => {
|
|
|
44
47
|
|
|
45
48
|
### Tracking Events
|
|
46
49
|
|
|
47
|
-
####
|
|
48
|
-
|
|
50
|
+
#### Set User Details
|
|
51
|
+
Update user profile information.
|
|
49
52
|
|
|
50
53
|
```typescript
|
|
51
54
|
// Signature: trackUser(userId: string, traits?: object)
|
|
52
55
|
await BytemTracker.trackUser('user_12345', {
|
|
53
56
|
email: 'user@example.com',
|
|
54
|
-
|
|
55
|
-
|
|
57
|
+
name: 'John Doe',
|
|
58
|
+
custom: {
|
|
59
|
+
membership: 'gold'
|
|
60
|
+
}
|
|
56
61
|
});
|
|
57
62
|
```
|
|
58
63
|
|
|
@@ -65,7 +70,65 @@ await BytemTracker.trackViewProduct({
|
|
|
65
70
|
name: 'Awesome Gadget',
|
|
66
71
|
price: 99.99,
|
|
67
72
|
currency: 'USD',
|
|
68
|
-
category: 'Electronics'
|
|
73
|
+
category: 'Electronics',
|
|
74
|
+
url: 'https://example.com/products/prod-001'
|
|
75
|
+
});
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
#### Add To Cart
|
|
79
|
+
Track when a user adds a product to their shopping cart.
|
|
80
|
+
|
|
81
|
+
```typescript
|
|
82
|
+
await BytemTracker.trackAddToCart({
|
|
83
|
+
productId: 'prod_001',
|
|
84
|
+
name: 'Awesome Gadget',
|
|
85
|
+
price: 99.99,
|
|
86
|
+
currency: 'USD',
|
|
87
|
+
category: 'Electronics',
|
|
88
|
+
url: 'https://example.com/products/prod-001',
|
|
89
|
+
quantity: 1
|
|
90
|
+
});
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
#### Add To Wishlist
|
|
94
|
+
Track when a user adds a product to their wishlist.
|
|
95
|
+
|
|
96
|
+
```typescript
|
|
97
|
+
await BytemTracker.trackAddWishlist({
|
|
98
|
+
productId: 'prod_001',
|
|
99
|
+
name: 'Awesome Gadget',
|
|
100
|
+
price: 99.99,
|
|
101
|
+
currency: 'USD',
|
|
102
|
+
category: 'Electronics',
|
|
103
|
+
url: 'https://example.com/products/prod-001'
|
|
104
|
+
});
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
#### Goods Impression
|
|
108
|
+
Track when a list of products is displayed to the user.
|
|
109
|
+
|
|
110
|
+
```typescript
|
|
111
|
+
const products = [
|
|
112
|
+
{ productId: 'prod_001', url: 'https://example.com/p/1' },
|
|
113
|
+
{ productId: 'prod_002', url: 'https://example.com/p/2' }
|
|
114
|
+
];
|
|
115
|
+
|
|
116
|
+
await BytemTracker.trackGoodsImpression(
|
|
117
|
+
products,
|
|
118
|
+
'Home Page', // Source
|
|
119
|
+
'Recommended For You' // Position (optional)
|
|
120
|
+
);
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
#### Goods Click
|
|
124
|
+
Track when a user clicks on a product.
|
|
125
|
+
|
|
126
|
+
```typescript
|
|
127
|
+
await BytemTracker.trackGoodsClick({
|
|
128
|
+
gid: 'prod_001', // Product ID
|
|
129
|
+
url: 'https://example.com/p/1',
|
|
130
|
+
source: 'Home Page',
|
|
131
|
+
position: '1'
|
|
69
132
|
});
|
|
70
133
|
```
|
|
71
134
|
|
|
@@ -107,4 +170,3 @@ This SDK is designed for **React Native** and supports:
|
|
|
107
170
|
|
|
108
171
|
It relies on:
|
|
109
172
|
- `@react-native-async-storage/async-storage`: For persisting session and visitor IDs.
|
|
110
|
-
- `react-native-device-info`: For capturing device metrics (model, OS version, etc.).
|
package/dist/package.json
CHANGED
|
@@ -111,14 +111,34 @@ declare class BytemTracker {
|
|
|
111
111
|
* @param product - The product object to track.
|
|
112
112
|
*/
|
|
113
113
|
trackViewProduct(product: Product): Promise<void>;
|
|
114
|
+
/**
|
|
115
|
+
* Tracks an add-to-cart event.
|
|
116
|
+
*
|
|
117
|
+
* @param product - The product added to cart.
|
|
118
|
+
*/
|
|
119
|
+
trackAddToCart(product: Product): Promise<void>;
|
|
120
|
+
/**
|
|
121
|
+
* Track goods impression (e.g. collection page view)
|
|
122
|
+
* @param products List of products displayed
|
|
123
|
+
* @param source Source page/section
|
|
124
|
+
* @param position Position in the list/page
|
|
125
|
+
*/
|
|
126
|
+
trackGoodsImpression(products: Product[], source?: string, position?: string): Promise<void>;
|
|
127
|
+
/**
|
|
128
|
+
* Tracks an add-to-wishlist event.
|
|
129
|
+
* @param product - The product added to wishlist.
|
|
130
|
+
*/
|
|
131
|
+
trackAddWishlist(product: Product): Promise<void>;
|
|
114
132
|
/**
|
|
115
133
|
* Tracks a checkout order event.
|
|
116
|
-
* Automatically splits product lists into parallel arrays (
|
|
134
|
+
* Automatically splits product lists into parallel arrays (gid, price, quantity)
|
|
117
135
|
* to match the backend requirement.
|
|
118
136
|
*
|
|
119
137
|
* @param order - The order object containing products to checkout.
|
|
138
|
+
* @param source - Source page/section
|
|
139
|
+
* @param position - Position info
|
|
120
140
|
*/
|
|
121
|
-
trackCheckOutOrder(order: Order): Promise<void>;
|
|
141
|
+
trackCheckOutOrder(order: Order, source?: string, position?: string): Promise<void>;
|
|
122
142
|
/**
|
|
123
143
|
* Tracks a payment order event.
|
|
124
144
|
* Maps product list to a 'goods' array structure expected by the backend.
|
package/dist/src/BytemTracker.js
CHANGED
|
@@ -1,6 +1,40 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
2
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
36
|
const types_1 = require("./types");
|
|
37
|
+
const Business = __importStar(require("./business"));
|
|
4
38
|
const storage_1 = require("./core/storage");
|
|
5
39
|
const device_1 = require("./core/device");
|
|
6
40
|
const package_json_1 = require("../package.json");
|
|
@@ -574,31 +608,80 @@ class BytemTracker {
|
|
|
574
608
|
console.error('[BytemTracker] Error in trackViewProduct:', e);
|
|
575
609
|
}
|
|
576
610
|
}
|
|
611
|
+
/**
|
|
612
|
+
* Tracks an add-to-cart event.
|
|
613
|
+
*
|
|
614
|
+
* @param product - The product added to cart.
|
|
615
|
+
*/
|
|
616
|
+
async trackAddToCart(product) {
|
|
617
|
+
try {
|
|
618
|
+
if (!this.checkInitialized())
|
|
619
|
+
return;
|
|
620
|
+
const segmentation = {
|
|
621
|
+
gid: product.productId,
|
|
622
|
+
name: product.name,
|
|
623
|
+
price: product.price,
|
|
624
|
+
currency: product.currency,
|
|
625
|
+
category: product.category,
|
|
626
|
+
quantity: product.quantity || 1,
|
|
627
|
+
url: product.url,
|
|
628
|
+
};
|
|
629
|
+
await this.trackEvent('add_to_cart', segmentation);
|
|
630
|
+
}
|
|
631
|
+
catch (e) {
|
|
632
|
+
if (this.debug)
|
|
633
|
+
console.error('[BytemTracker] Error in trackAddToCart:', e);
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
/**
|
|
637
|
+
* Track goods impression (e.g. collection page view)
|
|
638
|
+
* @param products List of products displayed
|
|
639
|
+
* @param source Source page/section
|
|
640
|
+
* @param position Position in the list/page
|
|
641
|
+
*/
|
|
642
|
+
async trackGoodsImpression(products, source, position) {
|
|
643
|
+
try {
|
|
644
|
+
if (!this.checkInitialized())
|
|
645
|
+
return;
|
|
646
|
+
const payload = Business.trackGoodsImpression(products, source, position);
|
|
647
|
+
await this.trackEvent(payload.event, payload.params);
|
|
648
|
+
}
|
|
649
|
+
catch (e) {
|
|
650
|
+
if (this.debug)
|
|
651
|
+
console.error('[BytemTracker] Error in trackGoodsImpression:', e);
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
/**
|
|
655
|
+
* Tracks an add-to-wishlist event.
|
|
656
|
+
* @param product - The product added to wishlist.
|
|
657
|
+
*/
|
|
658
|
+
async trackAddWishlist(product) {
|
|
659
|
+
try {
|
|
660
|
+
if (!this.checkInitialized())
|
|
661
|
+
return;
|
|
662
|
+
const payload = Business.trackAddWishlist(product);
|
|
663
|
+
await this.trackEvent(payload.event, payload.params);
|
|
664
|
+
}
|
|
665
|
+
catch (e) {
|
|
666
|
+
if (this.debug)
|
|
667
|
+
console.error('[BytemTracker] Error in trackAddWishlist:', e);
|
|
668
|
+
}
|
|
669
|
+
}
|
|
577
670
|
/**
|
|
578
671
|
* Tracks a checkout order event.
|
|
579
|
-
* Automatically splits product lists into parallel arrays (
|
|
672
|
+
* Automatically splits product lists into parallel arrays (gid, price, quantity)
|
|
580
673
|
* to match the backend requirement.
|
|
581
674
|
*
|
|
582
675
|
* @param order - The order object containing products to checkout.
|
|
676
|
+
* @param source - Source page/section
|
|
677
|
+
* @param position - Position info
|
|
583
678
|
*/
|
|
584
|
-
async trackCheckOutOrder(order) {
|
|
679
|
+
async trackCheckOutOrder(order, source, position) {
|
|
585
680
|
try {
|
|
586
681
|
if (!this.checkInitialized())
|
|
587
682
|
return;
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
order_id: order.orderId,
|
|
591
|
-
total: order.total,
|
|
592
|
-
currency: order.currency,
|
|
593
|
-
};
|
|
594
|
-
if (order.products && order.products.length > 0) {
|
|
595
|
-
segmentation.gids = order.products.map(p => p.productId);
|
|
596
|
-
segmentation.prices = order.products.map(p => p.price);
|
|
597
|
-
segmentation.quantity = order.products.map(p => p.quantity || 1);
|
|
598
|
-
// Optional: skuids if available in Product type, currently not in interface but good to handle if extended
|
|
599
|
-
// segmentation.skuids = ...
|
|
600
|
-
}
|
|
601
|
-
await this.trackEvent('check_out_order', segmentation);
|
|
683
|
+
const payload = Business.trackCheckOutOrder(order, source, position);
|
|
684
|
+
await this.trackEvent(payload.event, payload.params);
|
|
602
685
|
}
|
|
603
686
|
catch (e) {
|
|
604
687
|
if (this.debug)
|
|
@@ -15,6 +15,8 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
17
|
__exportStar(require("./trackViewProduct"), exports);
|
|
18
|
+
__exportStar(require("./trackAddToCart"), exports);
|
|
18
19
|
__exportStar(require("./trackCheckOutOrder"), exports);
|
|
19
20
|
__exportStar(require("./trackPayOrder"), exports);
|
|
20
|
-
__exportStar(require("./
|
|
21
|
+
__exportStar(require("./trackGoodsImpression"), exports);
|
|
22
|
+
__exportStar(require("./trackAddWishlist"), exports);
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.trackAddToCart = void 0;
|
|
4
|
+
const trackAddToCart = (product) => {
|
|
5
|
+
return {
|
|
6
|
+
event: 'add_to_cart',
|
|
7
|
+
params: {
|
|
8
|
+
gid: product.productId,
|
|
9
|
+
name: product.name,
|
|
10
|
+
price: product.price,
|
|
11
|
+
currency: product.currency,
|
|
12
|
+
category: product.category,
|
|
13
|
+
quantity: product.quantity || 1,
|
|
14
|
+
url: product.url,
|
|
15
|
+
},
|
|
16
|
+
};
|
|
17
|
+
};
|
|
18
|
+
exports.trackAddToCart = trackAddToCart;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.trackAddWishlist = void 0;
|
|
4
|
+
const trackAddWishlist = (product) => {
|
|
5
|
+
return {
|
|
6
|
+
event: 'add_wishlist',
|
|
7
|
+
params: {
|
|
8
|
+
gid: product.productId,
|
|
9
|
+
name: product.name,
|
|
10
|
+
price: product.price,
|
|
11
|
+
currency: product.currency,
|
|
12
|
+
category: product.category,
|
|
13
|
+
quantity: product.quantity || 1,
|
|
14
|
+
url: product.url,
|
|
15
|
+
},
|
|
16
|
+
};
|
|
17
|
+
};
|
|
18
|
+
exports.trackAddWishlist = trackAddWishlist;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import { EventPayload, Order } from '../types';
|
|
2
|
-
export declare const trackCheckOutOrder: (order: Order) => EventPayload;
|
|
2
|
+
export declare const trackCheckOutOrder: (order: Order, source?: string, position?: string) => EventPayload;
|
|
@@ -1,19 +1,18 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.trackCheckOutOrder = void 0;
|
|
4
|
-
const trackCheckOutOrder = (order) => {
|
|
4
|
+
const trackCheckOutOrder = (order, source, position) => {
|
|
5
5
|
return {
|
|
6
|
-
event: '
|
|
6
|
+
event: 'check_out_order',
|
|
7
7
|
params: {
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
gid: order.products.map(p => p.productId),
|
|
9
|
+
url: order.products.map(p => p.url || ''),
|
|
10
|
+
price: order.products.map(p => p.price || 0),
|
|
11
|
+
quantity: order.products.map(p => p.quantity || 1),
|
|
12
|
+
amount: order.total,
|
|
10
13
|
currency: order.currency,
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
name: p.name,
|
|
14
|
-
price: p.price,
|
|
15
|
-
quantity: p.quantity,
|
|
16
|
-
})),
|
|
14
|
+
source: source || 'Other Page',
|
|
15
|
+
position: position || ''
|
|
17
16
|
},
|
|
18
17
|
};
|
|
19
18
|
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.trackGoodsImpression = void 0;
|
|
4
|
+
const trackGoodsImpression = (products, source, position) => {
|
|
5
|
+
const gids = products.map(p => p.productId);
|
|
6
|
+
const urls = products.map(p => p.url || '');
|
|
7
|
+
// Currently Product doesn't have skuid, so we leave it empty or undefined?
|
|
8
|
+
// dart/main.js: "skuid": skuids != null ? skuids : [],
|
|
9
|
+
return {
|
|
10
|
+
event: 'goods_impression',
|
|
11
|
+
params: {
|
|
12
|
+
gid: gids,
|
|
13
|
+
skuid: [], // Empty for now as not in Product interface
|
|
14
|
+
urls: urls,
|
|
15
|
+
source: source || 'Other Page', // Default from dart/main.js? line 7: source= 'Other Page'
|
|
16
|
+
position: position || '',
|
|
17
|
+
// visitor_id, ab, realab are handled by BytemTracker automatically or need to be passed?
|
|
18
|
+
// BytemTracker usually handles common params like visitor_id.
|
|
19
|
+
},
|
|
20
|
+
};
|
|
21
|
+
};
|
|
22
|
+
exports.trackGoodsImpression = trackGoodsImpression;
|
package/dist/src/types.d.ts
CHANGED
|
@@ -226,12 +226,12 @@ describe('BytemTracker SDK', () => {
|
|
|
226
226
|
const events = JSON.parse(new URLSearchParams(eventCall[1].body).get('events') || '[]');
|
|
227
227
|
expect(events[0].key).toBe('check_out_order');
|
|
228
228
|
expect(events[0].segmentation).toMatchObject({
|
|
229
|
-
|
|
230
|
-
|
|
229
|
+
gid: ['prod_1', 'prod_2'],
|
|
230
|
+
price: [50, 49.99],
|
|
231
|
+
quantity: [1, 1],
|
|
232
|
+
amount: 99.99,
|
|
231
233
|
currency: 'USD',
|
|
232
|
-
|
|
233
|
-
prices: [50, 49.99],
|
|
234
|
-
quantity: [1, 1]
|
|
234
|
+
url: ['', '']
|
|
235
235
|
});
|
|
236
236
|
});
|
|
237
237
|
it('should track view product', async () => {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const BytemTracker_1 = __importDefault(require("../src/BytemTracker"));
|
|
7
|
+
const async_storage_1 = __importDefault(require("@react-native-async-storage/async-storage"));
|
|
8
|
+
describe('BytemTracker Add To Cart', () => {
|
|
9
|
+
const mockConfig = {
|
|
10
|
+
appKey: 'test-app-id',
|
|
11
|
+
endpoint: 'https://api.example.com/track',
|
|
12
|
+
debug: true,
|
|
13
|
+
};
|
|
14
|
+
beforeEach(async () => {
|
|
15
|
+
jest.clearAllMocks();
|
|
16
|
+
// Reset singleton
|
|
17
|
+
// @ts-ignore
|
|
18
|
+
BytemTracker_1.default.isInitialized = false;
|
|
19
|
+
// @ts-ignore
|
|
20
|
+
async_storage_1.default.clear();
|
|
21
|
+
await BytemTracker_1.default.init(mockConfig);
|
|
22
|
+
});
|
|
23
|
+
it('should track add_to_cart event correctly', async () => {
|
|
24
|
+
const product = {
|
|
25
|
+
productId: 'p_1001',
|
|
26
|
+
name: 'Test Product',
|
|
27
|
+
price: 99.99,
|
|
28
|
+
currency: 'USD',
|
|
29
|
+
category: 'Electronics',
|
|
30
|
+
quantity: 2,
|
|
31
|
+
url: 'https://example.com/product/p_1001'
|
|
32
|
+
};
|
|
33
|
+
await BytemTracker_1.default.trackAddToCart(product);
|
|
34
|
+
expect(global.fetch).toHaveBeenCalled();
|
|
35
|
+
const calls = global.fetch.mock.calls;
|
|
36
|
+
const body = calls[calls.length - 1][1].body;
|
|
37
|
+
// Decode body to check params
|
|
38
|
+
const params = new URLSearchParams(body);
|
|
39
|
+
const eventsJson = params.get('events');
|
|
40
|
+
const events = JSON.parse(eventsJson);
|
|
41
|
+
expect(events[0].key).toBe('add_to_cart');
|
|
42
|
+
expect(events[0].segmentation).toEqual({
|
|
43
|
+
gid: 'p_1001',
|
|
44
|
+
name: 'Test Product',
|
|
45
|
+
price: 99.99,
|
|
46
|
+
currency: 'USD',
|
|
47
|
+
category: 'Electronics',
|
|
48
|
+
quantity: 2,
|
|
49
|
+
url: 'https://example.com/product/p_1001'
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
it('should use default quantity of 1 if not provided', async () => {
|
|
53
|
+
const product = {
|
|
54
|
+
productId: 'p_1002',
|
|
55
|
+
name: 'Single Product',
|
|
56
|
+
price: 10.00,
|
|
57
|
+
};
|
|
58
|
+
await BytemTracker_1.default.trackAddToCart(product);
|
|
59
|
+
const calls = global.fetch.mock.calls;
|
|
60
|
+
const body = calls[calls.length - 1][1].body;
|
|
61
|
+
const params = new URLSearchParams(body);
|
|
62
|
+
const events = JSON.parse(params.get('events'));
|
|
63
|
+
expect(events[0].segmentation.quantity).toBe(1);
|
|
64
|
+
});
|
|
65
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const BytemTracker_1 = __importDefault(require("../src/BytemTracker"));
|
|
7
|
+
// Mock global fetch
|
|
8
|
+
global.fetch = jest.fn(() => Promise.resolve({
|
|
9
|
+
ok: true,
|
|
10
|
+
status: 200,
|
|
11
|
+
json: () => Promise.resolve({ status: 'success' }),
|
|
12
|
+
text: () => Promise.resolve('{"status":"success"}'),
|
|
13
|
+
}));
|
|
14
|
+
describe('BytemTracker Additional Methods', () => {
|
|
15
|
+
const mockConfig = {
|
|
16
|
+
appKey: 'test-app-id',
|
|
17
|
+
endpoint: 'https://api.example.com',
|
|
18
|
+
debug: true,
|
|
19
|
+
};
|
|
20
|
+
beforeEach(() => {
|
|
21
|
+
jest.clearAllMocks();
|
|
22
|
+
BytemTracker_1.default.init(mockConfig);
|
|
23
|
+
});
|
|
24
|
+
it('should track add_wishlist event correctly', async () => {
|
|
25
|
+
const product = {
|
|
26
|
+
productId: 'p_wish_1',
|
|
27
|
+
name: 'Wish Product',
|
|
28
|
+
price: 50.00,
|
|
29
|
+
url: 'https://example.com/wish'
|
|
30
|
+
};
|
|
31
|
+
await BytemTracker_1.default.trackAddWishlist(product);
|
|
32
|
+
expect(global.fetch).toHaveBeenCalled();
|
|
33
|
+
const calls = global.fetch.mock.calls;
|
|
34
|
+
const body = calls[calls.length - 1][1].body;
|
|
35
|
+
const params = new URLSearchParams(body);
|
|
36
|
+
const eventsJson = params.get('events');
|
|
37
|
+
const events = JSON.parse(eventsJson);
|
|
38
|
+
expect(events[0].key).toBe('add_wishlist');
|
|
39
|
+
expect(events[0].segmentation).toMatchObject({
|
|
40
|
+
gid: 'p_wish_1',
|
|
41
|
+
url: 'https://example.com/wish',
|
|
42
|
+
name: 'Wish Product'
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
it('should track check_out_order event correctly', async () => {
|
|
46
|
+
const order = {
|
|
47
|
+
orderId: 'order_123',
|
|
48
|
+
total: 150.00,
|
|
49
|
+
currency: 'USD',
|
|
50
|
+
products: [
|
|
51
|
+
{ productId: 'p_1', price: 100.00, quantity: 1, url: 'https://example.com/p1' },
|
|
52
|
+
{ productId: 'p_2', price: 50.00, quantity: 1, url: 'https://example.com/p2' }
|
|
53
|
+
]
|
|
54
|
+
};
|
|
55
|
+
await BytemTracker_1.default.trackCheckOutOrder(order, 'Cart Page', 'Checkout Button');
|
|
56
|
+
expect(global.fetch).toHaveBeenCalled();
|
|
57
|
+
const calls = global.fetch.mock.calls;
|
|
58
|
+
const body = calls[calls.length - 1][1].body;
|
|
59
|
+
const params = new URLSearchParams(body);
|
|
60
|
+
const eventsJson = params.get('events');
|
|
61
|
+
const events = JSON.parse(eventsJson);
|
|
62
|
+
expect(events[0].key).toBe('check_out_order');
|
|
63
|
+
expect(events[0].segmentation).toMatchObject({
|
|
64
|
+
gid: ['p_1', 'p_2'],
|
|
65
|
+
url: ['https://example.com/p1', 'https://example.com/p2'],
|
|
66
|
+
price: [100.00, 50.00],
|
|
67
|
+
amount: 150.00,
|
|
68
|
+
source: 'Cart Page',
|
|
69
|
+
position: 'Checkout Button'
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const BytemTracker_1 = __importDefault(require("../src/BytemTracker"));
|
|
7
|
+
// Mock global fetch
|
|
8
|
+
global.fetch = jest.fn(() => Promise.resolve({
|
|
9
|
+
ok: true,
|
|
10
|
+
status: 200,
|
|
11
|
+
json: () => Promise.resolve({ status: 'success' }),
|
|
12
|
+
text: () => Promise.resolve('ok'),
|
|
13
|
+
}));
|
|
14
|
+
describe('BytemTracker Goods Impression', () => {
|
|
15
|
+
const mockConfig = {
|
|
16
|
+
appKey: 'test-app-id',
|
|
17
|
+
endpoint: 'https://api.example.com',
|
|
18
|
+
debug: true,
|
|
19
|
+
};
|
|
20
|
+
beforeEach(() => {
|
|
21
|
+
jest.clearAllMocks();
|
|
22
|
+
BytemTracker_1.default.init(mockConfig);
|
|
23
|
+
});
|
|
24
|
+
it('should track goods_impression event correctly', async () => {
|
|
25
|
+
const products = [
|
|
26
|
+
{
|
|
27
|
+
productId: 'p_1',
|
|
28
|
+
url: 'https://example.com/p1'
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
productId: 'p_2',
|
|
32
|
+
url: 'https://example.com/p2'
|
|
33
|
+
}
|
|
34
|
+
];
|
|
35
|
+
await BytemTracker_1.default.trackGoodsImpression(products, 'Collection Page', 'Top List');
|
|
36
|
+
expect(global.fetch).toHaveBeenCalled();
|
|
37
|
+
const calls = global.fetch.mock.calls;
|
|
38
|
+
const body = calls[calls.length - 1][1].body;
|
|
39
|
+
// Decode body to check params
|
|
40
|
+
const params = new URLSearchParams(body);
|
|
41
|
+
const eventsJson = params.get('events');
|
|
42
|
+
const events = JSON.parse(eventsJson);
|
|
43
|
+
expect(events[0].key).toBe('goods_impression');
|
|
44
|
+
expect(events[0].segmentation).toMatchObject({
|
|
45
|
+
gid: ['p_1', 'p_2'],
|
|
46
|
+
urls: ['https://example.com/p1', 'https://example.com/p2'],
|
|
47
|
+
source: 'Collection Page',
|
|
48
|
+
position: 'Top List'
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
it('should handle missing urls or default values', async () => {
|
|
52
|
+
const products = [
|
|
53
|
+
{ productId: 'p_3' }
|
|
54
|
+
];
|
|
55
|
+
await BytemTracker_1.default.trackGoodsImpression(products);
|
|
56
|
+
expect(global.fetch).toHaveBeenCalled();
|
|
57
|
+
const calls = global.fetch.mock.calls;
|
|
58
|
+
const body = calls[calls.length - 1][1].body;
|
|
59
|
+
const params = new URLSearchParams(body);
|
|
60
|
+
const eventsJson = params.get('events');
|
|
61
|
+
const events = JSON.parse(eventsJson);
|
|
62
|
+
expect(events[0].key).toBe('goods_impression');
|
|
63
|
+
expect(events[0].segmentation).toMatchObject({
|
|
64
|
+
gid: ['p_3'],
|
|
65
|
+
urls: [''], // Should default to empty string
|
|
66
|
+
source: 'Other Page', // Default value
|
|
67
|
+
position: '' // Default value
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
});
|
package/dist/test/setup.js
CHANGED
|
@@ -19,13 +19,6 @@ jest.mock('@react-native-async-storage/async-storage', () => ({
|
|
|
19
19
|
return Promise.resolve(null);
|
|
20
20
|
}),
|
|
21
21
|
}));
|
|
22
|
-
// Mock React Native Device Info
|
|
23
|
-
jest.mock('react-native-device-info', () => ({
|
|
24
|
-
getSystemName: jest.fn(() => 'iOS'),
|
|
25
|
-
getSystemVersion: jest.fn(() => '14.0'),
|
|
26
|
-
getModel: jest.fn(() => 'iPhone 11'),
|
|
27
|
-
getUserAgent: jest.fn(() => Promise.resolve('Mozilla/5.0 (iPhone; CPU iPhone OS 14_0 like Mac OS X)')),
|
|
28
|
-
}), { virtual: true });
|
|
29
22
|
// Mock React Native
|
|
30
23
|
jest.mock('react-native', () => ({
|
|
31
24
|
Platform: {
|
package/package.json
CHANGED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.trackUser = void 0;
|
|
4
|
-
const trackUser = (userId, traits = {}) => {
|
|
5
|
-
return {
|
|
6
|
-
event: 'identify',
|
|
7
|
-
params: {
|
|
8
|
-
user_id: userId,
|
|
9
|
-
traits: traits,
|
|
10
|
-
},
|
|
11
|
-
};
|
|
12
|
-
};
|
|
13
|
-
exports.trackUser = trackUser;
|