@admoai/sdk-scenarios 1.1.0 → 1.2.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,118 @@
1
+ {
2
+ "success": true,
3
+ "data": [
4
+ {
5
+ "placement": "preroll",
6
+ "creatives": [
7
+ {
8
+ "delivery": "json",
9
+ "contents": [
10
+ {
11
+ "key": "video_asset",
12
+ "type": "video",
13
+ "value": "https://cdn.admoai.com/media/volta-15s.mp4"
14
+ },
15
+ {
16
+ "key": "poster_image",
17
+ "type": "image",
18
+ "value": "https://cdn.admoai.com/media/volta-poster.jpg"
19
+ },
20
+ {
21
+ "key": "brand_logo",
22
+ "type": "image",
23
+ "value": "https://cdn.admoai.com/media/volta-logo.png"
24
+ },
25
+ {
26
+ "key": "headline",
27
+ "type": "text",
28
+ "value": "Two lattes, one price"
29
+ },
30
+ {
31
+ "key": "supporting_text",
32
+ "type": "text",
33
+ "value": "At every Volta in Santiago until Sunday."
34
+ },
35
+ {
36
+ "key": "cta_text",
37
+ "type": "text",
38
+ "value": "See the menu"
39
+ },
40
+ {
41
+ "key": "destination_url",
42
+ "type": "url",
43
+ "value": "https://volta.example/menu"
44
+ },
45
+ {
46
+ "key": "disclaimer",
47
+ "type": "text",
48
+ "value": "While stocks last."
49
+ }
50
+ ],
51
+ "advertiser": {
52
+ "name": "Volta Coffee",
53
+ "legalName": "Volta Coffee SpA",
54
+ "logoUrl": "https://cdn.admoai.com/media/volta-logo.png"
55
+ },
56
+ "template": {
57
+ "key": "standard_video",
58
+ "style": "default"
59
+ },
60
+ "tracking": {
61
+ "impressions": [
62
+ {
63
+ "key": "default",
64
+ "url": "https://api.admoai.com/v1/tracking?e=tok.standard_video.full.impression"
65
+ }
66
+ ],
67
+ "clicks": [
68
+ {
69
+ "key": "default",
70
+ "url": "https://api.admoai.com/v1/tracking?e=tok.standard_video.full.click"
71
+ }
72
+ ],
73
+ "custom": [],
74
+ "videoEvents": [
75
+ {
76
+ "key": "start",
77
+ "url": "https://api.admoai.com/v1/tracking?e=tok.standard_video.full.start"
78
+ },
79
+ {
80
+ "key": "first_quartile",
81
+ "url": "https://api.admoai.com/v1/tracking?e=tok.standard_video.full.first_quartile"
82
+ },
83
+ {
84
+ "key": "midpoint",
85
+ "url": "https://api.admoai.com/v1/tracking?e=tok.standard_video.full.midpoint"
86
+ },
87
+ {
88
+ "key": "third_quartile",
89
+ "url": "https://api.admoai.com/v1/tracking?e=tok.standard_video.full.third_quartile"
90
+ },
91
+ {
92
+ "key": "complete",
93
+ "url": "https://api.admoai.com/v1/tracking?e=tok.standard_video.full.complete"
94
+ }
95
+ ]
96
+ },
97
+ "metadata": {
98
+ "adId": "ad_01JDDR87YZYWJKANY5ZRAXWS3Q",
99
+ "creativeId": "creative_01JDGR1RTA3KV7KARB86J1DP84",
100
+ "advertiserId": "advertiser_01JDH315KXW0FP82VY8WMV97YE",
101
+ "placementId": "placement_01JDGX7Z9JHJR8PN9HZJPDNFWA",
102
+ "templateId": "template_01JDM27C055JQSS6R0DV2H5XPB",
103
+ "priority": "standard",
104
+ "language": "en",
105
+ "format": "video",
106
+ "effectiveStandardFormatKey": "standard_video",
107
+ "effectiveStandardFormatVersion": 1,
108
+ "templateSource": "admoai_standard",
109
+ "duration": 15,
110
+ "aspectRatio": "16:9"
111
+ }
112
+ }
113
+ ]
114
+ }
115
+ ],
116
+ "errors": null,
117
+ "warnings": null
118
+ }
@@ -0,0 +1,83 @@
1
+ {
2
+ "success": true,
3
+ "data": [
4
+ {
5
+ "placement": "preroll",
6
+ "creatives": [
7
+ {
8
+ "delivery": "json",
9
+ "contents": [
10
+ {
11
+ "key": "video_asset",
12
+ "type": "video",
13
+ "value": "https://cdn.admoai.com/media/volta-15s.mp4"
14
+ },
15
+ {
16
+ "key": "poster_image",
17
+ "type": "image",
18
+ "value": "https://cdn.admoai.com/media/volta-poster.jpg"
19
+ }
20
+ ],
21
+ "advertiser": {
22
+ "name": "Volta Coffee",
23
+ "legalName": "Volta Coffee SpA",
24
+ "logoUrl": "https://cdn.admoai.com/media/volta-logo.png"
25
+ },
26
+ "template": {
27
+ "key": "standard_video",
28
+ "style": "default"
29
+ },
30
+ "tracking": {
31
+ "impressions": [
32
+ {
33
+ "key": "default",
34
+ "url": "https://api.admoai.com/v1/tracking?e=tok.standard_video.minimal.impression"
35
+ }
36
+ ],
37
+ "clicks": [],
38
+ "custom": [],
39
+ "videoEvents": [
40
+ {
41
+ "key": "start",
42
+ "url": "https://api.admoai.com/v1/tracking?e=tok.standard_video.minimal.start"
43
+ },
44
+ {
45
+ "key": "first_quartile",
46
+ "url": "https://api.admoai.com/v1/tracking?e=tok.standard_video.minimal.first_quartile"
47
+ },
48
+ {
49
+ "key": "midpoint",
50
+ "url": "https://api.admoai.com/v1/tracking?e=tok.standard_video.minimal.midpoint"
51
+ },
52
+ {
53
+ "key": "third_quartile",
54
+ "url": "https://api.admoai.com/v1/tracking?e=tok.standard_video.minimal.third_quartile"
55
+ },
56
+ {
57
+ "key": "complete",
58
+ "url": "https://api.admoai.com/v1/tracking?e=tok.standard_video.minimal.complete"
59
+ }
60
+ ]
61
+ },
62
+ "metadata": {
63
+ "adId": "ad_01JDB2BVYVEG36SJ39ZVJ2S7FK",
64
+ "creativeId": "creative_01JDXWS60TJADDBKW1184GW4DE",
65
+ "advertiserId": "advertiser_01JDH315KXW0FP82VY8WMV97YE",
66
+ "placementId": "placement_01JDGX7Z9JHJR8PN9HZJPDNFWA",
67
+ "templateId": "template_01JDJ0JEE18TK4W82VSCT9NM1F",
68
+ "priority": "standard",
69
+ "language": "en",
70
+ "format": "video",
71
+ "effectiveStandardFormatKey": "standard_video",
72
+ "effectiveStandardFormatVersion": 1,
73
+ "templateSource": "admoai_standard",
74
+ "duration": 15,
75
+ "aspectRatio": "16:9"
76
+ }
77
+ }
78
+ ]
79
+ }
80
+ ],
81
+ "errors": null,
82
+ "warnings": null
83
+ }
package/package.json CHANGED
@@ -1,11 +1,12 @@
1
1
  {
2
2
  "name": "@admoai/sdk-scenarios",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "description": "The cross-SDK decision & tracking scenarios every AdMoai SDK asserts against a real decision-engine. Data only.",
5
5
  "license": "MIT",
6
6
  "files": [
7
7
  "scenarios.json",
8
8
  "scenarios.feature",
9
+ "fixtures/",
9
10
  "CHANGELOG.md",
10
11
  "README.md"
11
12
  ],
package/scenarios.feature CHANGED
@@ -1,11 +1,12 @@
1
1
  # GENERATED from scenarios.json — do not edit; regenerate with: go run ./tools/sdkfeaturegen
2
2
  #
3
- # scenarios.json is what the iOS, Android and Flutter manifest runners execute against a
4
- # real decision-engine. This is its readable rendering: what every AdMoai SDK promises a
5
- # publisher's app, in the same words for all three. CI regenerates it and fails on any
6
- # difference, so it cannot drift from what the runners execute.
3
+ # scenarios.json is what the iOS, Android and Flutter manifest runners execute: the live
4
+ # scenarios against a real decision-engine, the @fixture scenarios offline against the golden
5
+ # decision wire shipped in the package. This is its readable rendering: what every AdMoai SDK
6
+ # promises a publisher's app, in the same words for all three. CI regenerates it and fails on
7
+ # any difference, so it cannot drift from what the runners execute.
7
8
  # How it is published and kept fresh: docs/guides/sdk-ci.md, Section 7.
8
- # Manifest schemaVersion: 1
9
+ # Manifest schemaVersion: 2
9
10
 
10
11
  Feature: Cross-SDK decision & tracking contract
11
12
  Shared cross-SDK E2E scenario manifest. ONE definition, executed by a thin interpreter in each
@@ -15,7 +16,13 @@ Feature: Cross-SDK decision & tracking contract
15
16
  (log capture, concurrency, retry, TTL waits) stay hand-written per SDK. Mirrored
16
17
  byte-identically into all three repos; a checksum test fails the build if the copies diverge.
17
18
  Every expected value here was verified against a live local decision-engine before being
18
- written.
19
+ written. `fixtureScenarios` (schemaVersion 2) run offline: each decodes one golden
20
+ decision-wire file (ui/platform/lib/ad-formats/golden-wire in adhub, shipped in this package
21
+ under fixtures/golden-wire/) after optional `edits`, and asserts what the publisher's app
22
+ reads from the decoded creative. `contentKeys` is the exact set of plain content keys (slides
23
+ and matched points are asserted through their own fields); a key in `contentKeysAbsent` must
24
+ decode as absent (null), never as an empty string or a placeholder; a null in `metadata` means
25
+ absent. A runner that does not execute fixtureScenarios must refuse schemaVersion 2.
19
26
 
20
27
  @L @native
21
28
  Scenario: L1 — a normal native ad serves with complete, well-formed metadata
@@ -369,3 +376,222 @@ Feature: Cross-SDK decision & tracking contract
369
376
  Then each shown pin's view beacon reaches the engine exactly once per response, and no pin the app never showed sends one
370
377
  And every tap and every click sends its beacon, on every call
371
378
  And the engine accepts every beacon
379
+
380
+ @F @fixture
381
+ Scenario: F1 — a Native Display creative exposes its standard format, version and template source
382
+ Given the app decodes the golden card.full response
383
+ Then the response decodes
384
+ And the creative's effectiveStandardFormatKey is "card"
385
+ And the creative's effectiveStandardFormatVersion is 1
386
+ And the creative's templateSource is "admoai_standard"
387
+ And the template key is "card"
388
+ And the creative's contents are exactly "image", "brand_logo", "headline", "supporting_text", "cta_text", "destination_url"
389
+ And the click trackers are exactly "default"
390
+ And the creative has no custom event tracker
391
+
392
+ @F @fixture
393
+ Scenario: F2 — a Native Display creative leaves every optional field it was served without absent
394
+ Given the app decodes the golden card.minimal response
395
+ Then the response decodes
396
+ And the creative's effectiveStandardFormatKey is "card"
397
+ And the creative's effectiveStandardFormatVersion is 1
398
+ And the creative's templateSource is "admoai_standard"
399
+ And the template key is "card"
400
+ And the creative's contents are exactly "image", "destination_url"
401
+ And "brand_logo", "headline", "supporting_text", "cta_text" decode as absent, never as an empty string or a placeholder
402
+ And the click trackers are exactly "default"
403
+ And the creative has no custom event tracker
404
+
405
+ @F @fixture
406
+ Scenario: F3 — a template based on a standard keeps the standard's identity and exposes the operator's addition by key
407
+ Given the app decodes the golden card.derived response
408
+ Then the response decodes
409
+ And the creative's effectiveStandardFormatKey is "card"
410
+ And the creative's effectiveStandardFormatVersion is 1
411
+ And the creative's templateSource is "based_on_standard"
412
+ And the template key is "city_promo_display"
413
+ And the creative's contents are exactly "image", "headline", "destination_url", "promo_code"
414
+ And the click trackers are exactly "default"
415
+ And the custom event trackers are exactly "save_offer"
416
+
417
+ @F @fixture
418
+ Scenario: F4 — a Carousel exposes its slides in server order, each with its id, position, contents and own trackers, and no creative-level click
419
+ Given the app decodes the golden carousel.full response
420
+ Then the response decodes
421
+ And the creative's effectiveStandardFormatKey is "carousel"
422
+ And the creative's effectiveStandardFormatVersion is 1
423
+ And the creative's templateSource is "admoai_standard"
424
+ And the template key is "carousel"
425
+ And the creative's contents are exactly "brand_logo", "disclaimer"
426
+ And the creative has no click tracker
427
+ And the creative has no custom event tracker
428
+ And there are 3 slides in server order
429
+ And slide 1 is "slide_01JDY02N8MA2K2HKQ74989YS99" with contents "image", "headline", "supporting_text", "cta_text", "destination_url", view trackers "slide_view" and click trackers "default"
430
+ And slide 2 is "slide_01JD04H8GY801VF8Y0FHETP6XA" with contents "image", "headline", "supporting_text", "cta_text", "destination_url", view trackers "slide_view" and click trackers "default"
431
+ And slide 3 is "slide_01JDRGMFSTZXQ7ES1QBCF0DR2X" with contents "image", "headline", "supporting_text", "cta_text", "destination_url", view trackers "slide_view" and click trackers "default"
432
+
433
+ @F @fixture
434
+ Scenario: F5 — a minimal Carousel still exposes its slides and leaves the optional brand logo and disclaimer absent
435
+ Given the app decodes the golden carousel.minimal response
436
+ Then the response decodes
437
+ And the creative's effectiveStandardFormatKey is "carousel"
438
+ And the creative's effectiveStandardFormatVersion is 1
439
+ And the creative's templateSource is "admoai_standard"
440
+ And the template key is "carousel"
441
+ And the creative has no plain contents
442
+ And "brand_logo", "disclaimer" decode as absent, never as an empty string or a placeholder
443
+ And the creative has no click tracker
444
+ And the creative has no custom event tracker
445
+ And there are 2 slides in server order
446
+ And slide 1 is "slide_01JDZ725G8017BHW9RQJX7Y56S" with contents "image", "destination_url", view trackers "slide_view" and click trackers "default"
447
+ And slide 2 is "slide_01JD4GNH6TH0XPP5YWCMDKN029" with contents "image", "destination_url", view trackers "slide_view" and click trackers "default"
448
+
449
+ @F @fixture
450
+ Scenario: F6 — a Carousel based on a standard exposes its slides and the operator's addition
451
+ Given the app decodes the golden carousel.derived response
452
+ Then the response decodes
453
+ And the creative's effectiveStandardFormatKey is "carousel"
454
+ And the creative's effectiveStandardFormatVersion is 1
455
+ And the creative's templateSource is "based_on_standard"
456
+ And the template key is "city_carousel"
457
+ And the creative's contents are exactly "promo_code"
458
+ And the creative has no click tracker
459
+ And the creative has no custom event tracker
460
+ And there are 2 slides in server order
461
+ And slide 1 is "slide_01JDS1H8VEM0ABE2PQ0JY6S38W" with contents "image", "destination_url", view trackers "slide_view" and click trackers "default"
462
+ And slide 2 is "slide_01JDDGXJE0JDBY21Y9KEJDD54A" with contents "image", "destination_url", view trackers "slide_view" and click trackers "default"
463
+
464
+ @F @fixture
465
+ Scenario: F7 — a Tap-to-expand creative exposes expand and close as custom events, apart from its click
466
+ Given the app decodes the golden expandable_banner.full response
467
+ Then the response decodes
468
+ And the creative's effectiveStandardFormatKey is "expandable_banner"
469
+ And the creative's effectiveStandardFormatVersion is 1
470
+ And the creative's templateSource is "admoai_standard"
471
+ And the template key is "expandable_banner"
472
+ And the creative's contents are exactly "teaser_image", "teaser_headline", "expanded_image", "headline", "supporting_text", "cta_text", "destination_url", "disclaimer"
473
+ And the click trackers are exactly "default"
474
+ And the custom event trackers are exactly "expand", "close"
475
+
476
+ @F @fixture
477
+ Scenario: F8 — a minimal Tap-to-expand creative leaves its optional texts absent and keeps expand and close
478
+ Given the app decodes the golden expandable_banner.minimal response
479
+ Then the response decodes
480
+ And the creative's effectiveStandardFormatKey is "expandable_banner"
481
+ And the creative's effectiveStandardFormatVersion is 1
482
+ And the creative's templateSource is "admoai_standard"
483
+ And the template key is "expandable_banner"
484
+ And the creative's contents are exactly "teaser_image", "expanded_image", "destination_url"
485
+ And "teaser_headline", "headline", "supporting_text", "cta_text", "disclaimer" decode as absent, never as an empty string or a placeholder
486
+ And the click trackers are exactly "default"
487
+ And the custom event trackers are exactly "expand", "close"
488
+
489
+ @F @fixture
490
+ Scenario: F9 — a Branded Assets creative exposes asset tap as a custom event, apart from its click
491
+ Given the app decodes the golden branded_assets.full response
492
+ Then the response decodes
493
+ And the creative's effectiveStandardFormatKey is "branded_assets"
494
+ And the creative's effectiveStandardFormatVersion is 1
495
+ And the creative's templateSource is "admoai_standard"
496
+ And the template key is "branded_assets"
497
+ And the creative's contents are exactly "branded_image", "accessible_label", "destination_url"
498
+ And the click trackers are exactly "default"
499
+ And the custom event trackers are exactly "asset_tap"
500
+
501
+ @F @fixture
502
+ Scenario: F10 — a Branded Assets creative without a destination has no click, only the asset tap
503
+ Given the app decodes the golden branded_assets.minimal response
504
+ Then the response decodes
505
+ And the creative's effectiveStandardFormatKey is "branded_assets"
506
+ And the creative's effectiveStandardFormatVersion is 1
507
+ And the creative's templateSource is "admoai_standard"
508
+ And the template key is "branded_assets"
509
+ And the creative's contents are exactly "branded_image"
510
+ And "accessible_label", "destination_url" decode as absent, never as an empty string or a placeholder
511
+ And the creative has no click tracker
512
+ And the custom event trackers are exactly "asset_tap"
513
+
514
+ @F @fixture
515
+ Scenario: F11 — a Standard Video exposes its video events and click, and no skippable setting
516
+ Given the app decodes the golden standard_video.full response
517
+ Then the response decodes
518
+ And the creative's effectiveStandardFormatKey is "standard_video"
519
+ And the creative's effectiveStandardFormatVersion is 1
520
+ And the creative's templateSource is "admoai_standard"
521
+ And the template key is "standard_video"
522
+ And the creative's contents are exactly "video_asset", "poster_image", "brand_logo", "headline", "supporting_text", "cta_text", "destination_url", "disclaimer"
523
+ And the click trackers are exactly "default"
524
+ And the creative has no custom event tracker
525
+ And the video event trackers are exactly "start", "first_quartile", "midpoint", "third_quartile", "complete"
526
+ And the creative exposes no skippable setting
527
+
528
+ @F @fixture
529
+ Scenario: F12 — a Standard Video without a destination has no click action or click tracker
530
+ Given the app decodes the golden standard_video.minimal response
531
+ Then the response decodes
532
+ And the creative's effectiveStandardFormatKey is "standard_video"
533
+ And the creative's effectiveStandardFormatVersion is 1
534
+ And the creative's templateSource is "admoai_standard"
535
+ And the template key is "standard_video"
536
+ And the creative's contents are exactly "video_asset", "poster_image"
537
+ And "brand_logo", "headline", "supporting_text", "cta_text", "destination_url", "disclaimer" decode as absent, never as an empty string or a placeholder
538
+ And the creative has no click tracker
539
+ And the creative has no custom event tracker
540
+ And the video event trackers are exactly "start", "first_quartile", "midpoint", "third_quartile", "complete"
541
+ And the creative exposes no skippable setting
542
+
543
+ @F @fixture
544
+ Scenario: F13 — a Sponsored Pin creative keeps decoding its matched points as it does today
545
+ Given the app decodes the golden sponsored_pin_location.full response
546
+ Then the response decodes
547
+ And the creative's effectiveStandardFormatKey is "sponsored_pin_location"
548
+ And the creative's effectiveStandardFormatVersion is 1
549
+ And the creative's templateSource is "admoai_standard"
550
+ And the template key is "sponsored_pin_location"
551
+ And the creative's contents are exactly "pinImage", "image", "headline", "description", "ctaText", "defaultDestinationUrl"
552
+ And the click trackers are exactly "default"
553
+ And the creative has no custom event tracker
554
+ And the creative exposes 2 matched points
555
+
556
+ @F @fixture
557
+ Scenario: F14 — a creative served before the standards (gate off) decodes as today, with the three standard fields absent
558
+ The engine omits the three standard fields while is_standard_native_formats_enabled is off;
559
+ this is that wire. Absent means null, never an empty string or a placeholder (BR-SDK-01,
560
+ BR-SDK-09).
561
+
562
+ Given the app decodes the golden card.full response
563
+ And with the metadata field "effectiveStandardFormatKey" removed
564
+ And with the metadata field "effectiveStandardFormatVersion" removed
565
+ And with the metadata field "templateSource" removed
566
+ Then the response decodes
567
+ And the creative's effectiveStandardFormatKey is absent
568
+ And the creative's effectiveStandardFormatVersion is absent
569
+ And the creative's templateSource is absent
570
+ And the template key is "card"
571
+ And the creative's contents are exactly "image", "brand_logo", "headline", "supporting_text", "cta_text", "destination_url"
572
+ And the click trackers are exactly "default"
573
+ And the creative has no custom event tracker
574
+
575
+ @F @fixture
576
+ Scenario: F15 — fields the SDK does not know yet, at any level, never break decoding
577
+ An additive field the engine starts sending later must be ignored, not fail the response
578
+ (BR-SDK-01).
579
+
580
+ Given the app decodes the golden carousel.full response
581
+ And with an unknown response field "futureField" added
582
+ And with an unknown creative field "futureField" added
583
+ And with an unknown metadata field "futureField" added
584
+ And with an unknown content field "futureField" added on every content entry
585
+ And with an unknown slide field "futureField" added on every slide
586
+ Then the response decodes
587
+ And the creative's effectiveStandardFormatKey is "carousel"
588
+ And the creative's effectiveStandardFormatVersion is 1
589
+ And the creative's templateSource is "admoai_standard"
590
+ And the template key is "carousel"
591
+ And the creative's contents are exactly "brand_logo", "disclaimer"
592
+ And the creative has no click tracker
593
+ And the creative has no custom event tracker
594
+ And there are 3 slides in server order
595
+ And slide 1 is "slide_01JDY02N8MA2K2HKQ74989YS99" with contents "image", "headline", "supporting_text", "cta_text", "destination_url", view trackers "slide_view" and click trackers "default"
596
+ And slide 2 is "slide_01JD04H8GY801VF8Y0FHETP6XA" with contents "image", "headline", "supporting_text", "cta_text", "destination_url", view trackers "slide_view" and click trackers "default"
597
+ And slide 3 is "slide_01JDRGMFSTZXQ7ES1QBCF0DR2X" with contents "image", "headline", "supporting_text", "cta_text", "destination_url", view trackers "slide_view" and click trackers "default"