docusaurus-plugin-generate-schema-docs 1.7.1 → 1.8.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.
@@ -0,0 +1,744 @@
1
+ import {
2
+ DEFAULT_SNIPPET_TARGET_ID,
3
+ generateSnippetForTarget,
4
+ getSnippetTarget,
5
+ SNIPPET_TARGETS,
6
+ } from '../../helpers/snippetTargets';
7
+
8
+ function executeWebSnippet(snippet, dataLayerName = 'dataLayer') {
9
+ const push = jest.fn();
10
+ const runtimeWindow = {
11
+ [dataLayerName]: { push },
12
+ };
13
+ const runner = new Function('window', snippet);
14
+ runner(runtimeWindow);
15
+ return push.mock.calls.map(([payload]) => payload);
16
+ }
17
+
18
+ describe('snippetTargets', () => {
19
+ it('exposes expected baseline target ids', () => {
20
+ expect(SNIPPET_TARGETS.map((target) => target.id)).toEqual(
21
+ expect.arrayContaining([
22
+ 'web-datalayer-js',
23
+ 'android-firebase-kotlin-sdk',
24
+ 'android-firebase-java-sdk',
25
+ 'ios-firebase-swift-sdk',
26
+ 'ios-firebase-objc-sdk',
27
+ ]),
28
+ );
29
+ });
30
+
31
+ it('resolves the default target when no id is provided', () => {
32
+ const target = getSnippetTarget();
33
+ expect(target.id).toBe(DEFAULT_SNIPPET_TARGET_ID);
34
+ });
35
+
36
+ it('throws for unknown target id', () => {
37
+ expect(() => getSnippetTarget('unknown-target-id')).toThrow(
38
+ 'Unknown snippet target',
39
+ );
40
+ });
41
+
42
+ it('generates web-datalayer snippet using configurable dataLayerName', () => {
43
+ const snippet = generateSnippetForTarget({
44
+ targetId: 'web-datalayer-js',
45
+ example: { event: 'test_event' },
46
+ schema: {
47
+ properties: {
48
+ ecommerce: { 'x-gtm-clear': true, type: 'object' },
49
+ event: { type: 'string' },
50
+ },
51
+ },
52
+ config: {
53
+ dataLayerName: 'customDataLayer',
54
+ },
55
+ });
56
+
57
+ expect(snippet).toContain('window.customDataLayer.push');
58
+ expect(snippet).toContain('"event": "test_event"');
59
+ });
60
+
61
+ it('executes web-datalayer snippet and pushes expected payload', () => {
62
+ const snippet = generateSnippetForTarget({
63
+ targetId: 'web-datalayer-js',
64
+ example: {
65
+ event: 'purchase',
66
+ ecommerce: {
67
+ currency: 'EUR',
68
+ value: 72.05,
69
+ },
70
+ },
71
+ schema: { properties: {} },
72
+ });
73
+
74
+ const pushedPayloads = executeWebSnippet(snippet);
75
+ expect(pushedPayloads).toEqual([
76
+ {
77
+ event: 'purchase',
78
+ ecommerce: { currency: 'EUR', value: 72.05 },
79
+ },
80
+ ]);
81
+ });
82
+
83
+ it('executes web-datalayer snippet with clearable properties reset first', () => {
84
+ const snippet = generateSnippetForTarget({
85
+ targetId: 'web-datalayer-js',
86
+ example: {
87
+ event: 'purchase',
88
+ ecommerce: { value: 10 },
89
+ },
90
+ schema: {
91
+ properties: {
92
+ ecommerce: { 'x-gtm-clear': true, type: 'object' },
93
+ user_data: { 'x-gtm-clear': true, type: 'object' },
94
+ event: { type: 'string' },
95
+ },
96
+ },
97
+ });
98
+
99
+ const pushedPayloads = executeWebSnippet(snippet);
100
+ expect(pushedPayloads).toEqual([
101
+ { ecommerce: null },
102
+ { event: 'purchase', ecommerce: { value: 10 } },
103
+ ]);
104
+ });
105
+
106
+ it('generates android kotlin firebase snippet', () => {
107
+ const snippet = generateSnippetForTarget({
108
+ targetId: 'android-firebase-kotlin-sdk',
109
+ example: {
110
+ event: 'share_image',
111
+ image_name: 'hero.jpg',
112
+ count: 2,
113
+ score: 4.5,
114
+ premium: true,
115
+ },
116
+ schema: { properties: {} },
117
+ });
118
+
119
+ expect(snippet).toContain('firebaseAnalytics.logEvent("share_image")');
120
+ expect(snippet).toContain('param("image_name", "hero.jpg")');
121
+ expect(snippet).toContain('param("count", 2L)');
122
+ expect(snippet).toContain('param(FirebaseAnalytics.Param.SCORE, 4.5)');
123
+ expect(snippet).toContain('param("premium", 1L)');
124
+ });
125
+
126
+ it('generates android java firebase snippet', () => {
127
+ const snippet = generateSnippetForTarget({
128
+ targetId: 'android-firebase-java-sdk',
129
+ example: {
130
+ event: 'share_image',
131
+ image_name: 'hero.jpg',
132
+ count: 2,
133
+ score: 4.5,
134
+ premium: false,
135
+ },
136
+ schema: { properties: {} },
137
+ });
138
+
139
+ expect(snippet).toContain('Bundle eventParams = new Bundle();');
140
+ expect(snippet).toContain(
141
+ 'eventParams.putString("image_name", "hero.jpg");',
142
+ );
143
+ expect(snippet).toContain('eventParams.putLong("count", 2L);');
144
+ expect(snippet).toContain(
145
+ 'eventParams.putDouble(FirebaseAnalytics.Param.SCORE, 4.5);',
146
+ );
147
+ expect(snippet).toContain('eventParams.putLong("premium", 0L);');
148
+ expect(snippet).toContain(
149
+ 'mFirebaseAnalytics.logEvent("share_image", eventParams);',
150
+ );
151
+ });
152
+
153
+ it('generates ios swift firebase snippet', () => {
154
+ const snippet = generateSnippetForTarget({
155
+ targetId: 'ios-firebase-swift-sdk',
156
+ example: {
157
+ event: 'share_image',
158
+ image_name: 'hero.jpg',
159
+ count: 2,
160
+ score: 4.5,
161
+ premium: true,
162
+ },
163
+ schema: { properties: {} },
164
+ });
165
+
166
+ expect(snippet).toContain('var eventParams: [String: Any] = [');
167
+ expect(snippet).toContain('"image_name": "hero.jpg"');
168
+ expect(snippet).toContain('"count": 2');
169
+ expect(snippet).toContain('AnalyticsParameterScore: 4.5');
170
+ expect(snippet).toContain('"premium": 1');
171
+ expect(snippet).toContain(
172
+ 'Analytics.logEvent("share_image", parameters: eventParams)',
173
+ );
174
+ });
175
+
176
+ it('generates ios objective-c firebase snippet', () => {
177
+ const snippet = generateSnippetForTarget({
178
+ targetId: 'ios-firebase-objc-sdk',
179
+ example: {
180
+ event: 'share_image',
181
+ image_name: 'hero.jpg',
182
+ count: 2,
183
+ score: 4.5,
184
+ premium: false,
185
+ },
186
+ schema: { properties: {} },
187
+ });
188
+
189
+ expect(snippet).toContain('NSMutableDictionary *eventParams = [@{');
190
+ expect(snippet).toContain('@"image_name": @"hero.jpg"');
191
+ expect(snippet).toContain('@"count": @(2)');
192
+ expect(snippet).toContain('kFIRParameterScore: @(4.5)');
193
+ expect(snippet).toContain('@"premium": @(0)');
194
+ expect(snippet).toContain(
195
+ '[FIRAnalytics logEventWithName:@"share_image" parameters:eventParams];',
196
+ );
197
+ });
198
+
199
+ it('throws when firebase payload contains unsupported nested values', () => {
200
+ expect(() =>
201
+ generateSnippetForTarget({
202
+ targetId: 'android-firebase-kotlin-sdk',
203
+ example: {
204
+ event: 'checkout',
205
+ ecommerce: {
206
+ currency: 'EUR',
207
+ metadata: { payment_step: 2 },
208
+ items: [{ sku: 'abc' }],
209
+ },
210
+ },
211
+ schema: { properties: {} },
212
+ }),
213
+ ).toThrow(
214
+ '[android-firebase-kotlin-sdk] Unsupported Firebase payload at "ecommerce"',
215
+ );
216
+ });
217
+
218
+ it('throws when firebase payload is missing a non-empty event name', () => {
219
+ expect(() =>
220
+ generateSnippetForTarget({
221
+ targetId: 'ios-firebase-swift-sdk',
222
+ example: {
223
+ value: 12.5,
224
+ },
225
+ schema: { properties: {} },
226
+ }),
227
+ ).toThrow(
228
+ '[ios-firebase-swift-sdk] Unsupported Firebase payload at "event"',
229
+ );
230
+
231
+ expect(() =>
232
+ generateSnippetForTarget({
233
+ targetId: 'android-firebase-java-sdk',
234
+ example: {
235
+ event: ' ',
236
+ value: 12.5,
237
+ },
238
+ schema: { properties: {} },
239
+ }),
240
+ ).toThrow(
241
+ '[android-firebase-java-sdk] Unsupported Firebase payload at "event"',
242
+ );
243
+ });
244
+
245
+ it('uses firebase constants and concrete item bundles for purchase event', () => {
246
+ const snippet = generateSnippetForTarget({
247
+ targetId: 'android-firebase-kotlin-sdk',
248
+ example: {
249
+ event: 'purchase',
250
+ transaction_id: 'T12345',
251
+ affiliation: 'Google Store',
252
+ currency: 'USD',
253
+ value: 14.98,
254
+ tax: 2.58,
255
+ shipping: 5.34,
256
+ coupon: 'SUMMER_FUN',
257
+ items: [{ item_id: 'sku-1' }],
258
+ },
259
+ schema: { properties: {} },
260
+ });
261
+
262
+ expect(snippet).toContain(
263
+ 'firebaseAnalytics.logEvent(FirebaseAnalytics.Event.PURCHASE)',
264
+ );
265
+ expect(snippet).toContain(
266
+ 'param(FirebaseAnalytics.Param.TRANSACTION_ID, "T12345")',
267
+ );
268
+ expect(snippet).toContain(
269
+ 'param(FirebaseAnalytics.Param.AFFILIATION, "Google Store")',
270
+ );
271
+ expect(snippet).toContain('param(FirebaseAnalytics.Param.CURRENCY, "USD")');
272
+ expect(snippet).toContain('param(FirebaseAnalytics.Param.VALUE, 14.98)');
273
+ expect(snippet).toContain('param(FirebaseAnalytics.Param.TAX, 2.58)');
274
+ expect(snippet).toContain('param(FirebaseAnalytics.Param.SHIPPING, 5.34)');
275
+ expect(snippet).toContain(
276
+ 'param(FirebaseAnalytics.Param.COUPON, "SUMMER_FUN")',
277
+ );
278
+ expect(snippet).toContain('val item1 = Bundle().apply {');
279
+ expect(snippet).toContain(
280
+ 'putString(FirebaseAnalytics.Param.ITEM_ID, "sku-1")',
281
+ );
282
+ expect(snippet).toContain(
283
+ 'param(FirebaseAnalytics.Param.ITEMS, arrayOf(item1))',
284
+ );
285
+ });
286
+
287
+ it('builds item dictionaries for swift purchase snippets', () => {
288
+ const snippet = generateSnippetForTarget({
289
+ targetId: 'ios-firebase-swift-sdk',
290
+ example: {
291
+ event: 'purchase',
292
+ transaction_id: 'T12345',
293
+ items: [
294
+ {
295
+ item_id: 'SKU_123',
296
+ item_name: 'jeggings',
297
+ item_category: 'pants',
298
+ item_variant: 'black',
299
+ item_brand: 'Google',
300
+ price: 9.99,
301
+ },
302
+ {
303
+ item_id: 'SKU_456',
304
+ item_name: 'boots',
305
+ item_category: 'shoes',
306
+ item_variant: 'brown',
307
+ item_brand: 'Google',
308
+ price: 24.99,
309
+ },
310
+ ],
311
+ },
312
+ schema: { properties: {} },
313
+ });
314
+
315
+ expect(snippet).toContain('var item1: [String: Any] = [');
316
+ expect(snippet).toContain('AnalyticsParameterItemID: "SKU_123"');
317
+ expect(snippet).toContain('AnalyticsParameterItemName: "jeggings"');
318
+ expect(snippet).toContain('AnalyticsParameterPrice: 9.99');
319
+ expect(snippet).toContain('var item2: [String: Any] = [');
320
+ expect(snippet).toContain('AnalyticsParameterItemID: "SKU_456"');
321
+ expect(snippet).toContain(
322
+ 'eventParams[AnalyticsParameterItems] = [item1, item2]',
323
+ );
324
+ });
325
+
326
+ it('omits $schema for firebase targets', () => {
327
+ const snippet = generateSnippetForTarget({
328
+ targetId: 'ios-firebase-swift-sdk',
329
+ example: {
330
+ $schema: 'https://example.com/schemas/purchase-event.json',
331
+ event: 'purchase',
332
+ transaction_id: 'T_12345',
333
+ value: 72.05,
334
+ currency: 'EUR',
335
+ },
336
+ schema: { properties: {} },
337
+ });
338
+
339
+ expect(snippet).toContain('AnalyticsParameterTransactionID: "T_12345"');
340
+ expect(snippet).toContain('AnalyticsParameterValue: 72.05');
341
+ expect(snippet).toContain('AnalyticsParameterCurrency: "EUR"');
342
+ expect(snippet).toContain(
343
+ 'Analytics.logEvent(AnalyticsEventPurchase, parameters: eventParams)',
344
+ );
345
+ expect(snippet).not.toContain('$schema');
346
+ });
347
+
348
+ it('uses official firebase screen_view constants for kotlin snippets', () => {
349
+ const snippet = generateSnippetForTarget({
350
+ targetId: 'android-firebase-kotlin-sdk',
351
+ example: {
352
+ event: 'screen_view',
353
+ screen_name: 'Checkout',
354
+ screen_class: 'CheckoutActivity',
355
+ firebase_screen: 'Checkout',
356
+ firebase_screen_class: 'CheckoutActivity',
357
+ },
358
+ schema: { properties: {} },
359
+ });
360
+
361
+ expect(snippet).toContain(
362
+ 'firebaseAnalytics.logEvent(FirebaseAnalytics.Event.SCREEN_VIEW)',
363
+ );
364
+ expect(snippet).toContain(
365
+ 'param(FirebaseAnalytics.Param.SCREEN_NAME, "Checkout")',
366
+ );
367
+ expect(snippet).toContain(
368
+ 'param(FirebaseAnalytics.Param.SCREEN_CLASS, "CheckoutActivity")',
369
+ );
370
+ });
371
+
372
+ it('uses official firebase screen_view constants for java snippets', () => {
373
+ const snippet = generateSnippetForTarget({
374
+ targetId: 'android-firebase-java-sdk',
375
+ example: {
376
+ event: 'screen_view',
377
+ screen_name: 'Checkout',
378
+ screen_class: 'CheckoutActivity',
379
+ },
380
+ schema: { properties: {} },
381
+ });
382
+
383
+ expect(snippet).toContain(
384
+ 'mFirebaseAnalytics.logEvent(FirebaseAnalytics.Event.SCREEN_VIEW, eventParams);',
385
+ );
386
+ expect(snippet).toContain(
387
+ 'eventParams.putString(FirebaseAnalytics.Param.SCREEN_NAME, "Checkout");',
388
+ );
389
+ expect(snippet).toContain(
390
+ 'eventParams.putString(FirebaseAnalytics.Param.SCREEN_CLASS, "CheckoutActivity");',
391
+ );
392
+ });
393
+
394
+ it('uses official firebase screen_view constants for swift snippets', () => {
395
+ const snippet = generateSnippetForTarget({
396
+ targetId: 'ios-firebase-swift-sdk',
397
+ example: {
398
+ event: 'screen_view',
399
+ screen_name: 'Checkout',
400
+ screen_class: 'CheckoutViewController',
401
+ },
402
+ schema: { properties: {} },
403
+ });
404
+
405
+ expect(snippet).toContain(
406
+ 'Analytics.logEvent(AnalyticsEventScreenView, parameters: eventParams)',
407
+ );
408
+ expect(snippet).toContain('AnalyticsParameterScreenName: "Checkout"');
409
+ expect(snippet).toContain(
410
+ 'AnalyticsParameterScreenClass: "CheckoutViewController"',
411
+ );
412
+ });
413
+
414
+ it('uses official firebase screen_view constants for objective-c snippets', () => {
415
+ const snippet = generateSnippetForTarget({
416
+ targetId: 'ios-firebase-objc-sdk',
417
+ example: {
418
+ event: 'screen_view',
419
+ screen_name: 'Checkout',
420
+ screen_class: 'CheckoutViewController',
421
+ },
422
+ schema: { properties: {} },
423
+ });
424
+
425
+ expect(snippet).toContain(
426
+ '[FIRAnalytics logEventWithName:kFIREventScreenView parameters:eventParams];',
427
+ );
428
+ expect(snippet).toContain('kFIRParameterScreenName: @"Checkout"');
429
+ expect(snippet).toContain(
430
+ 'kFIRParameterScreenClass: @"CheckoutViewController"',
431
+ );
432
+ });
433
+
434
+ it('maps additional predefined firebase event and parameter constants', () => {
435
+ const kotlinSnippet = generateSnippetForTarget({
436
+ targetId: 'android-firebase-kotlin-sdk',
437
+ example: {
438
+ event: 'add_to_cart',
439
+ currency: 'EUR',
440
+ value: 42.5,
441
+ },
442
+ schema: { properties: {} },
443
+ });
444
+ const swiftSnippet = generateSnippetForTarget({
445
+ targetId: 'ios-firebase-swift-sdk',
446
+ example: {
447
+ event: 'login',
448
+ method: 'email',
449
+ },
450
+ schema: { properties: {} },
451
+ });
452
+
453
+ expect(kotlinSnippet).toContain(
454
+ 'firebaseAnalytics.logEvent(FirebaseAnalytics.Event.ADD_TO_CART)',
455
+ );
456
+ expect(kotlinSnippet).toContain(
457
+ 'param(FirebaseAnalytics.Param.CURRENCY, "EUR")',
458
+ );
459
+ expect(kotlinSnippet).toContain(
460
+ 'param(FirebaseAnalytics.Param.VALUE, 42.5)',
461
+ );
462
+ expect(swiftSnippet).toContain(
463
+ 'Analytics.logEvent(AnalyticsEventLogin, parameters: eventParams)',
464
+ );
465
+ expect(swiftSnippet).toContain('AnalyticsParameterMethod: "email"');
466
+ });
467
+
468
+ it('keeps custom events and params as string literals', () => {
469
+ const javaSnippet = generateSnippetForTarget({
470
+ targetId: 'android-firebase-java-sdk',
471
+ example: {
472
+ event: 'my_custom_event',
473
+ custom_prop: 'x',
474
+ },
475
+ schema: { properties: {} },
476
+ });
477
+
478
+ expect(javaSnippet).toContain(
479
+ 'mFirebaseAnalytics.logEvent("my_custom_event", eventParams);',
480
+ );
481
+ expect(javaSnippet).toContain('eventParams.putString("custom_prop", "x");');
482
+ });
483
+
484
+ it('maps campaign_details standard params to firebase constants', () => {
485
+ const kotlinSnippet = generateSnippetForTarget({
486
+ targetId: 'android-firebase-kotlin-sdk',
487
+ example: {
488
+ event: 'campaign_details',
489
+ campaign_id: 'cmp_42',
490
+ aclid: 'aclid_99',
491
+ },
492
+ schema: { properties: {} },
493
+ });
494
+ const objcSnippet = generateSnippetForTarget({
495
+ targetId: 'ios-firebase-objc-sdk',
496
+ example: {
497
+ event: 'campaign_details',
498
+ campaign_id: 'cmp_42',
499
+ aclid: 'aclid_99',
500
+ },
501
+ schema: { properties: {} },
502
+ });
503
+
504
+ expect(kotlinSnippet).toContain(
505
+ 'firebaseAnalytics.logEvent(FirebaseAnalytics.Event.CAMPAIGN_DETAILS)',
506
+ );
507
+ expect(kotlinSnippet).toContain(
508
+ 'param(FirebaseAnalytics.Param.CAMPAIGN_ID, "cmp_42")',
509
+ );
510
+ expect(kotlinSnippet).toContain(
511
+ 'param(FirebaseAnalytics.Param.ACLID, "aclid_99")',
512
+ );
513
+ expect(objcSnippet).toContain(
514
+ '[FIRAnalytics logEventWithName:kFIREventCampaignDetails parameters:eventParams];',
515
+ );
516
+ expect(objcSnippet).toContain('kFIRParameterCampaignID: @"cmp_42"');
517
+ expect(objcSnippet).toContain('kFIRParameterAdNetworkClickID: @"aclid_99"');
518
+ });
519
+
520
+ it('uses the iOS/Obj-C aclid exception constant and additional standard params', () => {
521
+ const swiftSnippet = generateSnippetForTarget({
522
+ targetId: 'ios-firebase-swift-sdk',
523
+ example: {
524
+ event: 'campaign_details',
525
+ aclid: 'aclid_99',
526
+ source_platform: 'google_ads',
527
+ marketing_tactic: 'retargeting',
528
+ },
529
+ schema: { properties: {} },
530
+ });
531
+ const kotlinSnippet = generateSnippetForTarget({
532
+ targetId: 'android-firebase-kotlin-sdk',
533
+ example: {
534
+ event: 'ad_impression',
535
+ ad_unit_name: '/123/home',
536
+ creative_format: 'video',
537
+ },
538
+ schema: { properties: {} },
539
+ });
540
+
541
+ expect(swiftSnippet).toContain(
542
+ 'AnalyticsParameterAdNetworkClickID: "aclid_99"',
543
+ );
544
+ expect(swiftSnippet).toContain(
545
+ 'AnalyticsParameterSourcePlatform: "google_ads"',
546
+ );
547
+ expect(swiftSnippet).toContain(
548
+ 'AnalyticsParameterMarketingTactic: "retargeting"',
549
+ );
550
+ expect(kotlinSnippet).toContain(
551
+ 'param(FirebaseAnalytics.Param.AD_UNIT_NAME, "/123/home")',
552
+ );
553
+ expect(kotlinSnippet).toContain(
554
+ 'param(FirebaseAnalytics.Param.CREATIVE_FORMAT, "video")',
555
+ );
556
+ });
557
+
558
+ it('emits firebase user property setters with predefined constants', () => {
559
+ const kotlinSnippet = generateSnippetForTarget({
560
+ targetId: 'android-firebase-kotlin-sdk',
561
+ example: {
562
+ event: 'login',
563
+ method: 'email',
564
+ user_properties: {
565
+ sign_up_method: 'email',
566
+ allow_ad_personalization_signals: 'false',
567
+ },
568
+ },
569
+ schema: { properties: {} },
570
+ });
571
+ const javaSnippet = generateSnippetForTarget({
572
+ targetId: 'android-firebase-java-sdk',
573
+ example: {
574
+ event: 'login',
575
+ method: 'email',
576
+ user_properties: {
577
+ sign_up_method: 'email',
578
+ },
579
+ },
580
+ schema: { properties: {} },
581
+ });
582
+ const swiftSnippet = generateSnippetForTarget({
583
+ targetId: 'ios-firebase-swift-sdk',
584
+ example: {
585
+ event: 'login',
586
+ method: 'email',
587
+ user_properties: {
588
+ sign_up_method: 'email',
589
+ },
590
+ },
591
+ schema: { properties: {} },
592
+ });
593
+ const objcSnippet = generateSnippetForTarget({
594
+ targetId: 'ios-firebase-objc-sdk',
595
+ example: {
596
+ event: 'login',
597
+ method: 'email',
598
+ user_properties: {
599
+ sign_up_method: 'email',
600
+ allow_ad_personalization_signals: null,
601
+ },
602
+ },
603
+ schema: { properties: {} },
604
+ });
605
+
606
+ expect(kotlinSnippet).toContain(
607
+ 'firebaseAnalytics.setUserProperty(FirebaseAnalytics.UserProperty.SIGN_UP_METHOD, "email")',
608
+ );
609
+ expect(kotlinSnippet).toContain(
610
+ 'firebaseAnalytics.setUserProperty(FirebaseAnalytics.UserProperty.ALLOW_AD_PERSONALIZATION_SIGNALS, "false")',
611
+ );
612
+ expect(javaSnippet).toContain(
613
+ 'mFirebaseAnalytics.setUserProperty(FirebaseAnalytics.UserProperty.SIGN_UP_METHOD, "email");',
614
+ );
615
+ expect(swiftSnippet).toContain(
616
+ 'Analytics.setUserProperty("email", forName: AnalyticsUserPropertySignUpMethod)',
617
+ );
618
+ expect(objcSnippet).toContain(
619
+ '[FIRAnalytics setUserPropertyString:@"email" forName:kFIRUserPropertySignUpMethod];',
620
+ );
621
+ expect(objcSnippet).toContain(
622
+ '[FIRAnalytics setUserPropertyString:nil forName:kFIRUserPropertyAllowAdPersonalizationSignals];',
623
+ );
624
+ expect(kotlinSnippet).not.toContain('param("user_properties"');
625
+ });
626
+
627
+ it('maps ecommerce-focused params with IDs and numbered categories correctly', () => {
628
+ const kotlinSnippet = generateSnippetForTarget({
629
+ targetId: 'android-firebase-kotlin-sdk',
630
+ example: {
631
+ event: 'select_promotion',
632
+ promotion_id: 'PROMO_123',
633
+ promotion_name: 'Summer Sale',
634
+ creative_slot: 'hero_top',
635
+ item_list_id: 'LIST_42',
636
+ item_list_name: 'Homepage Picks',
637
+ },
638
+ schema: { properties: {} },
639
+ });
640
+ const swiftSnippet = generateSnippetForTarget({
641
+ targetId: 'ios-firebase-swift-sdk',
642
+ example: {
643
+ event: 'purchase',
644
+ transaction_id: 'T_100',
645
+ shipping_tier: 'Express',
646
+ items: [
647
+ {
648
+ item_id: 'SKU_123',
649
+ item_name: 'jeggings',
650
+ item_category2: 'bottoms',
651
+ item_category5: 'sale',
652
+ },
653
+ ],
654
+ },
655
+ schema: { properties: {} },
656
+ });
657
+ const objcSnippet = generateSnippetForTarget({
658
+ targetId: 'ios-firebase-objc-sdk',
659
+ example: {
660
+ event: 'add_to_cart',
661
+ item_list_id: 'LIST_42',
662
+ item_list_name: 'Homepage Picks',
663
+ coupon: 'WELCOME10',
664
+ },
665
+ schema: { properties: {} },
666
+ });
667
+
668
+ expect(kotlinSnippet).toContain(
669
+ 'param(FirebaseAnalytics.Param.PROMOTION_ID, "PROMO_123")',
670
+ );
671
+ expect(kotlinSnippet).toContain(
672
+ 'param(FirebaseAnalytics.Param.ITEM_LIST_ID, "LIST_42")',
673
+ );
674
+ expect(swiftSnippet).toContain('AnalyticsParameterTransactionID: "T_100"');
675
+ expect(swiftSnippet).toContain('AnalyticsParameterShippingTier: "Express"');
676
+ expect(swiftSnippet).toContain(
677
+ 'AnalyticsParameterItemCategory2: "bottoms"',
678
+ );
679
+ expect(swiftSnippet).toContain('AnalyticsParameterItemCategory5: "sale"');
680
+ expect(objcSnippet).toContain('kFIRParameterItemListID: @"LIST_42"');
681
+ expect(objcSnippet).toContain(
682
+ 'kFIRParameterItemListName: @"Homepage Picks"',
683
+ );
684
+ expect(objcSnippet).toContain('kFIRParameterCoupon: @"WELCOME10"');
685
+ });
686
+
687
+ it('maps additional Firebase commerce constants present in reference docs', () => {
688
+ const kotlinSnippet = generateSnippetForTarget({
689
+ targetId: 'android-firebase-kotlin-sdk',
690
+ example: {
691
+ event: 'in_app_purchase',
692
+ product_id: 'sku_premium',
693
+ product_name: 'Premium Plan',
694
+ subscription: true,
695
+ free_trial: false,
696
+ price_is_discounted: true,
697
+ },
698
+ schema: { properties: {} },
699
+ });
700
+ const swiftSnippet = generateSnippetForTarget({
701
+ targetId: 'ios-firebase-swift-sdk',
702
+ example: {
703
+ event: 'in_app_purchase',
704
+ product_id: 'sku_premium',
705
+ product_name: 'Premium Plan',
706
+ subscription: true,
707
+ free_trial: false,
708
+ price_is_discounted: true,
709
+ },
710
+ schema: { properties: {} },
711
+ });
712
+
713
+ expect(kotlinSnippet).toContain(
714
+ 'firebaseAnalytics.logEvent(FirebaseAnalytics.Event.IN_APP_PURCHASE)',
715
+ );
716
+ expect(kotlinSnippet).toContain(
717
+ 'param(FirebaseAnalytics.Param.PRODUCT_ID, "sku_premium")',
718
+ );
719
+ expect(kotlinSnippet).toContain(
720
+ 'param(FirebaseAnalytics.Param.PRODUCT_NAME, "Premium Plan")',
721
+ );
722
+ expect(kotlinSnippet).toContain(
723
+ 'param(FirebaseAnalytics.Param.SUBSCRIPTION, 1L)',
724
+ );
725
+ expect(kotlinSnippet).toContain(
726
+ 'param(FirebaseAnalytics.Param.FREE_TRIAL, 0L)',
727
+ );
728
+ expect(kotlinSnippet).toContain(
729
+ 'param(FirebaseAnalytics.Param.PRICE_IS_DISCOUNTED, 1L)',
730
+ );
731
+ expect(swiftSnippet).toContain(
732
+ 'Analytics.logEvent(AnalyticsEventInAppPurchase, parameters: eventParams)',
733
+ );
734
+ expect(swiftSnippet).toContain(
735
+ 'AnalyticsParameterProductID: "sku_premium"',
736
+ );
737
+ expect(swiftSnippet).toContain(
738
+ 'AnalyticsParameterProductName: "Premium Plan"',
739
+ );
740
+ expect(swiftSnippet).toContain('AnalyticsParameterSubscription: 1');
741
+ expect(swiftSnippet).toContain('AnalyticsParameterFreeTrial: 0');
742
+ expect(swiftSnippet).toContain('AnalyticsParameterPriceIsDiscounted: 1');
743
+ });
744
+ });