@segment/analytics-browser-actions-cj 1.1.0

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.
Files changed (89) hide show
  1. package/dist/cjs/generated-types.d.ts +4 -0
  2. package/dist/cjs/generated-types.js +3 -0
  3. package/dist/cjs/generated-types.js.map +1 -0
  4. package/dist/cjs/index.d.ts +11 -0
  5. package/dist/cjs/index.js +38 -0
  6. package/dist/cjs/index.js.map +1 -0
  7. package/dist/cjs/order/generated-types.d.ts +141 -0
  8. package/dist/cjs/order/generated-types.js +3 -0
  9. package/dist/cjs/order/generated-types.js.map +1 -0
  10. package/dist/cjs/order/hashing-utils.d.ts +15 -0
  11. package/dist/cjs/order/hashing-utils.js +96 -0
  12. package/dist/cjs/order/hashing-utils.js.map +1 -0
  13. package/dist/cjs/order/index.d.ts +6 -0
  14. package/dist/cjs/order/index.js +58 -0
  15. package/dist/cjs/order/index.js.map +1 -0
  16. package/dist/cjs/order/order-fields.d.ts +6 -0
  17. package/dist/cjs/order/order-fields.js +1091 -0
  18. package/dist/cjs/order/order-fields.js.map +1 -0
  19. package/dist/cjs/order/utils.d.ts +3 -0
  20. package/dist/cjs/order/utils.js +19 -0
  21. package/dist/cjs/order/utils.js.map +1 -0
  22. package/dist/cjs/sitePage/generated-types.d.ts +13 -0
  23. package/dist/cjs/sitePage/generated-types.js +3 -0
  24. package/dist/cjs/sitePage/generated-types.js.map +1 -0
  25. package/dist/cjs/sitePage/index.d.ts +6 -0
  26. package/dist/cjs/sitePage/index.js +125 -0
  27. package/dist/cjs/sitePage/index.js.map +1 -0
  28. package/dist/cjs/sitePage/utils.d.ts +2 -0
  29. package/dist/cjs/sitePage/utils.js +7 -0
  30. package/dist/cjs/sitePage/utils.js.map +1 -0
  31. package/dist/cjs/types.d.ts +34 -0
  32. package/dist/cjs/types.js +3 -0
  33. package/dist/cjs/types.js.map +1 -0
  34. package/dist/cjs/utils.d.ts +1 -0
  35. package/dist/cjs/utils.js +23 -0
  36. package/dist/cjs/utils.js.map +1 -0
  37. package/dist/esm/generated-types.d.ts +4 -0
  38. package/dist/esm/generated-types.js +2 -0
  39. package/dist/esm/generated-types.js.map +1 -0
  40. package/dist/esm/index.d.ts +11 -0
  41. package/dist/esm/index.js +34 -0
  42. package/dist/esm/index.js.map +1 -0
  43. package/dist/esm/order/generated-types.d.ts +141 -0
  44. package/dist/esm/order/generated-types.js +2 -0
  45. package/dist/esm/order/generated-types.js.map +1 -0
  46. package/dist/esm/order/hashing-utils.d.ts +15 -0
  47. package/dist/esm/order/hashing-utils.js +88 -0
  48. package/dist/esm/order/hashing-utils.js.map +1 -0
  49. package/dist/esm/order/index.d.ts +6 -0
  50. package/dist/esm/order/index.js +56 -0
  51. package/dist/esm/order/index.js.map +1 -0
  52. package/dist/esm/order/order-fields.d.ts +6 -0
  53. package/dist/esm/order/order-fields.js +1088 -0
  54. package/dist/esm/order/order-fields.js.map +1 -0
  55. package/dist/esm/order/utils.d.ts +3 -0
  56. package/dist/esm/order/utils.js +15 -0
  57. package/dist/esm/order/utils.js.map +1 -0
  58. package/dist/esm/sitePage/generated-types.d.ts +13 -0
  59. package/dist/esm/sitePage/generated-types.js +2 -0
  60. package/dist/esm/sitePage/generated-types.js.map +1 -0
  61. package/dist/esm/sitePage/index.d.ts +6 -0
  62. package/dist/esm/sitePage/index.js +123 -0
  63. package/dist/esm/sitePage/index.js.map +1 -0
  64. package/dist/esm/sitePage/utils.d.ts +2 -0
  65. package/dist/esm/sitePage/utils.js +4 -0
  66. package/dist/esm/sitePage/utils.js.map +1 -0
  67. package/dist/esm/types.d.ts +34 -0
  68. package/dist/esm/types.js +2 -0
  69. package/dist/esm/types.js.map +1 -0
  70. package/dist/esm/utils.d.ts +1 -0
  71. package/dist/esm/utils.js +20 -0
  72. package/dist/esm/utils.js.map +1 -0
  73. package/dist/tsconfig.tsbuildinfo +1 -0
  74. package/package.json +25 -0
  75. package/src/generated-types.ts +12 -0
  76. package/src/index.ts +46 -0
  77. package/src/order/__tests__/index.test.ts +985 -0
  78. package/src/order/generated-types.ts +545 -0
  79. package/src/order/hashing-utils.ts +141 -0
  80. package/src/order/index.ts +90 -0
  81. package/src/order/order-fields.ts +1117 -0
  82. package/src/order/utils.ts +19 -0
  83. package/src/sitePage/__tests__/index.test.ts +124 -0
  84. package/src/sitePage/generated-types.ts +45 -0
  85. package/src/sitePage/index.ts +128 -0
  86. package/src/sitePage/utils.ts +5 -0
  87. package/src/types.ts +38 -0
  88. package/src/utils.ts +21 -0
  89. package/tsconfig.json +9 -0
