@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 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 and its peer dependencies using Yarn:
7
+ Install the package using Yarn:
8
8
 
9
9
  ```bash
10
- yarn add @bytem/bytem-tracker-app react-native-device-info
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: __DEV__, // Enable debug logs in development
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
- #### Identify User
48
- Track user identification when a user logs in or updates their profile.
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
- age: 25,
55
- membership: 'gold'
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bytem/bytem-tracker-app",
3
- "version": "0.0.16",
3
+ "version": "0.0.18",
4
4
  "description": "Bytem Tracker SDK for React Native",
5
5
  "main": "dist/src/index.js",
6
6
  "types": "dist/src/index.d.ts",
@@ -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 (gids, prices, quantities)
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.
@@ -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 (gids, prices, quantities)
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
- // Map Order to segmentation
589
- const segmentation = {
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)
@@ -1,4 +1,6 @@
1
1
  export * from './trackViewProduct';
2
+ export * from './trackAddToCart';
2
3
  export * from './trackCheckOutOrder';
3
4
  export * from './trackPayOrder';
4
- export * from './trackUser';
5
+ export * from './trackGoodsImpression';
6
+ export * from './trackAddWishlist';
@@ -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("./trackUser"), exports);
21
+ __exportStar(require("./trackGoodsImpression"), exports);
22
+ __exportStar(require("./trackAddWishlist"), exports);
@@ -0,0 +1,2 @@
1
+ import { EventPayload, Product } from '../types';
2
+ export declare const trackAddToCart: (product: Product) => EventPayload;
@@ -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,2 @@
1
+ import { EventPayload, Product } from '../types';
2
+ export declare const trackAddWishlist: (product: Product) => EventPayload;
@@ -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: 'checkout_order',
6
+ event: 'check_out_order',
7
7
  params: {
8
- order_id: order.orderId,
9
- total: order.total,
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
- products: order.products.map((p) => ({
12
- product_id: p.productId,
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,2 @@
1
+ import { EventPayload, Product } from '../types';
2
+ export declare const trackGoodsImpression: (products: Product[], source?: string, position?: string) => EventPayload;
@@ -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;
@@ -13,8 +13,7 @@ const trackPayOrder = (order) => {
13
13
  name: p.name,
14
14
  price: p.price,
15
15
  quantity: p.quantity,
16
- })),
17
- status: 'success',
16
+ }))
18
17
  },
19
18
  };
20
19
  };
@@ -76,6 +76,7 @@ export interface Product {
76
76
  currency?: string;
77
77
  category?: string;
78
78
  quantity?: number;
79
+ url?: string;
79
80
  }
80
81
  /**
81
82
  * Represents an order (checkout or payment).
@@ -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
- order_id: 'order_123',
230
- total: 99.99,
229
+ gid: ['prod_1', 'prod_2'],
230
+ price: [50, 49.99],
231
+ quantity: [1, 1],
232
+ amount: 99.99,
231
233
  currency: 'USD',
232
- gids: ['prod_1', 'prod_2'],
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
+ });
@@ -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,6 +1,6 @@
1
1
  {
2
2
  "name": "@bytem/bytem-tracker-app",
3
- "version": "0.0.16",
3
+ "version": "0.0.18",
4
4
  "description": "Bytem Tracker SDK for React Native",
5
5
  "main": "dist/src/index.js",
6
6
  "types": "dist/src/index.d.ts",
@@ -1,2 +0,0 @@
1
- import { EventPayload, UserTraits } from '../types';
2
- export declare const trackUser: (userId: string, traits?: UserTraits) => EventPayload;
@@ -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;