@segment/analytics-browser-actions-facebook-conversions-api-web 1.9.1-staging-99a2d468f.1 → 1.11.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.
- package/dist/cjs/functions.d.ts +0 -1
- package/dist/cjs/functions.js +2 -11
- package/dist/cjs/functions.js.map +1 -1
- package/dist/cjs/generated-types.d.ts +1 -0
- package/dist/cjs/index.d.ts +6 -2
- package/dist/cjs/index.js +17 -5
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/send/depends-on.js +11 -40
- package/dist/cjs/send/depends-on.js.map +1 -1
- package/dist/cjs/send/fields.js +18 -5
- package/dist/cjs/send/fields.js.map +1 -1
- package/dist/cjs/send/functions.d.ts +2 -2
- package/dist/cjs/send/functions.js +40 -29
- package/dist/cjs/send/functions.js.map +1 -1
- package/dist/cjs/send/generated-types.d.ts +2 -0
- package/dist/cjs/send/index.d.ts +5 -2
- package/dist/cjs/send/index.js +1 -1
- package/dist/cjs/send/index.js.map +1 -1
- package/dist/cjs/types.d.ts +10 -0
- package/dist/cjs/types.js.map +1 -1
- package/dist/esm/functions.d.ts +0 -1
- package/dist/esm/functions.js +2 -10
- package/dist/esm/functions.js.map +1 -1
- package/dist/esm/generated-types.d.ts +1 -0
- package/dist/esm/index.d.ts +6 -2
- package/dist/esm/index.js +17 -5
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/send/depends-on.js +11 -40
- package/dist/esm/send/depends-on.js.map +1 -1
- package/dist/esm/send/fields.js +18 -5
- package/dist/esm/send/fields.js.map +1 -1
- package/dist/esm/send/functions.d.ts +2 -2
- package/dist/esm/send/functions.js +40 -29
- package/dist/esm/send/functions.js.map +1 -1
- package/dist/esm/send/generated-types.d.ts +2 -0
- package/dist/esm/send/index.d.ts +5 -2
- package/dist/esm/send/index.js +1 -1
- package/dist/esm/send/index.js.map +1 -1
- package/dist/esm/types.d.ts +10 -0
- package/dist/esm/types.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +3 -3
- package/src/__tests__/functions.test.ts +159 -0
- package/src/constants.ts +1 -1
- package/src/functions.ts +66 -65
- package/src/generated-types.ts +4 -0
- package/src/index.ts +43 -26
- package/src/send/__tests__/depends-on.test.ts +28 -0
- package/src/send/__tests__/functions.test.ts +1178 -0
- package/src/send/depends-on.ts +41 -69
- package/src/send/fields.ts +304 -299
- package/src/send/functions.ts +213 -153
- package/src/send/generated-types.ts +10 -2
- package/src/send/index.ts +4 -4
- package/src/types.ts +33 -21
|
@@ -0,0 +1,1178 @@
|
|
|
1
|
+
import { send } from '../functions'
|
|
2
|
+
|
|
3
|
+
describe('Facebook Conversions API Web - Send Functions', () => {
|
|
4
|
+
let mockFbq
|
|
5
|
+
let mockAnalytics
|
|
6
|
+
let mockClientParamBuilder
|
|
7
|
+
let consoleWarnSpy
|
|
8
|
+
|
|
9
|
+
beforeEach(() => {
|
|
10
|
+
mockFbq = jest.fn()
|
|
11
|
+
mockAnalytics = {
|
|
12
|
+
storage: {
|
|
13
|
+
get: jest.fn(),
|
|
14
|
+
set: jest.fn()
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
mockClientParamBuilder = undefined
|
|
19
|
+
consoleWarnSpy = jest.spyOn(console, 'warn').mockImplementation()
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
afterEach(() => {
|
|
23
|
+
jest.restoreAllMocks()
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
const defaultSettings = {
|
|
27
|
+
pixelId: 'test-pixel-123',
|
|
28
|
+
ldu: 'Disabled'
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
describe('send - Standard Events', () => {
|
|
32
|
+
it('should send Purchase event with required fields', () => {
|
|
33
|
+
const payload = {
|
|
34
|
+
event_config: {
|
|
35
|
+
event_name: 'Purchase',
|
|
36
|
+
show_fields: false
|
|
37
|
+
},
|
|
38
|
+
content_ids: ['product-123'],
|
|
39
|
+
value: 99.99,
|
|
40
|
+
currency: 'USD'
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
send(mockFbq, mockClientParamBuilder, payload, defaultSettings, mockAnalytics)
|
|
44
|
+
|
|
45
|
+
expect(mockFbq).toHaveBeenCalledWith(
|
|
46
|
+
'trackSingle',
|
|
47
|
+
'test-pixel-123',
|
|
48
|
+
'Purchase',
|
|
49
|
+
expect.objectContaining({
|
|
50
|
+
content_ids: ['product-123'],
|
|
51
|
+
value: 99.99,
|
|
52
|
+
currency: 'USD'
|
|
53
|
+
}),
|
|
54
|
+
undefined
|
|
55
|
+
)
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
it('should send AddToCart event with contents', () => {
|
|
59
|
+
const payload = {
|
|
60
|
+
event_config: {
|
|
61
|
+
event_name: 'AddToCart',
|
|
62
|
+
show_fields: false
|
|
63
|
+
},
|
|
64
|
+
contents: [
|
|
65
|
+
{
|
|
66
|
+
id: 'product-123',
|
|
67
|
+
quantity: 2,
|
|
68
|
+
item_price: 49.99
|
|
69
|
+
}
|
|
70
|
+
],
|
|
71
|
+
value: 99.98,
|
|
72
|
+
currency: 'USD'
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
send(mockFbq, mockClientParamBuilder, payload, defaultSettings, mockAnalytics)
|
|
76
|
+
|
|
77
|
+
expect(mockFbq).toHaveBeenCalledWith(
|
|
78
|
+
'trackSingle',
|
|
79
|
+
'test-pixel-123',
|
|
80
|
+
'AddToCart',
|
|
81
|
+
expect.objectContaining({
|
|
82
|
+
contents: [{ id: 'product-123', quantity: 2, item_price: 49.99 }],
|
|
83
|
+
value: 99.98,
|
|
84
|
+
currency: 'USD'
|
|
85
|
+
}),
|
|
86
|
+
undefined
|
|
87
|
+
)
|
|
88
|
+
})
|
|
89
|
+
|
|
90
|
+
it('should send ViewContent event', () => {
|
|
91
|
+
const payload = {
|
|
92
|
+
event_config: {
|
|
93
|
+
event_name: 'ViewContent',
|
|
94
|
+
show_fields: false
|
|
95
|
+
},
|
|
96
|
+
content_ids: ['product-456'],
|
|
97
|
+
content_name: 'Test Product',
|
|
98
|
+
content_category: 'Electronics',
|
|
99
|
+
value: 199.99
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
send(mockFbq, mockClientParamBuilder, payload, defaultSettings, mockAnalytics)
|
|
103
|
+
|
|
104
|
+
expect(mockFbq).toHaveBeenCalledWith(
|
|
105
|
+
'trackSingle',
|
|
106
|
+
'test-pixel-123',
|
|
107
|
+
'ViewContent',
|
|
108
|
+
expect.objectContaining({
|
|
109
|
+
content_ids: ['product-456'],
|
|
110
|
+
content_name: 'Test Product',
|
|
111
|
+
content_category: 'Electronics',
|
|
112
|
+
value: 199.99
|
|
113
|
+
}),
|
|
114
|
+
undefined
|
|
115
|
+
)
|
|
116
|
+
})
|
|
117
|
+
|
|
118
|
+
it('should send PageView event', () => {
|
|
119
|
+
const payload = {
|
|
120
|
+
event_config: {
|
|
121
|
+
event_name: 'PageView',
|
|
122
|
+
show_fields: false
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
send(mockFbq, mockClientParamBuilder, payload, defaultSettings, mockAnalytics)
|
|
127
|
+
|
|
128
|
+
expect(mockFbq).toHaveBeenCalledWith('trackSingle', 'test-pixel-123', 'PageView', {}, undefined)
|
|
129
|
+
})
|
|
130
|
+
})
|
|
131
|
+
|
|
132
|
+
describe('send - Custom Events', () => {
|
|
133
|
+
it('should send custom event with custom event name', () => {
|
|
134
|
+
const payload = {
|
|
135
|
+
event_config: {
|
|
136
|
+
event_name: 'CustomEvent',
|
|
137
|
+
custom_event_name: 'MyCustomEvent',
|
|
138
|
+
show_fields: true
|
|
139
|
+
},
|
|
140
|
+
value: 50.0,
|
|
141
|
+
custom_data: {
|
|
142
|
+
custom_field_1: 'value1',
|
|
143
|
+
custom_field_2: 'value2'
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
send(mockFbq, mockClientParamBuilder, payload, defaultSettings, mockAnalytics)
|
|
148
|
+
|
|
149
|
+
expect(mockFbq).toHaveBeenCalledWith(
|
|
150
|
+
'trackSingleCustom',
|
|
151
|
+
'test-pixel-123',
|
|
152
|
+
'MyCustomEvent',
|
|
153
|
+
expect.objectContaining({
|
|
154
|
+
value: 50.0,
|
|
155
|
+
custom_data: {
|
|
156
|
+
custom_field_1: 'value1',
|
|
157
|
+
custom_field_2: 'value2'
|
|
158
|
+
}
|
|
159
|
+
}),
|
|
160
|
+
undefined
|
|
161
|
+
)
|
|
162
|
+
})
|
|
163
|
+
})
|
|
164
|
+
|
|
165
|
+
describe('send - Validation', () => {
|
|
166
|
+
it('should warn if AddToCart is missing both content_ids and contents', () => {
|
|
167
|
+
const payload = {
|
|
168
|
+
event_config: {
|
|
169
|
+
event_name: 'AddToCart',
|
|
170
|
+
show_fields: false
|
|
171
|
+
},
|
|
172
|
+
value: 99.99
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
send(mockFbq, mockClientParamBuilder, payload, defaultSettings, mockAnalytics)
|
|
176
|
+
|
|
177
|
+
expect(consoleWarnSpy).toHaveBeenCalledWith(
|
|
178
|
+
expect.stringContaining('At least one of content_ids or contents is required for the AddToCart event')
|
|
179
|
+
)
|
|
180
|
+
expect(mockFbq).not.toHaveBeenCalled()
|
|
181
|
+
})
|
|
182
|
+
|
|
183
|
+
it('should warn if Purchase is missing both content_ids and contents', () => {
|
|
184
|
+
const payload = {
|
|
185
|
+
event_config: {
|
|
186
|
+
event_name: 'Purchase',
|
|
187
|
+
show_fields: false
|
|
188
|
+
},
|
|
189
|
+
value: 199.99,
|
|
190
|
+
currency: 'USD'
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
send(mockFbq, mockClientParamBuilder, payload, defaultSettings, mockAnalytics)
|
|
194
|
+
|
|
195
|
+
expect(consoleWarnSpy).toHaveBeenCalledWith(
|
|
196
|
+
expect.stringContaining('At least one of content_ids or contents is required for the Purchase event')
|
|
197
|
+
)
|
|
198
|
+
expect(mockFbq).not.toHaveBeenCalled()
|
|
199
|
+
})
|
|
200
|
+
|
|
201
|
+
it('should warn if ViewContent is missing both content_ids and contents', () => {
|
|
202
|
+
const payload = {
|
|
203
|
+
event_config: {
|
|
204
|
+
event_name: 'ViewContent',
|
|
205
|
+
show_fields: false
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
send(mockFbq, mockClientParamBuilder, payload, defaultSettings, mockAnalytics)
|
|
210
|
+
|
|
211
|
+
expect(consoleWarnSpy).toHaveBeenCalledWith(
|
|
212
|
+
expect.stringContaining('At least one of content_ids or contents is required for the ViewContent event')
|
|
213
|
+
)
|
|
214
|
+
expect(mockFbq).not.toHaveBeenCalled()
|
|
215
|
+
})
|
|
216
|
+
|
|
217
|
+
it('should not warn if AddToCart has content_ids', () => {
|
|
218
|
+
const payload = {
|
|
219
|
+
event_config: {
|
|
220
|
+
event_name: 'AddToCart',
|
|
221
|
+
show_fields: false
|
|
222
|
+
},
|
|
223
|
+
content_ids: ['product-123'],
|
|
224
|
+
value: 99.99
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
send(mockFbq, mockClientParamBuilder, payload, defaultSettings, mockAnalytics)
|
|
228
|
+
|
|
229
|
+
expect(consoleWarnSpy).not.toHaveBeenCalled()
|
|
230
|
+
expect(mockFbq).toHaveBeenCalled()
|
|
231
|
+
})
|
|
232
|
+
|
|
233
|
+
it('should not warn if AddToCart has contents', () => {
|
|
234
|
+
const payload = {
|
|
235
|
+
event_config: {
|
|
236
|
+
event_name: 'AddToCart',
|
|
237
|
+
show_fields: false
|
|
238
|
+
},
|
|
239
|
+
contents: [{ id: 'product-123', quantity: 1 }],
|
|
240
|
+
value: 99.99
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
send(mockFbq, mockClientParamBuilder, payload, defaultSettings, mockAnalytics)
|
|
244
|
+
|
|
245
|
+
expect(consoleWarnSpy).not.toHaveBeenCalled()
|
|
246
|
+
expect(mockFbq).toHaveBeenCalled()
|
|
247
|
+
})
|
|
248
|
+
})
|
|
249
|
+
|
|
250
|
+
describe('send - Event Options', () => {
|
|
251
|
+
it('should include eventID when provided', () => {
|
|
252
|
+
const payload = {
|
|
253
|
+
event_config: {
|
|
254
|
+
event_name: 'Purchase',
|
|
255
|
+
show_fields: false
|
|
256
|
+
},
|
|
257
|
+
content_ids: ['product-123'],
|
|
258
|
+
value: 99.99,
|
|
259
|
+
eventID: 'unique-event-id-123'
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
send(mockFbq, mockClientParamBuilder, payload, defaultSettings, mockAnalytics)
|
|
263
|
+
|
|
264
|
+
expect(mockFbq).toHaveBeenCalledWith(
|
|
265
|
+
'trackSingle',
|
|
266
|
+
'test-pixel-123',
|
|
267
|
+
'Purchase',
|
|
268
|
+
expect.any(Object),
|
|
269
|
+
expect.objectContaining({
|
|
270
|
+
eventID: 'unique-event-id-123'
|
|
271
|
+
})
|
|
272
|
+
)
|
|
273
|
+
})
|
|
274
|
+
|
|
275
|
+
it('should include eventSourceUrl when provided', () => {
|
|
276
|
+
const payload = {
|
|
277
|
+
event_config: {
|
|
278
|
+
event_name: 'Purchase',
|
|
279
|
+
show_fields: false
|
|
280
|
+
},
|
|
281
|
+
content_ids: ['product-123'],
|
|
282
|
+
value: 99.99,
|
|
283
|
+
eventSourceUrl: 'https://example.com/checkout'
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
send(mockFbq, mockClientParamBuilder, payload, defaultSettings, mockAnalytics)
|
|
287
|
+
|
|
288
|
+
expect(mockFbq).toHaveBeenCalledWith(
|
|
289
|
+
'trackSingle',
|
|
290
|
+
'test-pixel-123',
|
|
291
|
+
'Purchase',
|
|
292
|
+
expect.any(Object),
|
|
293
|
+
expect.objectContaining({
|
|
294
|
+
eventSourceUrl: 'https://example.com/checkout'
|
|
295
|
+
})
|
|
296
|
+
)
|
|
297
|
+
})
|
|
298
|
+
|
|
299
|
+
it('should include both eventID and eventSourceUrl when provided', () => {
|
|
300
|
+
const payload = {
|
|
301
|
+
event_config: {
|
|
302
|
+
event_name: 'Purchase',
|
|
303
|
+
show_fields: false
|
|
304
|
+
},
|
|
305
|
+
content_ids: ['product-123'],
|
|
306
|
+
value: 99.99,
|
|
307
|
+
eventID: 'unique-event-id-123',
|
|
308
|
+
eventSourceUrl: 'https://example.com/checkout'
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
send(mockFbq, mockClientParamBuilder, payload, defaultSettings, mockAnalytics)
|
|
312
|
+
|
|
313
|
+
expect(mockFbq).toHaveBeenCalledWith(
|
|
314
|
+
'trackSingle',
|
|
315
|
+
'test-pixel-123',
|
|
316
|
+
'Purchase',
|
|
317
|
+
expect.any(Object),
|
|
318
|
+
expect.objectContaining({
|
|
319
|
+
eventID: 'unique-event-id-123',
|
|
320
|
+
eventSourceUrl: 'https://example.com/checkout'
|
|
321
|
+
})
|
|
322
|
+
)
|
|
323
|
+
})
|
|
324
|
+
})
|
|
325
|
+
|
|
326
|
+
describe('send - User Data Formatting', () => {
|
|
327
|
+
it('should format userData with email', () => {
|
|
328
|
+
mockAnalytics.storage.get.mockReturnValue('0')
|
|
329
|
+
|
|
330
|
+
const payload = {
|
|
331
|
+
event_config: {
|
|
332
|
+
event_name: 'Purchase',
|
|
333
|
+
show_fields: false
|
|
334
|
+
},
|
|
335
|
+
content_ids: ['product-123'],
|
|
336
|
+
value: 99.99,
|
|
337
|
+
userData: {
|
|
338
|
+
em: 'TEST@EXAMPLE.COM'
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
send(mockFbq, mockClientParamBuilder, payload, defaultSettings, mockAnalytics)
|
|
343
|
+
|
|
344
|
+
// Should have called init with formatted user data
|
|
345
|
+
expect(mockFbq).toHaveBeenCalledWith('init', 'test-pixel-123', expect.objectContaining({ em: 'test@example.com' }))
|
|
346
|
+
// Should have stored user data
|
|
347
|
+
expect(mockAnalytics.storage.set).toHaveBeenCalledWith(
|
|
348
|
+
'fb_user_data',
|
|
349
|
+
expect.stringContaining('test@example.com')
|
|
350
|
+
)
|
|
351
|
+
})
|
|
352
|
+
|
|
353
|
+
it('should format userData with phone number', () => {
|
|
354
|
+
mockAnalytics.storage.get.mockReturnValue('0')
|
|
355
|
+
|
|
356
|
+
const payload = {
|
|
357
|
+
event_config: {
|
|
358
|
+
event_name: 'Purchase',
|
|
359
|
+
show_fields: false
|
|
360
|
+
},
|
|
361
|
+
content_ids: ['product-123'],
|
|
362
|
+
value: 99.99,
|
|
363
|
+
userData: {
|
|
364
|
+
ph: '(555) 123-4567'
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
send(mockFbq, mockClientParamBuilder, payload, defaultSettings, mockAnalytics)
|
|
369
|
+
|
|
370
|
+
// Phone should be cleaned of non-numeric characters
|
|
371
|
+
expect(mockFbq).toHaveBeenCalledWith('init', 'test-pixel-123', expect.objectContaining({ ph: '5551234567' }))
|
|
372
|
+
})
|
|
373
|
+
|
|
374
|
+
it('should format userData with first and last name', () => {
|
|
375
|
+
mockAnalytics.storage.get.mockReturnValue('0')
|
|
376
|
+
|
|
377
|
+
const payload = {
|
|
378
|
+
event_config: {
|
|
379
|
+
event_name: 'Purchase',
|
|
380
|
+
show_fields: false
|
|
381
|
+
},
|
|
382
|
+
content_ids: ['product-123'],
|
|
383
|
+
value: 99.99,
|
|
384
|
+
userData: {
|
|
385
|
+
fn: ' JOHN ',
|
|
386
|
+
ln: ' DOE '
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
send(mockFbq, mockClientParamBuilder, payload, defaultSettings, mockAnalytics)
|
|
391
|
+
|
|
392
|
+
// Names should be lowercased and trimmed
|
|
393
|
+
expect(mockFbq).toHaveBeenCalledWith(
|
|
394
|
+
'init',
|
|
395
|
+
'test-pixel-123',
|
|
396
|
+
expect.objectContaining({ fn: 'john', ln: 'doe' })
|
|
397
|
+
)
|
|
398
|
+
})
|
|
399
|
+
|
|
400
|
+
it('should format userData with gender', () => {
|
|
401
|
+
mockAnalytics.storage.get.mockReturnValue('0')
|
|
402
|
+
|
|
403
|
+
const payload = {
|
|
404
|
+
event_config: {
|
|
405
|
+
event_name: 'Purchase',
|
|
406
|
+
show_fields: false
|
|
407
|
+
},
|
|
408
|
+
content_ids: ['product-123'],
|
|
409
|
+
value: 99.99,
|
|
410
|
+
userData: {
|
|
411
|
+
ge: 'm'
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
send(mockFbq, mockClientParamBuilder, payload, defaultSettings, mockAnalytics)
|
|
416
|
+
|
|
417
|
+
expect(mockFbq).toHaveBeenCalledWith('init', 'test-pixel-123', expect.objectContaining({ ge: 'm' }))
|
|
418
|
+
})
|
|
419
|
+
|
|
420
|
+
it('should format userData with date of birth', () => {
|
|
421
|
+
mockAnalytics.storage.get.mockReturnValue('0')
|
|
422
|
+
|
|
423
|
+
const payload = {
|
|
424
|
+
event_config: {
|
|
425
|
+
event_name: 'Purchase',
|
|
426
|
+
show_fields: false
|
|
427
|
+
},
|
|
428
|
+
content_ids: ['product-123'],
|
|
429
|
+
value: 99.99,
|
|
430
|
+
userData: {
|
|
431
|
+
db: '1990-05-15T00:00:00.000Z'
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
send(mockFbq, mockClientParamBuilder, payload, defaultSettings, mockAnalytics)
|
|
436
|
+
|
|
437
|
+
// Date should be formatted as YYYYMMDD
|
|
438
|
+
expect(mockFbq).toHaveBeenCalledWith('init', 'test-pixel-123', expect.objectContaining({ db: '19900515' }))
|
|
439
|
+
})
|
|
440
|
+
|
|
441
|
+
it('should format userData with city', () => {
|
|
442
|
+
mockAnalytics.storage.get.mockReturnValue('0')
|
|
443
|
+
|
|
444
|
+
const payload = {
|
|
445
|
+
event_config: {
|
|
446
|
+
event_name: 'Purchase',
|
|
447
|
+
show_fields: false
|
|
448
|
+
},
|
|
449
|
+
content_ids: ['product-123'],
|
|
450
|
+
value: 99.99,
|
|
451
|
+
userData: {
|
|
452
|
+
ct: ' New York '
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
send(mockFbq, mockClientParamBuilder, payload, defaultSettings, mockAnalytics)
|
|
457
|
+
|
|
458
|
+
// City should be lowercased with spaces removed
|
|
459
|
+
expect(mockFbq).toHaveBeenCalledWith('init', 'test-pixel-123', expect.objectContaining({ ct: 'newyork' }))
|
|
460
|
+
})
|
|
461
|
+
|
|
462
|
+
it('should format userData with US state - full name to code', () => {
|
|
463
|
+
mockAnalytics.storage.get.mockReturnValue('0')
|
|
464
|
+
|
|
465
|
+
const payload = {
|
|
466
|
+
event_config: {
|
|
467
|
+
event_name: 'Purchase',
|
|
468
|
+
show_fields: false
|
|
469
|
+
},
|
|
470
|
+
content_ids: ['product-123'],
|
|
471
|
+
value: 99.99,
|
|
472
|
+
userData: {
|
|
473
|
+
st: 'California'
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
send(mockFbq, mockClientParamBuilder, payload, defaultSettings, mockAnalytics)
|
|
478
|
+
|
|
479
|
+
// State should be converted to 2-letter code
|
|
480
|
+
expect(mockFbq).toHaveBeenCalledWith('init', 'test-pixel-123', expect.objectContaining({ st: 'ca' }))
|
|
481
|
+
})
|
|
482
|
+
|
|
483
|
+
it('should format userData with US state - already 2-letter code', () => {
|
|
484
|
+
mockAnalytics.storage.get.mockReturnValue('0')
|
|
485
|
+
|
|
486
|
+
const payload = {
|
|
487
|
+
event_config: {
|
|
488
|
+
event_name: 'Purchase',
|
|
489
|
+
show_fields: false
|
|
490
|
+
},
|
|
491
|
+
content_ids: ['product-123'],
|
|
492
|
+
value: 99.99,
|
|
493
|
+
userData: {
|
|
494
|
+
st: 'NY'
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
send(mockFbq, mockClientParamBuilder, payload, defaultSettings, mockAnalytics)
|
|
499
|
+
|
|
500
|
+
// State code should be lowercased
|
|
501
|
+
expect(mockFbq).toHaveBeenCalledWith('init', 'test-pixel-123', expect.objectContaining({ st: 'ny' }))
|
|
502
|
+
})
|
|
503
|
+
|
|
504
|
+
it('should format userData with country - full name to code', () => {
|
|
505
|
+
mockAnalytics.storage.get.mockReturnValue('0')
|
|
506
|
+
|
|
507
|
+
const payload = {
|
|
508
|
+
event_config: {
|
|
509
|
+
event_name: 'Purchase',
|
|
510
|
+
show_fields: false
|
|
511
|
+
},
|
|
512
|
+
content_ids: ['product-123'],
|
|
513
|
+
value: 99.99,
|
|
514
|
+
userData: {
|
|
515
|
+
country: 'United States'
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
send(mockFbq, mockClientParamBuilder, payload, defaultSettings, mockAnalytics)
|
|
520
|
+
|
|
521
|
+
// Country should be converted to 2-letter code
|
|
522
|
+
expect(mockFbq).toHaveBeenCalledWith('init', 'test-pixel-123', expect.objectContaining({ country: 'us' }))
|
|
523
|
+
})
|
|
524
|
+
|
|
525
|
+
it('should format userData with country - already 2-letter code', () => {
|
|
526
|
+
mockAnalytics.storage.get.mockReturnValue('0')
|
|
527
|
+
|
|
528
|
+
const payload = {
|
|
529
|
+
event_config: {
|
|
530
|
+
event_name: 'Purchase',
|
|
531
|
+
show_fields: false
|
|
532
|
+
},
|
|
533
|
+
content_ids: ['product-123'],
|
|
534
|
+
value: 99.99,
|
|
535
|
+
userData: {
|
|
536
|
+
country: 'GB'
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
send(mockFbq, mockClientParamBuilder, payload, defaultSettings, mockAnalytics)
|
|
541
|
+
|
|
542
|
+
// Country code should be lowercased
|
|
543
|
+
expect(mockFbq).toHaveBeenCalledWith('init', 'test-pixel-123', expect.objectContaining({ country: 'gb' }))
|
|
544
|
+
})
|
|
545
|
+
|
|
546
|
+
it('should format userData with zip code', () => {
|
|
547
|
+
mockAnalytics.storage.get.mockReturnValue('0')
|
|
548
|
+
|
|
549
|
+
const payload = {
|
|
550
|
+
event_config: {
|
|
551
|
+
event_name: 'Purchase',
|
|
552
|
+
show_fields: false
|
|
553
|
+
},
|
|
554
|
+
content_ids: ['product-123'],
|
|
555
|
+
value: 99.99,
|
|
556
|
+
userData: {
|
|
557
|
+
zp: ' 94102 '
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
send(mockFbq, mockClientParamBuilder, payload, defaultSettings, mockAnalytics)
|
|
562
|
+
|
|
563
|
+
// Zip should be trimmed
|
|
564
|
+
expect(mockFbq).toHaveBeenCalledWith('init', 'test-pixel-123', expect.objectContaining({ zp: '94102' }))
|
|
565
|
+
})
|
|
566
|
+
|
|
567
|
+
it('should format userData with external_id', () => {
|
|
568
|
+
mockAnalytics.storage.get.mockReturnValue('0')
|
|
569
|
+
|
|
570
|
+
const payload = {
|
|
571
|
+
event_config: {
|
|
572
|
+
event_name: 'Purchase',
|
|
573
|
+
show_fields: false
|
|
574
|
+
},
|
|
575
|
+
content_ids: ['product-123'],
|
|
576
|
+
value: 99.99,
|
|
577
|
+
userData: {
|
|
578
|
+
external_id: ' user-123 '
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
send(mockFbq, mockClientParamBuilder, payload, defaultSettings, mockAnalytics)
|
|
583
|
+
|
|
584
|
+
// External ID should be trimmed
|
|
585
|
+
expect(mockFbq).toHaveBeenCalledWith('init', 'test-pixel-123', expect.objectContaining({ external_id: 'user-123' }))
|
|
586
|
+
})
|
|
587
|
+
|
|
588
|
+
it('should format userData with fbp and fbc cookies', () => {
|
|
589
|
+
mockAnalytics.storage.get.mockReturnValue('0')
|
|
590
|
+
|
|
591
|
+
const payload = {
|
|
592
|
+
event_config: {
|
|
593
|
+
event_name: 'Purchase',
|
|
594
|
+
show_fields: false
|
|
595
|
+
},
|
|
596
|
+
content_ids: ['product-123'],
|
|
597
|
+
value: 99.99,
|
|
598
|
+
userData: {
|
|
599
|
+
fbp: ' fb.1.1234567890.1234567890 ',
|
|
600
|
+
fbc: ' fb.1.1234567890.AbCdEf123 '
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
send(mockFbq, mockClientParamBuilder, payload, defaultSettings, mockAnalytics)
|
|
605
|
+
|
|
606
|
+
// FBP and FBC should be trimmed
|
|
607
|
+
expect(mockFbq).toHaveBeenCalledWith(
|
|
608
|
+
'init',
|
|
609
|
+
'test-pixel-123',
|
|
610
|
+
expect.objectContaining({
|
|
611
|
+
fbp: 'fb.1.1234567890.1234567890',
|
|
612
|
+
fbc: 'fb.1.1234567890.AbCdEf123'
|
|
613
|
+
})
|
|
614
|
+
)
|
|
615
|
+
})
|
|
616
|
+
|
|
617
|
+
it('should format userData with all fields combined', () => {
|
|
618
|
+
mockAnalytics.storage.get.mockReturnValue('0')
|
|
619
|
+
|
|
620
|
+
const payload = {
|
|
621
|
+
event_config: {
|
|
622
|
+
event_name: 'Purchase',
|
|
623
|
+
show_fields: false
|
|
624
|
+
},
|
|
625
|
+
content_ids: ['product-123'],
|
|
626
|
+
value: 99.99,
|
|
627
|
+
userData: {
|
|
628
|
+
external_id: 'user-123',
|
|
629
|
+
em: 'test@example.com',
|
|
630
|
+
ph: '5551234567',
|
|
631
|
+
fn: 'John',
|
|
632
|
+
ln: 'Doe',
|
|
633
|
+
ge: 'm',
|
|
634
|
+
db: '1990-05-15T00:00:00.000Z',
|
|
635
|
+
ct: 'San Francisco',
|
|
636
|
+
st: 'California',
|
|
637
|
+
zp: '94102',
|
|
638
|
+
country: 'United States',
|
|
639
|
+
fbp: 'fb.1.1234567890.1234567890',
|
|
640
|
+
fbc: 'fb.1.1234567890.AbCdEf123'
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
send(mockFbq, mockClientParamBuilder, payload, defaultSettings, mockAnalytics)
|
|
645
|
+
|
|
646
|
+
expect(mockFbq).toHaveBeenCalledWith(
|
|
647
|
+
'init',
|
|
648
|
+
'test-pixel-123',
|
|
649
|
+
expect.objectContaining({
|
|
650
|
+
external_id: 'user-123',
|
|
651
|
+
em: 'test@example.com',
|
|
652
|
+
ph: '5551234567',
|
|
653
|
+
fn: 'john',
|
|
654
|
+
ln: 'doe',
|
|
655
|
+
ge: 'm',
|
|
656
|
+
db: '19900515',
|
|
657
|
+
ct: 'sanfrancisco',
|
|
658
|
+
st: 'ca',
|
|
659
|
+
zp: '94102',
|
|
660
|
+
country: 'us',
|
|
661
|
+
fbp: 'fb.1.1234567890.1234567890',
|
|
662
|
+
fbc: 'fb.1.1234567890.AbCdEf123'
|
|
663
|
+
})
|
|
664
|
+
)
|
|
665
|
+
})
|
|
666
|
+
|
|
667
|
+
it('should not send userData init when init count is at max', () => {
|
|
668
|
+
mockAnalytics.storage.get.mockReturnValue('2')
|
|
669
|
+
|
|
670
|
+
const payload = {
|
|
671
|
+
event_config: {
|
|
672
|
+
event_name: 'Purchase',
|
|
673
|
+
show_fields: false
|
|
674
|
+
},
|
|
675
|
+
content_ids: ['product-123'],
|
|
676
|
+
value: 99.99,
|
|
677
|
+
userData: {
|
|
678
|
+
em: 'test@example.com'
|
|
679
|
+
}
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
send(mockFbq, mockClientParamBuilder, payload, defaultSettings, mockAnalytics)
|
|
683
|
+
|
|
684
|
+
// Should not call init with user data when count is at max
|
|
685
|
+
const initCalls = (mockFbq).mock.calls.filter((call) => call[0] === 'init')
|
|
686
|
+
expect(initCalls.length).toBe(0)
|
|
687
|
+
})
|
|
688
|
+
|
|
689
|
+
it('should skip invalid gender values', () => {
|
|
690
|
+
mockAnalytics.storage.get.mockReturnValue('0')
|
|
691
|
+
|
|
692
|
+
const payload = {
|
|
693
|
+
event_config: {
|
|
694
|
+
event_name: 'Purchase',
|
|
695
|
+
show_fields: false
|
|
696
|
+
},
|
|
697
|
+
content_ids: ['product-123'],
|
|
698
|
+
value: 99.99,
|
|
699
|
+
userData: {
|
|
700
|
+
ge: 'invalid'
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
send(mockFbq, mockClientParamBuilder, payload, defaultSettings, mockAnalytics)
|
|
705
|
+
|
|
706
|
+
// Should not call init if only invalid gender is provided
|
|
707
|
+
const initCalls = (mockFbq).mock.calls.filter((call) => call[0] === 'init')
|
|
708
|
+
expect(initCalls.length).toBe(0)
|
|
709
|
+
})
|
|
710
|
+
|
|
711
|
+
it('should skip invalid date of birth', () => {
|
|
712
|
+
mockAnalytics.storage.get.mockReturnValue('0')
|
|
713
|
+
|
|
714
|
+
const payload = {
|
|
715
|
+
event_config: {
|
|
716
|
+
event_name: 'Purchase',
|
|
717
|
+
show_fields: false
|
|
718
|
+
},
|
|
719
|
+
content_ids: ['product-123'],
|
|
720
|
+
value: 99.99,
|
|
721
|
+
userData: {
|
|
722
|
+
db: 'invalid-date'
|
|
723
|
+
}
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
send(mockFbq, mockClientParamBuilder, payload, defaultSettings, mockAnalytics)
|
|
727
|
+
|
|
728
|
+
// Should not call init if only invalid date is provided
|
|
729
|
+
const initCalls = (mockFbq).mock.calls.filter((call) => call[0] === 'init')
|
|
730
|
+
expect(initCalls.length).toBe(0)
|
|
731
|
+
})
|
|
732
|
+
})
|
|
733
|
+
|
|
734
|
+
describe('send - Event Data Fields', () => {
|
|
735
|
+
it('should include all event fields when show_fields is true', () => {
|
|
736
|
+
const payload = {
|
|
737
|
+
event_config: {
|
|
738
|
+
event_name: 'Purchase',
|
|
739
|
+
show_fields: true
|
|
740
|
+
},
|
|
741
|
+
content_ids: ['product-123'],
|
|
742
|
+
content_name: 'Test Product',
|
|
743
|
+
content_category: 'Electronics',
|
|
744
|
+
content_type: 'product',
|
|
745
|
+
value: 99.99,
|
|
746
|
+
currency: 'USD',
|
|
747
|
+
num_items: 1,
|
|
748
|
+
delivery_category: 'home_delivery'
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
send(mockFbq, mockClientParamBuilder, payload, defaultSettings, mockAnalytics)
|
|
752
|
+
|
|
753
|
+
expect(mockFbq).toHaveBeenCalledWith(
|
|
754
|
+
'trackSingle',
|
|
755
|
+
'test-pixel-123',
|
|
756
|
+
'Purchase',
|
|
757
|
+
expect.objectContaining({
|
|
758
|
+
content_ids: ['product-123'],
|
|
759
|
+
content_name: 'Test Product',
|
|
760
|
+
content_category: 'Electronics',
|
|
761
|
+
content_type: 'product',
|
|
762
|
+
value: 99.99,
|
|
763
|
+
currency: 'USD',
|
|
764
|
+
num_items: 1,
|
|
765
|
+
delivery_category: 'home_delivery'
|
|
766
|
+
}),
|
|
767
|
+
undefined
|
|
768
|
+
)
|
|
769
|
+
})
|
|
770
|
+
|
|
771
|
+
it('should include predicted_ltv for Subscribe event', () => {
|
|
772
|
+
const payload = {
|
|
773
|
+
event_config: {
|
|
774
|
+
event_name: 'Subscribe',
|
|
775
|
+
show_fields: false
|
|
776
|
+
},
|
|
777
|
+
predicted_ltv: 500.0,
|
|
778
|
+
value: 50.0
|
|
779
|
+
}
|
|
780
|
+
|
|
781
|
+
send(mockFbq, mockClientParamBuilder, payload, defaultSettings, mockAnalytics)
|
|
782
|
+
|
|
783
|
+
expect(mockFbq).toHaveBeenCalledWith(
|
|
784
|
+
'trackSingle',
|
|
785
|
+
'test-pixel-123',
|
|
786
|
+
'Subscribe',
|
|
787
|
+
expect.objectContaining({
|
|
788
|
+
predicted_ltv: 500.0,
|
|
789
|
+
value: 50.0
|
|
790
|
+
}),
|
|
791
|
+
undefined
|
|
792
|
+
)
|
|
793
|
+
})
|
|
794
|
+
|
|
795
|
+
it('should include net_revenue for Purchase event', () => {
|
|
796
|
+
const payload = {
|
|
797
|
+
event_config: {
|
|
798
|
+
event_name: 'Purchase',
|
|
799
|
+
show_fields: false
|
|
800
|
+
},
|
|
801
|
+
content_ids: ['product-123'],
|
|
802
|
+
net_revenue: 450.0,
|
|
803
|
+
value: 50.0
|
|
804
|
+
}
|
|
805
|
+
|
|
806
|
+
send(mockFbq, mockClientParamBuilder, payload, defaultSettings, mockAnalytics)
|
|
807
|
+
|
|
808
|
+
expect(mockFbq).toHaveBeenCalledWith(
|
|
809
|
+
'trackSingle',
|
|
810
|
+
'test-pixel-123',
|
|
811
|
+
'Purchase',
|
|
812
|
+
expect.objectContaining({
|
|
813
|
+
net_revenue: 450.0,
|
|
814
|
+
value: 50.0
|
|
815
|
+
}),
|
|
816
|
+
undefined
|
|
817
|
+
)
|
|
818
|
+
})
|
|
819
|
+
|
|
820
|
+
it('should include custom_data', () => {
|
|
821
|
+
const payload = {
|
|
822
|
+
event_config: {
|
|
823
|
+
event_name: 'Purchase',
|
|
824
|
+
show_fields: false
|
|
825
|
+
},
|
|
826
|
+
content_ids: ['product-123'],
|
|
827
|
+
value: 99.99,
|
|
828
|
+
custom_data: {
|
|
829
|
+
order_id: 'order-789',
|
|
830
|
+
campaign_id: 'summer-sale',
|
|
831
|
+
user_tier: 'premium'
|
|
832
|
+
}
|
|
833
|
+
}
|
|
834
|
+
|
|
835
|
+
send(mockFbq, mockClientParamBuilder, payload, defaultSettings, mockAnalytics)
|
|
836
|
+
|
|
837
|
+
expect(mockFbq).toHaveBeenCalledWith(
|
|
838
|
+
'trackSingle',
|
|
839
|
+
'test-pixel-123',
|
|
840
|
+
'Purchase',
|
|
841
|
+
expect.objectContaining({
|
|
842
|
+
custom_data: {
|
|
843
|
+
order_id: 'order-789',
|
|
844
|
+
campaign_id: 'summer-sale',
|
|
845
|
+
user_tier: 'premium'
|
|
846
|
+
}
|
|
847
|
+
}),
|
|
848
|
+
undefined
|
|
849
|
+
)
|
|
850
|
+
})
|
|
851
|
+
|
|
852
|
+
it('should not include empty arrays or objects', () => {
|
|
853
|
+
const payload = {
|
|
854
|
+
event_config: {
|
|
855
|
+
event_name: 'PageView',
|
|
856
|
+
show_fields: false
|
|
857
|
+
},
|
|
858
|
+
content_ids: [],
|
|
859
|
+
contents: [],
|
|
860
|
+
custom_data: {}
|
|
861
|
+
}
|
|
862
|
+
|
|
863
|
+
send(mockFbq, mockClientParamBuilder, payload, defaultSettings, mockAnalytics)
|
|
864
|
+
|
|
865
|
+
const eventData = (mockFbq).mock.calls[0][3]
|
|
866
|
+
expect(eventData).toEqual({})
|
|
867
|
+
})
|
|
868
|
+
|
|
869
|
+
it('should handle numeric values correctly including zero', () => {
|
|
870
|
+
const payload = {
|
|
871
|
+
event_config: {
|
|
872
|
+
event_name: 'InitiateCheckout',
|
|
873
|
+
show_fields: false
|
|
874
|
+
},
|
|
875
|
+
content_ids: ['product-123'],
|
|
876
|
+
value: 0,
|
|
877
|
+
num_items: 0
|
|
878
|
+
}
|
|
879
|
+
|
|
880
|
+
send(mockFbq, mockClientParamBuilder, payload, defaultSettings, mockAnalytics)
|
|
881
|
+
|
|
882
|
+
expect(mockFbq).toHaveBeenCalledWith(
|
|
883
|
+
'trackSingle',
|
|
884
|
+
'test-pixel-123',
|
|
885
|
+
'InitiateCheckout',
|
|
886
|
+
expect.objectContaining({
|
|
887
|
+
value: 0,
|
|
888
|
+
num_items: 0
|
|
889
|
+
}),
|
|
890
|
+
undefined
|
|
891
|
+
)
|
|
892
|
+
})
|
|
893
|
+
})
|
|
894
|
+
|
|
895
|
+
describe('send - Client Param Builder (formatUserDataWithParamBuilder)', () => {
|
|
896
|
+
let mockClientParamBuilderInstance
|
|
897
|
+
|
|
898
|
+
beforeEach(() => {
|
|
899
|
+
mockClientParamBuilderInstance = {
|
|
900
|
+
getNormalizedAndHashedPII: jest.fn(),
|
|
901
|
+
processAndCollectAllParams: jest.fn(),
|
|
902
|
+
getFbc: jest.fn(),
|
|
903
|
+
getFbp: jest.fn()
|
|
904
|
+
}
|
|
905
|
+
})
|
|
906
|
+
|
|
907
|
+
it('should use clientParamBuilder to format email when available', () => {
|
|
908
|
+
mockAnalytics.storage.get.mockReturnValue('0')
|
|
909
|
+
mockClientParamBuilderInstance.getNormalizedAndHashedPII.mockReturnValue('hashed_email_value')
|
|
910
|
+
|
|
911
|
+
const payload = {
|
|
912
|
+
event_config: {
|
|
913
|
+
event_name: 'Purchase',
|
|
914
|
+
show_fields: false
|
|
915
|
+
},
|
|
916
|
+
content_ids: ['product-123'],
|
|
917
|
+
value: 99.99,
|
|
918
|
+
userData: {
|
|
919
|
+
em: 'TEST@EXAMPLE.COM'
|
|
920
|
+
}
|
|
921
|
+
}
|
|
922
|
+
|
|
923
|
+
send(mockFbq, mockClientParamBuilderInstance, payload, defaultSettings, mockAnalytics)
|
|
924
|
+
|
|
925
|
+
expect(mockClientParamBuilderInstance.processAndCollectAllParams).toHaveBeenCalled()
|
|
926
|
+
expect(mockClientParamBuilderInstance.getNormalizedAndHashedPII).toHaveBeenCalledWith('TEST@EXAMPLE.COM', 'email')
|
|
927
|
+
expect(mockFbq).toHaveBeenCalledWith('init', 'test-pixel-123', expect.objectContaining({ em: 'hashed_email_value' }))
|
|
928
|
+
})
|
|
929
|
+
|
|
930
|
+
it('should use clientParamBuilder to format phone number when available', () => {
|
|
931
|
+
mockAnalytics.storage.get.mockReturnValue('0')
|
|
932
|
+
mockClientParamBuilderInstance.getNormalizedAndHashedPII.mockReturnValue('hashed_phone_value')
|
|
933
|
+
|
|
934
|
+
const payload = {
|
|
935
|
+
event_config: {
|
|
936
|
+
event_name: 'Purchase',
|
|
937
|
+
show_fields: false
|
|
938
|
+
},
|
|
939
|
+
content_ids: ['product-123'],
|
|
940
|
+
value: 99.99,
|
|
941
|
+
userData: {
|
|
942
|
+
ph: '+1 (555) 123-4567'
|
|
943
|
+
}
|
|
944
|
+
}
|
|
945
|
+
|
|
946
|
+
send(mockFbq, mockClientParamBuilderInstance, payload, defaultSettings, mockAnalytics)
|
|
947
|
+
|
|
948
|
+
expect(mockClientParamBuilderInstance.getNormalizedAndHashedPII).toHaveBeenCalledWith(
|
|
949
|
+
'+1 (555) 123-4567',
|
|
950
|
+
'phone'
|
|
951
|
+
)
|
|
952
|
+
expect(mockFbq).toHaveBeenCalledWith('init', 'test-pixel-123', expect.objectContaining({ ph: 'hashed_phone_value' }))
|
|
953
|
+
})
|
|
954
|
+
|
|
955
|
+
it('should use clientParamBuilder to format all PII fields', () => {
|
|
956
|
+
mockAnalytics.storage.get.mockReturnValue('0')
|
|
957
|
+
mockClientParamBuilderInstance.getNormalizedAndHashedPII.mockImplementation((_, type) => {
|
|
958
|
+
return `hashed_${type}_value`
|
|
959
|
+
})
|
|
960
|
+
|
|
961
|
+
const payload = {
|
|
962
|
+
event_config: {
|
|
963
|
+
event_name: 'Purchase',
|
|
964
|
+
show_fields: false
|
|
965
|
+
},
|
|
966
|
+
content_ids: ['product-123'],
|
|
967
|
+
value: 99.99,
|
|
968
|
+
userData: {
|
|
969
|
+
em: 'test@example.com',
|
|
970
|
+
ph: '5551234567',
|
|
971
|
+
fn: 'John',
|
|
972
|
+
ln: 'Doe',
|
|
973
|
+
ge: 'm',
|
|
974
|
+
db: '1990-05-15',
|
|
975
|
+
ct: 'San Francisco',
|
|
976
|
+
st: 'CA',
|
|
977
|
+
zp: '94102',
|
|
978
|
+
country: 'US',
|
|
979
|
+
external_id: 'user-123'
|
|
980
|
+
}
|
|
981
|
+
}
|
|
982
|
+
|
|
983
|
+
send(mockFbq, mockClientParamBuilderInstance, payload, defaultSettings, mockAnalytics)
|
|
984
|
+
|
|
985
|
+
expect(mockClientParamBuilderInstance.getNormalizedAndHashedPII).toHaveBeenCalledWith('test@example.com', 'email')
|
|
986
|
+
expect(mockClientParamBuilderInstance.getNormalizedAndHashedPII).toHaveBeenCalledWith('5551234567', 'phone')
|
|
987
|
+
expect(mockClientParamBuilderInstance.getNormalizedAndHashedPII).toHaveBeenCalledWith('John', 'first_name')
|
|
988
|
+
expect(mockClientParamBuilderInstance.getNormalizedAndHashedPII).toHaveBeenCalledWith('Doe', 'last_name')
|
|
989
|
+
expect(mockClientParamBuilderInstance.getNormalizedAndHashedPII).toHaveBeenCalledWith('m', 'gender')
|
|
990
|
+
expect(mockClientParamBuilderInstance.getNormalizedAndHashedPII).toHaveBeenCalledWith('1990-05-15', 'date_of_birth')
|
|
991
|
+
expect(mockClientParamBuilderInstance.getNormalizedAndHashedPII).toHaveBeenCalledWith('San Francisco', 'city')
|
|
992
|
+
expect(mockClientParamBuilderInstance.getNormalizedAndHashedPII).toHaveBeenCalledWith('CA', 'state')
|
|
993
|
+
expect(mockClientParamBuilderInstance.getNormalizedAndHashedPII).toHaveBeenCalledWith('94102', 'zip_code')
|
|
994
|
+
expect(mockClientParamBuilderInstance.getNormalizedAndHashedPII).toHaveBeenCalledWith('US', 'country')
|
|
995
|
+
expect(mockClientParamBuilderInstance.getNormalizedAndHashedPII).toHaveBeenCalledWith('user-123', 'external_id')
|
|
996
|
+
|
|
997
|
+
expect(mockFbq).toHaveBeenCalledWith(
|
|
998
|
+
'init',
|
|
999
|
+
'test-pixel-123',
|
|
1000
|
+
expect.objectContaining({
|
|
1001
|
+
em: 'hashed_email_value',
|
|
1002
|
+
ph: 'hashed_phone_value',
|
|
1003
|
+
fn: 'hashed_first_name_value',
|
|
1004
|
+
ln: 'hashed_last_name_value',
|
|
1005
|
+
ge: 'hashed_gender_value',
|
|
1006
|
+
db: 'hashed_date_of_birth_value',
|
|
1007
|
+
ct: 'hashed_city_value',
|
|
1008
|
+
st: 'hashed_state_value',
|
|
1009
|
+
zp: 'hashed_zip_code_value',
|
|
1010
|
+
country: 'hashed_country_value',
|
|
1011
|
+
external_id: 'hashed_external_id_value'
|
|
1012
|
+
})
|
|
1013
|
+
)
|
|
1014
|
+
})
|
|
1015
|
+
|
|
1016
|
+
it('should use clientParamBuilder getFbc and getFbp methods', () => {
|
|
1017
|
+
mockAnalytics.storage.get.mockReturnValue('0')
|
|
1018
|
+
mockClientParamBuilderInstance.getFbc.mockReturnValue('fb.1.1234567890.ClientParamBuilderFbc')
|
|
1019
|
+
mockClientParamBuilderInstance.getFbp.mockReturnValue('fb.1.1234567890.ClientParamBuilderFbp')
|
|
1020
|
+
|
|
1021
|
+
const payload = {
|
|
1022
|
+
event_config: {
|
|
1023
|
+
event_name: 'Purchase',
|
|
1024
|
+
show_fields: false
|
|
1025
|
+
},
|
|
1026
|
+
content_ids: ['product-123'],
|
|
1027
|
+
value: 99.99,
|
|
1028
|
+
userData: {
|
|
1029
|
+
em: 'test@example.com',
|
|
1030
|
+
fbc: 'fb.1.1234567890.PayloadFbc',
|
|
1031
|
+
fbp: 'fb.1.1234567890.PayloadFbp'
|
|
1032
|
+
}
|
|
1033
|
+
}
|
|
1034
|
+
|
|
1035
|
+
send(mockFbq, mockClientParamBuilderInstance, payload, defaultSettings, mockAnalytics)
|
|
1036
|
+
|
|
1037
|
+
expect(mockClientParamBuilderInstance.processAndCollectAllParams).toHaveBeenCalled()
|
|
1038
|
+
expect(mockClientParamBuilderInstance.getFbc).toHaveBeenCalled()
|
|
1039
|
+
expect(mockClientParamBuilderInstance.getFbp).toHaveBeenCalled()
|
|
1040
|
+
|
|
1041
|
+
// ClientParamBuilder values should override payload values
|
|
1042
|
+
expect(mockFbq).toHaveBeenCalledWith(
|
|
1043
|
+
'init',
|
|
1044
|
+
'test-pixel-123',
|
|
1045
|
+
expect.objectContaining({
|
|
1046
|
+
fbc: 'fb.1.1234567890.ClientParamBuilderFbc',
|
|
1047
|
+
fbp: 'fb.1.1234567890.ClientParamBuilderFbp'
|
|
1048
|
+
})
|
|
1049
|
+
)
|
|
1050
|
+
})
|
|
1051
|
+
|
|
1052
|
+
it('should use payload fbc/fbp when clientParamBuilder methods return null', () => {
|
|
1053
|
+
mockAnalytics.storage.get.mockReturnValue('0')
|
|
1054
|
+
mockClientParamBuilderInstance.getFbc.mockReturnValue(null)
|
|
1055
|
+
mockClientParamBuilderInstance.getFbp.mockReturnValue(null)
|
|
1056
|
+
|
|
1057
|
+
const payload = {
|
|
1058
|
+
event_config: {
|
|
1059
|
+
event_name: 'Purchase',
|
|
1060
|
+
show_fields: false
|
|
1061
|
+
},
|
|
1062
|
+
content_ids: ['product-123'],
|
|
1063
|
+
value: 99.99,
|
|
1064
|
+
userData: {
|
|
1065
|
+
em: 'test@example.com',
|
|
1066
|
+
fbc: 'fb.1.1234567890.PayloadFbc',
|
|
1067
|
+
fbp: 'fb.1.1234567890.PayloadFbp'
|
|
1068
|
+
}
|
|
1069
|
+
}
|
|
1070
|
+
|
|
1071
|
+
send(mockFbq, mockClientParamBuilderInstance, payload, defaultSettings, mockAnalytics)
|
|
1072
|
+
|
|
1073
|
+
expect(mockClientParamBuilderInstance.getFbc).toHaveBeenCalled()
|
|
1074
|
+
expect(mockClientParamBuilderInstance.getFbp).toHaveBeenCalled()
|
|
1075
|
+
|
|
1076
|
+
// Should fall back to payload values when clientParamBuilder returns null
|
|
1077
|
+
expect(mockFbq).toHaveBeenCalledWith(
|
|
1078
|
+
'init',
|
|
1079
|
+
'test-pixel-123',
|
|
1080
|
+
expect.objectContaining({
|
|
1081
|
+
fbc: 'fb.1.1234567890.PayloadFbc',
|
|
1082
|
+
fbp: 'fb.1.1234567890.PayloadFbp'
|
|
1083
|
+
})
|
|
1084
|
+
)
|
|
1085
|
+
})
|
|
1086
|
+
|
|
1087
|
+
it('should fall back to default formatting when clientParamBuilder returns undefined', () => {
|
|
1088
|
+
mockAnalytics.storage.get.mockReturnValue('0')
|
|
1089
|
+
mockClientParamBuilderInstance.getNormalizedAndHashedPII.mockReturnValue(undefined)
|
|
1090
|
+
|
|
1091
|
+
const payload = {
|
|
1092
|
+
event_config: {
|
|
1093
|
+
event_name: 'Purchase',
|
|
1094
|
+
show_fields: false
|
|
1095
|
+
},
|
|
1096
|
+
content_ids: ['product-123'],
|
|
1097
|
+
value: 99.99,
|
|
1098
|
+
userData: {
|
|
1099
|
+
em: 'TEST@EXAMPLE.COM',
|
|
1100
|
+
ph: '(555) 123-4567'
|
|
1101
|
+
}
|
|
1102
|
+
}
|
|
1103
|
+
|
|
1104
|
+
send(mockFbq, mockClientParamBuilderInstance, payload, defaultSettings, mockAnalytics)
|
|
1105
|
+
|
|
1106
|
+
expect(mockClientParamBuilderInstance.getNormalizedAndHashedPII).toHaveBeenCalledWith('TEST@EXAMPLE.COM', 'email')
|
|
1107
|
+
expect(mockClientParamBuilderInstance.getNormalizedAndHashedPII).toHaveBeenCalledWith('(555) 123-4567', 'phone')
|
|
1108
|
+
|
|
1109
|
+
// When clientParamBuilder returns undefined, should fall back to default formatting
|
|
1110
|
+
expect(mockFbq).toHaveBeenCalledWith(
|
|
1111
|
+
'init',
|
|
1112
|
+
'test-pixel-123',
|
|
1113
|
+
expect.objectContaining({
|
|
1114
|
+
em: 'test@example.com',
|
|
1115
|
+
ph: '5551234567'
|
|
1116
|
+
})
|
|
1117
|
+
)
|
|
1118
|
+
})
|
|
1119
|
+
|
|
1120
|
+
it('should call processAndCollectAllParams before getting cookie values', () => {
|
|
1121
|
+
mockAnalytics.storage.get.mockReturnValue('0')
|
|
1122
|
+
mockClientParamBuilderInstance.getFbc.mockReturnValue('fb.1.fbc')
|
|
1123
|
+
mockClientParamBuilderInstance.getFbp.mockReturnValue('fb.1.fbp')
|
|
1124
|
+
|
|
1125
|
+
const payload = {
|
|
1126
|
+
event_config: {
|
|
1127
|
+
event_name: 'Purchase',
|
|
1128
|
+
show_fields: false
|
|
1129
|
+
},
|
|
1130
|
+
content_ids: ['product-123'],
|
|
1131
|
+
value: 99.99,
|
|
1132
|
+
userData: {
|
|
1133
|
+
em: 'test@example.com'
|
|
1134
|
+
}
|
|
1135
|
+
}
|
|
1136
|
+
|
|
1137
|
+
send(mockFbq, mockClientParamBuilderInstance, payload, defaultSettings, mockAnalytics)
|
|
1138
|
+
|
|
1139
|
+
const calls = mockClientParamBuilderInstance.processAndCollectAllParams.mock.invocationCallOrder
|
|
1140
|
+
const fbcCalls = mockClientParamBuilderInstance.getFbc.mock.invocationCallOrder
|
|
1141
|
+
const fbpCalls = mockClientParamBuilderInstance.getFbp.mock.invocationCallOrder
|
|
1142
|
+
|
|
1143
|
+
// processAndCollectAllParams should be called before getFbc/getFbp
|
|
1144
|
+
expect(calls[0]).toBeLessThan(fbcCalls[0])
|
|
1145
|
+
expect(calls[0]).toBeLessThan(fbpCalls[0])
|
|
1146
|
+
})
|
|
1147
|
+
|
|
1148
|
+
it('should work correctly when clientParamBuilder is undefined', () => {
|
|
1149
|
+
mockAnalytics.storage.get.mockReturnValue('0')
|
|
1150
|
+
|
|
1151
|
+
const payload = {
|
|
1152
|
+
event_config: {
|
|
1153
|
+
event_name: 'Purchase',
|
|
1154
|
+
show_fields: false
|
|
1155
|
+
},
|
|
1156
|
+
content_ids: ['product-123'],
|
|
1157
|
+
value: 99.99,
|
|
1158
|
+
userData: {
|
|
1159
|
+
em: 'TEST@EXAMPLE.COM',
|
|
1160
|
+
ph: '(555) 123-4567'
|
|
1161
|
+
}
|
|
1162
|
+
}
|
|
1163
|
+
|
|
1164
|
+
// Pass undefined for clientParamBuilder
|
|
1165
|
+
send(mockFbq, undefined, payload, defaultSettings, mockAnalytics)
|
|
1166
|
+
|
|
1167
|
+
// Should use default formatting (lowercase and trim for email, digits only for phone)
|
|
1168
|
+
expect(mockFbq).toHaveBeenCalledWith(
|
|
1169
|
+
'init',
|
|
1170
|
+
'test-pixel-123',
|
|
1171
|
+
expect.objectContaining({
|
|
1172
|
+
em: 'test@example.com',
|
|
1173
|
+
ph: '5551234567'
|
|
1174
|
+
})
|
|
1175
|
+
)
|
|
1176
|
+
})
|
|
1177
|
+
})
|
|
1178
|
+
})
|