@@ -0,0 +1,985 @@
1
+ import { Analytics, Context } from '@segment/analytics-next'
2
+ import { Subscription } from '@segment/browser-destination-runtime'
3
+ import CJDestination, { destination } from '../../index'
4
+ import { CJ } from '../../types'
5
+ import * as sendModule from '../../utils'
6
+ import * as orderModule from '../utils'
7
+ import { allVerticals, travelVerticals, financeVerticals, networkServicesVerticals } from '../order-fields'
8
+
9
+ describe('CJ init', () => {
10
+ const settings = {
11
+ tagId: '123456789',
12
+ actionTrackerId: '987654321'
13
+ }
14
+
15
+ const testCookieName = 'cjeventOrder'
16
+ let mockCJ: CJ
17
+ let orderEvent: any
18
+ beforeEach(async () => {
19
+ jest.spyOn(destination, 'initialize').mockImplementation(() => {
20
+ mockCJ = {} as CJ
21
+ return Promise.resolve(mockCJ)
22
+ })
23
+
24
+ document.cookie = `${testCookieName}=testcCookieValue`
25
+
26
+ jest.spyOn(sendModule, 'send').mockImplementation(() => {
27
+ return Promise.resolve()
28
+ })
29
+
30
+ jest.spyOn(orderModule, 'setOrderJSON')
31
+
32
+ })
33
+
34
+ afterEach(() => {
35
+ jest.restoreAllMocks()
36
+ })
37
+
38
+ test('CJ pixel order event', async () => {
39
+ const subscriptions: Subscription[] = [
40
+ {
41
+ partnerAction: 'order',
42
+ name: 'order',
43
+ enabled: true,
44
+ subscribe: 'type = "track" and event = "Order Completed"',
45
+ mapping: {
46
+ userId: { '@path': '$.userId' },
47
+ enterpriseId: 999999,
48
+ pageType: 'conversionConfirmation',
49
+ emailHash: {
50
+ '@if': {
51
+ exists: { '@path': '$.context.traits.email' },
52
+ then: { '@path': '$.context.traits.email' },
53
+ else: { '@path': '$.properties.email' }
54
+ }
55
+ },
56
+ orderId: { '@path': '$.properties.order_id' },
57
+ currency: { '@path': '$.properties.currency' },
58
+ amount: { '@path': '$.properties.total' },
59
+ discount: { '@path': '$.properties.discount' },
60
+ coupon: { '@path': '$.properties.coupon' },
61
+ cjeventOrderCookieName: testCookieName,
62
+ items: {
63
+ '@arrayPath': [
64
+ '$.properties.products',
65
+ {
66
+ itemPrice: { '@path': '$.price' },
67
+ itemId: { '@path': '$.id' },
68
+ quantity: { '@path': '$.quantity' },
69
+ discount: { '@path': '$.discount' }
70
+ }
71
+ ]
72
+ }
73
+ }
74
+ }
75
+ ]
76
+ const context = new Context({
77
+ type: 'track',
78
+ event: 'Order Completed',
79
+ userId: 'userId-abc123',
80
+ context: {
81
+ traits: {
82
+ email: 'test@test.com'
83
+ }
84
+ },
85
+ properties: {
86
+ order_id: 'abc12345',
87
+ currency: 'USD',
88
+ coupon: 'COUPON1',
89
+ quantity: 5,
90
+ total: 10.99,
91
+ discount: 1,
92
+ products: [
93
+ {
94
+ id: '123',
95
+ quantity: 1,
96
+ price: 1,
97
+ discount: 0.5
98
+ },
99
+ {
100
+ id: '456',
101
+ quantity: 2,
102
+ price: 2,
103
+ discount: 0
104
+ }
105
+ ]
106
+ }
107
+ })
108
+ const [event] = await CJDestination({
109
+ ...settings,
110
+ subscriptions
111
+ })
112
+
113
+ const orderJSON = {
114
+ trackingSource: 'Segment',
115
+ userId: 'userId-abc123',
116
+ enterpriseId: 999999,
117
+ pageType: 'conversionConfirmation',
118
+ emailHash: 'f660ab912ec121d1b1e928a0bb4bc61b15f5ad44d5efdc4e1c92a25e99b8e44a',
119
+ orderId: 'abc12345',
120
+ actionTrackerId: "987654321",
121
+ currency: 'USD',
122
+ amount: 10.99,
123
+ discount: 1,
124
+ coupon: 'COUPON1',
125
+ cjeventOrder: 'testcCookieValue',
126
+ items:[
127
+ {
128
+ itemId: '123',
129
+ quantity: 1,
130
+ itemPrice: 1,
131
+ discount: 0.5
132
+ },
133
+ {
134
+ itemId: '456',
135
+ quantity: 2,
136
+ itemPrice: 2,
137
+ discount: 0
138
+ }
139
+ ]
140
+ }
141
+
142
+ orderEvent = event
143
+ const sendSpy = jest.spyOn(sendModule, 'send').mockResolvedValue(undefined)
144
+ await orderEvent.load(Context.system(), {} as Analytics)
145
+ await orderEvent.track?.(context)
146
+ expect(destination.initialize).toHaveBeenCalled()
147
+ expect(orderModule.setOrderJSON).toHaveBeenCalled()
148
+ expect(orderModule.setOrderJSON).toHaveBeenCalledWith(
149
+ {},
150
+ orderJSON
151
+ )
152
+ expect(sendSpy).toHaveBeenCalledWith('123456789')
153
+ expect(mockCJ.sitePage).toBe(undefined)
154
+ expect(mockCJ.order).toBe(undefined)
155
+ })
156
+
157
+ test('CJ pixel order event with pre-hashed email', async () => {
158
+ const subscriptions: Subscription[] = [
159
+ {
160
+ partnerAction: 'order',
161
+ name: 'order',
162
+ enabled: true,
163
+ subscribe: 'type = "track" and event = "Order Completed"',
164
+ mapping: {
165
+ userId: { '@path': '$.userId' },
166
+ enterpriseId: 999999,
167
+ pageType: 'conversionConfirmation',
168
+ emailHash: {
169
+ '@if': {
170
+ exists: { '@path': '$.context.traits.email' },
171
+ then: { '@path': '$.context.traits.email' },
172
+ else: { '@path': '$.properties.email' }
173
+ }
174
+ },
175
+ orderId: { '@path': '$.properties.order_id' },
176
+ currency: { '@path': '$.properties.currency' },
177
+ amount: { '@path': '$.properties.total' },
178
+ discount: { '@path': '$.properties.discount' },
179
+ coupon: { '@path': '$.properties.coupon' },
180
+ cjeventOrderCookieName: testCookieName,
181
+ items: {
182
+ '@arrayPath': [
183
+ '$.properties.products',
184
+ {
185
+ itemPrice: { '@path': '$.price' },
186
+ itemId: { '@path': '$.id' },
187
+ quantity: { '@path': '$.quantity' },
188
+ discount: { '@path': '$.discount' }
189
+ }
190
+ ]
191
+ }
192
+ }
193
+ }
194
+ ]
195
+ const context = new Context({
196
+ type: 'track',
197
+ event: 'Order Completed',
198
+ userId: 'userId-abc123',
199
+ context: {
200
+ traits: {
201
+ email: 'f660ab912ec121d1b1e928a0bb4bc61b15f5ad44d5efdc4e1c92a25e99b8e44a'
202
+ }
203
+ },
204
+ properties: {
205
+ order_id: 'abc12345',
206
+ currency: 'USD',
207
+ coupon: 'COUPON1',
208
+ quantity: 5,
209
+ total: 10.99,
210
+ discount: 1,
211
+ products: [
212
+ {
213
+ id: '123',
214
+ quantity: 1,
215
+ price: 1,
216
+ discount: 0.5
217
+ },
218
+ {
219
+ id: '456',
220
+ quantity: 2,
221
+ price: 2,
222
+ discount: 0
223
+ }
224
+ ]
225
+ }
226
+ })
227
+ const [event] = await CJDestination({
228
+ ...settings,
229
+ subscriptions
230
+ })
231
+
232
+ const orderJSON = {
233
+ trackingSource: 'Segment',
234
+ userId: 'userId-abc123',
235
+ enterpriseId: 999999,
236
+ pageType: 'conversionConfirmation',
237
+ emailHash: 'f660ab912ec121d1b1e928a0bb4bc61b15f5ad44d5efdc4e1c92a25e99b8e44a',
238
+ orderId: 'abc12345',
239
+ actionTrackerId: "987654321",
240
+ currency: 'USD',
241
+ amount: 10.99,
242
+ discount: 1,
243
+ coupon: 'COUPON1',
244
+ cjeventOrder: 'testcCookieValue',
245
+ items:[
246
+ {
247
+ itemId: '123',
248
+ quantity: 1,
249
+ itemPrice: 1,
250
+ discount: 0.5
251
+ },
252
+ {
253
+ itemId: '456',
254
+ quantity: 2,
255
+ itemPrice: 2,
256
+ discount: 0
257
+ }
258
+ ]
259
+ }
260
+
261
+ orderEvent = event
262
+ const sendSpy = jest.spyOn(sendModule, 'send').mockResolvedValue(undefined)
263
+ await orderEvent.load(Context.system(), {} as Analytics)
264
+ await orderEvent.track?.(context)
265
+ expect(destination.initialize).toHaveBeenCalled()
266
+ expect(orderModule.setOrderJSON).toHaveBeenCalled()
267
+ expect(orderModule.setOrderJSON).toHaveBeenCalledWith(
268
+ {},
269
+ orderJSON
270
+ )
271
+ expect(sendSpy).toHaveBeenCalledWith('123456789')
272
+ expect(mockCJ.sitePage).toBe(undefined)
273
+ expect(mockCJ.order).toBe(undefined)
274
+ })
275
+
276
+ test('CJ pixel order event with All Verticals field data', async () => {
277
+ const subscriptions: Subscription[] = [
278
+ {
279
+ partnerAction: 'order',
280
+ name: 'order',
281
+ enabled: true,
282
+ subscribe: 'type = "track" and event = "Order Completed"',
283
+ mapping: {
284
+ userId: { '@path': '$.userId' },
285
+ enterpriseId: 999999,
286
+ pageType: 'conversionConfirmation',
287
+ emailHash: {
288
+ '@if': {
289
+ exists: { '@path': '$.context.traits.email' },
290
+ then: { '@path': '$.context.traits.email' },
291
+ else: { '@path': '$.properties.email' }
292
+ }
293
+ },
294
+ orderId: { '@path': '$.properties.order_id' },
295
+ currency: { '@path': '$.properties.currency' },
296
+ amount: { '@path': '$.properties.total' },
297
+ discount: { '@path': '$.properties.discount' },
298
+ coupon: { '@path': '$.properties.coupon' },
299
+ cjeventOrderCookieName: testCookieName,
300
+ items: {
301
+ '@arrayPath': [
302
+ '$.properties.products',
303
+ {
304
+ itemPrice: { '@path': '$.price' },
305
+ itemId: { '@path': '$.id' },
306
+ quantity: { '@path': '$.quantity' },
307
+ discount: { '@path': '$.discount' }
308
+ }
309
+ ]
310
+ },
311
+ allVerticals: allVerticals.default
312
+ }
313
+ }
314
+ ]
315
+ const context = new Context({
316
+ type: 'track',
317
+ event: 'Order Completed',
318
+ userId: 'userId-abc123',
319
+ context: {
320
+ traits: {
321
+ email: 'test@test.com'
322
+ },
323
+ locale: 'en-US'
324
+ },
325
+ properties: {
326
+ order_id: 'abc12345',
327
+ currency: 'USD',
328
+ coupon: 'COUPON1',
329
+ quantity: 5,
330
+ total: 10.99,
331
+ discount: 1,
332
+ products: [
333
+ {
334
+ id: '123',
335
+ quantity: 1,
336
+ price: 1,
337
+ discount: 0.5
338
+ },
339
+ {
340
+ id: '456',
341
+ quantity: 2,
342
+ price: 2,
343
+ discount: 0
344
+ }
345
+ ],
346
+ // All Verticals fields
347
+ brand: 'Nike',
348
+ brand_id: 'BR123',
349
+ business_unit: 'Online',
350
+ campaign_id: 'CAMP456',
351
+ campaign_name: 'BackToSchool',
352
+ category: 'Footwear',
353
+ class: 'Premium',
354
+ confirmation_number: 999888777,
355
+ coupon_discount: 15,
356
+ coupon_type: 'percent',
357
+ customer_country: 'en-US',
358
+ customer_segment: 'Loyal',
359
+ customer_status: 'Return',
360
+ customer_type: 'GroupBuyer',
361
+ delivery: 'STANDARD',
362
+ description: 'Running shoes',
363
+ duration: 7,
364
+ end_date_time: '2025-08-06T18:30:00Z',
365
+ genre: 'Sports',
366
+ item_id: 'ITEM999',
367
+ item_name: 'Air Max',
368
+ item_type: 'Sneakers',
369
+ lifestage: 'Adult',
370
+ location: 'NY',
371
+ loyalty_earned: 200,
372
+ loyalty_first_time_signup: 'Yes',
373
+ loyalty_level: 'Gold',
374
+ loyalty_redeemed: 50,
375
+ loyalty_status: 'Yes',
376
+ margin: '15%',
377
+ marketing_channel: 'affiliate',
378
+ no_cancellation: 'No',
379
+ order_subtotal: 120,
380
+ payment_method: 'credit_debit_card',
381
+ payment_model: 'OneTime',
382
+ platform_id: 'ios',
383
+ point_of_sale: 'INTERNET',
384
+ preorder: 'No',
385
+ prepaid: 'Yes',
386
+ promotion: 'SUMMER20',
387
+ promotion_amount: 20,
388
+ promotion_condition_threshold: 100,
389
+ promotion_condition_type: 'LOYALTY_REQUIRED',
390
+ promotion_ends: '2025-08-10T00:00:00Z',
391
+ promotion_starts: '2025-08-01T00:00:00Z',
392
+ promotion_type: 'PERCENT_OFF',
393
+ rating: '4.5',
394
+ service_type: 'wireless',
395
+ start_date_time: '2025-08-05T10:00:00Z',
396
+ subscription_fee: 9.99,
397
+ subscription_length: '12 months',
398
+ tax_amount: 10,
399
+ tax_type: 'STATE',
400
+ upsell: 'Yes'
401
+ }
402
+ })
403
+ const [event] = await CJDestination({
404
+ ...settings,
405
+ subscriptions
406
+ })
407
+
408
+ const orderJSON = {
409
+ trackingSource: 'Segment',
410
+ userId: 'userId-abc123',
411
+ enterpriseId: 999999,
412
+ pageType: 'conversionConfirmation',
413
+ emailHash: 'f660ab912ec121d1b1e928a0bb4bc61b15f5ad44d5efdc4e1c92a25e99b8e44a',
414
+ orderId: 'abc12345',
415
+ actionTrackerId: '987654321',
416
+ currency: 'USD',
417
+ amount: 10.99,
418
+ discount: 1,
419
+ coupon: 'COUPON1',
420
+ cjeventOrder: 'testcCookieValue',
421
+ items: [
422
+ {
423
+ itemId: '123',
424
+ quantity: 1,
425
+ itemPrice: 1,
426
+ discount: 0.5
427
+ },
428
+ {
429
+ itemId: '456',
430
+ quantity: 2,
431
+ itemPrice: 2,
432
+ discount: 0
433
+ }
434
+ ],
435
+ // All Verticals fields
436
+ brand: 'Nike',
437
+ brandId: 'BR123',
438
+ businessUnit: 'Online',
439
+ campaignId: 'CAMP456',
440
+ campaignName: 'BackToSchool',
441
+ category: 'Footwear',
442
+ class: 'Premium',
443
+ confirmationNumber: 999888777,
444
+ couponDiscount: 15,
445
+ couponType: 'percent',
446
+ customerCountry: 'US',
447
+ customerSegment: 'Loyal',
448
+ customerStatus: 'Return',
449
+ customerType: 'GroupBuyer',
450
+ delivery: 'STANDARD',
451
+ description: 'Running shoes',
452
+ duration: 7,
453
+ endDateTime: '2025-08-06T18:30:00Z',
454
+ genre: 'Sports',
455
+ itemId: 'ITEM999',
456
+ itemName: 'Air Max',
457
+ itemType: 'Sneakers',
458
+ lifestage: 'Adult',
459
+ location: 'NY',
460
+ loyaltyEarned: 200,
461
+ loyaltyFirstTimeSignup: 'Yes',
462
+ loyaltyLevel: 'Gold',
463
+ loyaltyRedeemed: 50,
464
+ loyaltyStatus: 'Yes',
465
+ margin: '15%',
466
+ marketingChannel: 'affiliate',
467
+ noCancellation: 'No',
468
+ orderSubtotal: 120,
469
+ paymentMethod: 'credit_debit_card',
470
+ paymentModel: 'OneTime',
471
+ platformId: 'ios',
472
+ pointOfSale: 'INTERNET',
473
+ preorder: 'No',
474
+ prepaid: 'Yes',
475
+ promotion: 'SUMMER20',
476
+ promotionAmount: 20,
477
+ promotionConditionThreshold: 100,
478
+ promotionConditionType: 'LOYALTY_REQUIRED',
479
+ promotionEnds: '2025-08-10T00:00:00Z',
480
+ promotionStarts: '2025-08-01T00:00:00Z',
481
+ promotionType: 'PERCENT_OFF',
482
+ quantity: 5,
483
+ rating: '4.5',
484
+ serviceType: 'wireless',
485
+ startDateTime: '2025-08-05T10:00:00Z',
486
+ subscriptionFee: 9.99,
487
+ subscriptionLength: '12 months',
488
+ taxAmount: 10,
489
+ taxType: 'STATE',
490
+ upsell: 'Yes'
491
+ }
492
+
493
+ orderEvent = event
494
+ const sendSpy = jest.spyOn(sendModule, 'send').mockResolvedValue(undefined)
495
+ await orderEvent.load(Context.system(), {} as Analytics)
496
+ await orderEvent.track?.(context)
497
+ expect(destination.initialize).toHaveBeenCalled()
498
+ expect(orderModule.setOrderJSON).toHaveBeenCalled()
499
+ expect(orderModule.setOrderJSON).toHaveBeenCalledWith(
500
+ {},
501
+ orderJSON
502
+ )
503
+ expect(sendSpy).toHaveBeenCalledWith('123456789')
504
+ expect(mockCJ.sitePage).toBe(undefined)
505
+ expect(mockCJ.order).toBe(undefined)
506
+ })
507
+
508
+ test('CJ pixel order event with Travel Vertical data', async () => {
509
+ const subscriptions: Subscription[] = [
510
+ {
511
+ partnerAction: 'order',
512
+ name: 'order',
513
+ enabled: true,
514
+ subscribe: 'type = "track" and event = "Order Completed"',
515
+ mapping: {
516
+ verticalType: 'travel',
517
+ userId: { '@path': '$.userId' },
518
+ enterpriseId: 999999,
519
+ pageType: 'conversionConfirmation',
520
+ emailHash: {
521
+ '@if': {
522
+ exists: { '@path': '$.context.traits.email' },
523
+ then: { '@path': '$.context.traits.email' },
524
+ else: { '@path': '$.properties.email' }
525
+ }
526
+ },
527
+ orderId: { '@path': '$.properties.order_id' },
528
+ currency: { '@path': '$.properties.currency' },
529
+ amount: { '@path': '$.properties.total' },
530
+ discount: { '@path': '$.properties.discount' },
531
+ coupon: { '@path': '$.properties.coupon' },
532
+ cjeventOrderCookieName: testCookieName,
533
+ items: {
534
+ '@arrayPath': [
535
+ '$.properties.products',
536
+ {
537
+ itemPrice: { '@path': '$.price' },
538
+ itemId: { '@path': '$.id' },
539
+ quantity: { '@path': '$.quantity' },
540
+ discount: { '@path': '$.discount' }
541
+ }
542
+ ]
543
+ },
544
+ travelVerticals: travelVerticals.default
545
+ }
546
+ }
547
+ ]
548
+ const context = new Context({
549
+ type: 'track',
550
+ event: 'Order Completed',
551
+ userId: 'userId-abc123',
552
+ context: {
553
+ traits: {
554
+ email: 'test@test.com'
555
+ }
556
+ },
557
+ properties: {
558
+ order_id: 'abc12345',
559
+ currency: 'USD',
560
+ coupon: 'COUPON1',
561
+ quantity: 5,
562
+ total: 10.99,
563
+ discount: 1,
564
+ products: [
565
+ {
566
+ id: '123',
567
+ quantity: 1,
568
+ price: 1,
569
+ discount: 0.5
570
+ },
571
+ {
572
+ id: '456',
573
+ quantity: 2,
574
+ price: 2,
575
+ discount: 0
576
+ }
577
+ ],
578
+ booking_date: '2025-08-06T18:30:00Z',
579
+ booking_status: 'Booking Status Test Value',
580
+ booking_value_post_tax: 100,
581
+ booking_value_pre_tax: 900,
582
+ car_options: 'insurance',
583
+ class: 'first',
584
+ cruise_type: 'Alaskan',
585
+ destination_city: 'London',
586
+ destination_country: 'UK',
587
+ destination_state: 'France',
588
+ domestic: 'NO',
589
+ dropoff_iata: 'DUB',
590
+ dropoff_id: 'CDG',
591
+ flight_fare_type: 'gotta get away',
592
+ flight_options: 'wifi',
593
+ flight_type: 'ROUND_TRIP',
594
+ flyer_miles: 8000,
595
+ guests: 2,
596
+ iata: 'CDG,LHR,DUB',
597
+ itinerary_id: 'itinerary_id_1',
598
+ minimum_stay_duration: 9,
599
+ origin_city: 'DUB',
600
+ origin_country: 'IE',
601
+ origin_state: 'US-AK',
602
+ paid_at_booking_post_tax: 100,
603
+ paid_at_booking_pre_tax: 90,
604
+ pickup_iata: 'LRH',
605
+ pickup_id: 'test_pickup+id',
606
+ port: 'SYD',
607
+ room_type: 'Double room',
608
+ rooms: 3,
609
+ ship_name: 'Titanic',
610
+ travel_type: 'CRUISE'
611
+ }
612
+ })
613
+ const [event] = await CJDestination({
614
+ ...settings,
615
+ subscriptions
616
+ })
617
+
618
+ const orderJSON = {
619
+ trackingSource: 'Segment',
620
+ userId: 'userId-abc123',
621
+ enterpriseId: 999999,
622
+ pageType: 'conversionConfirmation',
623
+ emailHash: 'f660ab912ec121d1b1e928a0bb4bc61b15f5ad44d5efdc4e1c92a25e99b8e44a',
624
+ orderId: 'abc12345',
625
+ actionTrackerId: '987654321',
626
+ currency: 'USD',
627
+ amount: 10.99,
628
+ discount: 1,
629
+ coupon: 'COUPON1',
630
+ cjeventOrder: 'testcCookieValue',
631
+ items: [
632
+ {
633
+ itemId: '123',
634
+ quantity: 1,
635
+ itemPrice: 1,
636
+ discount: 0.5
637
+ },
638
+ {
639
+ itemId: '456',
640
+ quantity: 2,
641
+ itemPrice: 2,
642
+ discount: 0
643
+ }
644
+ ],
645
+ bookingDate: '2025-08-06T18:30:00Z',
646
+ bookingStatus: 'Booking Status Test Value',
647
+ bookingValuePostTax: 100,
648
+ bookingValuePreTax: 900,
649
+ carOptions: 'insurance',
650
+ class: 'first',
651
+ cruiseType: 'Alaskan',
652
+ destinationCity: 'London',
653
+ destinationCountry: 'UK',
654
+ destinationState: 'France',
655
+ domestic: 'NO',
656
+ dropoffIata: 'DUB',
657
+ dropoffId: 'CDG',
658
+ flightFareType: 'gotta get away',
659
+ flightOptions: 'wifi',
660
+ flightType: 'ROUND_TRIP',
661
+ flyerMiles: 8000,
662
+ guests: 2,
663
+ iata: 'CDG,LHR,DUB',
664
+ itineraryId: 'itinerary_id_1',
665
+ minimumStayDuration: 9,
666
+ originCity: 'DUB',
667
+ originCountry: 'IE',
668
+ originState: 'US-AK',
669
+ paidAtBookingPostTax: 100,
670
+ paidAtBookingPreTax: 90,
671
+ pickupIata: 'LRH',
672
+ pickupId: 'test_pickup+id',
673
+ port: 'SYD',
674
+ roomType: 'Double room',
675
+ rooms: 3,
676
+ shipName: 'Titanic',
677
+ travelType: 'CRUISE'
678
+ }
679
+
680
+ orderEvent = event
681
+ const sendSpy = jest.spyOn(sendModule, 'send').mockResolvedValue(undefined)
682
+ await orderEvent.load(Context.system(), {} as Analytics)
683
+ await orderEvent.track?.(context)
684
+ expect(destination.initialize).toHaveBeenCalled()
685
+ expect(orderModule.setOrderJSON).toHaveBeenCalled()
686
+ expect(orderModule.setOrderJSON).toHaveBeenCalledWith(
687
+ {},
688
+ orderJSON
689
+ )
690
+ expect(sendSpy).toHaveBeenCalledWith('123456789')
691
+ expect(mockCJ.sitePage).toBe(undefined)
692
+ expect(mockCJ.order).toBe(undefined)
693
+ })
694
+
695
+ test('CJ pixel order event with Finance Vertical data', async () => {
696
+ const subscriptions: Subscription[] = [
697
+ {
698
+ partnerAction: 'order',
699
+ name: 'order',
700
+ enabled: true,
701
+ subscribe: 'type = "track" and event = "Order Completed"',
702
+ mapping: {
703
+ verticalType: 'finance',
704
+ userId: { '@path': '$.userId' },
705
+ enterpriseId: 999999,
706
+ pageType: 'conversionConfirmation',
707
+ emailHash: {
708
+ '@if': {
709
+ exists: { '@path': '$.context.traits.email' },
710
+ then: { '@path': '$.context.traits.email' },
711
+ else: { '@path': '$.properties.email' }
712
+ }
713
+ },
714
+ orderId: { '@path': '$.properties.order_id' },
715
+ currency: { '@path': '$.properties.currency' },
716
+ amount: { '@path': '$.properties.total' },
717
+ discount: { '@path': '$.properties.discount' },
718
+ coupon: { '@path': '$.properties.coupon' },
719
+ cjeventOrderCookieName: testCookieName,
720
+ items: {
721
+ '@arrayPath': [
722
+ '$.properties.products',
723
+ {
724
+ itemPrice: { '@path': '$.price' },
725
+ itemId: { '@path': '$.id' },
726
+ quantity: { '@path': '$.quantity' },
727
+ discount: { '@path': '$.discount' }
728
+ }
729
+ ]
730
+ },
731
+ financeVerticals: financeVerticals.default
732
+ }
733
+ }
734
+ ]
735
+ const context = new Context({
736
+ type: 'track',
737
+ event: 'Order Completed',
738
+ userId: 'userId-abc123',
739
+ context: {
740
+ traits: {
741
+ email: 'test@test.com'
742
+ }
743
+ },
744
+ properties: {
745
+ order_id: 'abc12345',
746
+ currency: 'USD',
747
+ coupon: 'COUPON1',
748
+ quantity: 5,
749
+ total: 10.99,
750
+ discount: 1,
751
+ products: [
752
+ {
753
+ id: '123',
754
+ quantity: 1,
755
+ price: 1,
756
+ discount: 0.5
757
+ },
758
+ {
759
+ id: '456',
760
+ quantity: 2,
761
+ price: 2,
762
+ discount: 0
763
+ }
764
+ ],
765
+ annual_fee: 100,
766
+ application_status: 'instant_approved',
767
+ apr: 0.4,
768
+ apr_transfer: 'test_aprTransfer',
769
+ apr_transfer_time: 5,
770
+ card_category: 'BALANCE_TRANSFER_CARDS',
771
+ cash_advance_fee: 5,
772
+ contract_length: 7,
773
+ contract_type: 'test contractType',
774
+ credit_report: 'purchase',
775
+ credit_line: 4,
776
+ credit_quality: 'Very Poor',
777
+ funded_amount: 200,
778
+ funded_currency: 'USD',
779
+ introductory_apr: 5,
780
+ introductory_apr_time: 2,
781
+ minimum_balance: 500,
782
+ minimum_deposit: { '@path': '$.properties.minimum_deposit' },
783
+ prequalify: 'YES',
784
+ transfer_fee: 80
785
+ }
786
+ })
787
+ const [event] = await CJDestination({
788
+ ...settings,
789
+ subscriptions
790
+ })
791
+
792
+ const orderJSON = {
793
+ trackingSource: 'Segment',
794
+ userId: 'userId-abc123',
795
+ enterpriseId: 999999,
796
+ pageType: 'conversionConfirmation',
797
+ emailHash: 'f660ab912ec121d1b1e928a0bb4bc61b15f5ad44d5efdc4e1c92a25e99b8e44a',
798
+ orderId: 'abc12345',
799
+ actionTrackerId: '987654321',
800
+ currency: 'USD',
801
+ amount: 10.99,
802
+ discount: 1,
803
+ coupon: 'COUPON1',
804
+ cjeventOrder: 'testcCookieValue',
805
+ items: [
806
+ {
807
+ itemId: '123',
808
+ quantity: 1,
809
+ itemPrice: 1,
810
+ discount: 0.5
811
+ },
812
+ {
813
+ itemId: '456',
814
+ quantity: 2,
815
+ itemPrice: 2,
816
+ discount: 0
817
+ }
818
+ ],
819
+ annualFee: 100,
820
+ applicationStatus: 'instant_approved',
821
+ apr: 0.4,
822
+ aprTransfer: 'test_aprTransfer',
823
+ aprTransferTime: 5,
824
+ cardCategory: 'BALANCE_TRANSFER_CARDS',
825
+ cashAdvanceFee: 5,
826
+ contractLength: 7,
827
+ contractType: 'test contractType',
828
+ creditReport: 'purchase',
829
+ creditLine: 4,
830
+ creditQuality: 'Very Poor',
831
+ fundedAmount: 200,
832
+ fundedCurrency: 'USD',
833
+ introductoryApr: 5,
834
+ introductoryAprTime: 2,
835
+ minimumBalance: 500,
836
+ minimumDeposit: { '@path': '$.properties.minimum_deposit' },
837
+ prequalify: 'YES',
838
+ transferFee: 80
839
+ }
840
+
841
+ orderEvent = event
842
+ const sendSpy = jest.spyOn(sendModule, 'send').mockResolvedValue(undefined)
843
+ await orderEvent.load(Context.system(), {} as Analytics)
844
+ await orderEvent.track?.(context)
845
+ expect(destination.initialize).toHaveBeenCalled()
846
+ expect(orderModule.setOrderJSON).toHaveBeenCalled()
847
+ expect(orderModule.setOrderJSON).toHaveBeenCalledWith(
848
+ {},
849
+ orderJSON
850
+ )
851
+ expect(sendSpy).toHaveBeenCalledWith('123456789')
852
+ expect(mockCJ.sitePage).toBe(undefined)
853
+ expect(mockCJ.order).toBe(undefined)
854
+ })
855
+
856
+ test('CJ pixel order event with Network Service Vertical data', async () => {
857
+ const subscriptions: Subscription[] = [
858
+ {
859
+ partnerAction: 'order',
860
+ name: 'order',
861
+ enabled: true,
862
+ subscribe: 'type = "track" and event = "Order Completed"',
863
+ mapping: {
864
+ verticalType: 'network',
865
+ userId: { '@path': '$.userId' },
866
+ enterpriseId: 999999,
867
+ pageType: 'conversionConfirmation',
868
+ emailHash: {
869
+ '@if': {
870
+ exists: { '@path': '$.context.traits.email' },
871
+ then: { '@path': '$.context.traits.email' },
872
+ else: { '@path': '$.properties.email' }
873
+ }
874
+ },
875
+ orderId: { '@path': '$.properties.order_id' },
876
+ currency: { '@path': '$.properties.currency' },
877
+ amount: { '@path': '$.properties.total' },
878
+ discount: { '@path': '$.properties.discount' },
879
+ coupon: { '@path': '$.properties.coupon' },
880
+ cjeventOrderCookieName: testCookieName,
881
+ items: {
882
+ '@arrayPath': [
883
+ '$.properties.products',
884
+ {
885
+ itemPrice: { '@path': '$.price' },
886
+ itemId: { '@path': '$.id' },
887
+ quantity: { '@path': '$.quantity' },
888
+ discount: { '@path': '$.discount' }
889
+ }
890
+ ]
891
+ },
892
+ networkServicesVerticals: networkServicesVerticals.default
893
+ }
894
+ }
895
+ ]
896
+ const context = new Context({
897
+ type: 'track',
898
+ event: 'Order Completed',
899
+ userId: 'userId-abc123',
900
+ context: {
901
+ traits: {
902
+ email: 'test@test.com'
903
+ }
904
+ },
905
+ properties: {
906
+ order_id: 'abc12345',
907
+ currency: 'USD',
908
+ coupon: 'COUPON1',
909
+ quantity: 5,
910
+ total: 10.99,
911
+ discount: 1,
912
+ products: [
913
+ {
914
+ id: '123',
915
+ quantity: 1,
916
+ price: 1,
917
+ discount: 0.5
918
+ },
919
+ {
920
+ id: '456',
921
+ quantity: 2,
922
+ price: 2,
923
+ discount: 0
924
+ }
925
+ ],
926
+ annual_fee: 10,
927
+ application_status: 'instant_approved',
928
+ contract_length: 2,
929
+ contract_type: 'test contract type'
930
+ }
931
+ })
932
+ const [event] = await CJDestination({
933
+ ...settings,
934
+ subscriptions
935
+ })
936
+
937
+ const orderJSON = {
938
+ trackingSource: 'Segment',
939
+ userId: 'userId-abc123',
940
+ enterpriseId: 999999,
941
+ pageType: 'conversionConfirmation',
942
+ emailHash: 'f660ab912ec121d1b1e928a0bb4bc61b15f5ad44d5efdc4e1c92a25e99b8e44a',
943
+ orderId: 'abc12345',
944
+ actionTrackerId: '987654321',
945
+ currency: 'USD',
946
+ amount: 10.99,
947
+ discount: 1,
948
+ coupon: 'COUPON1',
949
+ cjeventOrder: 'testcCookieValue',
950
+ items: [
951
+ {
952
+ itemId: '123',
953
+ quantity: 1,
954
+ itemPrice: 1,
955
+ discount: 0.5
956
+ },
957
+ {
958
+ itemId: '456',
959
+ quantity: 2,
960
+ itemPrice: 2,
961
+ discount: 0
962
+ }
963
+ ],
964
+ annualFee: 10,
965
+ applicationStatus: 'instant_approved',
966
+ contractLength: 2,
967
+ contractType: 'test contract type'
968
+ }
969
+
970
+ orderEvent = event
971
+ const sendSpy = jest.spyOn(sendModule, 'send').mockResolvedValue(undefined)
972
+ await orderEvent.load(Context.system(), {} as Analytics)
973
+ await orderEvent.track?.(context)
974
+ expect(destination.initialize).toHaveBeenCalled()
975
+ expect(orderModule.setOrderJSON).toHaveBeenCalled()
976
+ expect(orderModule.setOrderJSON).toHaveBeenCalledWith(
977
+ {},
978
+ orderJSON
979
+ )
980
+ expect(sendSpy).toHaveBeenCalledWith('123456789')
981
+ expect(mockCJ.sitePage).toBe(undefined)
982
+ expect(mockCJ.order).toBe(undefined)
983
+ })
984
+
985
+ })