@admoai/sdk-scenarios 1.2.0 → 1.3.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/CHANGELOG.md CHANGED
@@ -4,6 +4,20 @@ Versioning: a scenario added or an `expect` tightened is a **minor** release; a
4
4
  removed, or a `request`/`expect` key renamed (every SDK's interpreter must change), is a
5
5
  **major** one. Each SDK vendors one version and its own CI checks the vendored bytes against it.
6
6
 
7
+ ## 1.3.0 — 2026-11-05
8
+
9
+ Adds fixture scenarios F16–F25 with a `slideTracking` block (admoai/adhub#4733): what the app
10
+ dispatches when it reports slides and interactions on a decoded standard creative, offline.
11
+ A slide view goes out once per served response, keyed on its signed URL, and again for a new
12
+ response (F16, F17). A slide click before its view sends the view, then the click, then the
13
+ creative's applicable third-party click trackers once per click. A slide view never sends them
14
+ (F18-F20). A Carousel has no creative click (F21). `fireClick` with no key sends `default`
15
+ (F22). Expand, close and asset tap are verbatim custom events, not clicks (F23, F24). A
16
+ Standard Video without a destination sends no click (F25). New edit level `tracking` (the
17
+ creative's tracking object), used to inject third-party trackers on `.example` hosts. A
18
+ `schemaVersion` moves to 3, so a runner that knows only 2 refuses the manifest instead of
19
+ skipping `slideTracking` silently; adopting 1.3.0 requires executing it.
20
+
7
21
  ## 1.2.0 — 2026-11-05
8
22
 
9
23
  Adds `fixtureScenarios` F1–F15 and moves `schemaVersion` to 2 (admoai/adhub#4733): offline
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@admoai/sdk-scenarios",
3
- "version": "1.2.0",
3
+ "version": "1.3.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": [
package/scenarios.feature CHANGED
@@ -6,7 +6,7 @@
6
6
  # promises a publisher's app, in the same words for all three. CI regenerates it and fails on
7
7
  # any difference, so it cannot drift from what the runners execute.
8
8
  # How it is published and kept fresh: docs/guides/sdk-ci.md, Section 7.
9
- # Manifest schemaVersion: 2
9
+ # Manifest schemaVersion: 3
10
10
 
11
11
  Feature: Cross-SDK decision & tracking contract
12
12
  Shared cross-SDK E2E scenario manifest. ONE definition, executed by a thin interpreter in each
@@ -22,7 +22,15 @@ Feature: Cross-SDK decision & tracking contract
22
22
  reads from the decoded creative. `contentKeys` is the exact set of plain content keys (slides
23
23
  and matched points are asserted through their own fields); a key in `contentKeysAbsent` must
24
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.
25
+ absent. A runner that does not execute fixtureScenarios must refuse schemaVersion 2. A fixture
26
+ scenario may add `slideTracking` (package 1.3.0, schemaVersion 3; a runner that does not
27
+ execute it must refuse schemaVersion 3): `steps` the app takes on the decoded creative
28
+ (`slideView`/`slideClick` with a 1-based slide index, `newResponse`, `fireClick` with a key or
29
+ null for no key, `custom` with a key) and the beacons that must be dispatched: `beacons` is
30
+ the exact ordered list of first-party beacons, each named by the tracker it must be
31
+ (`slide`+`view`/`click`, or creative `click`/`custom`, with `response`), and
32
+ `thirdPartyBeacons` the exact multiset of third-party tracker ids dispatched (their order is
33
+ not asserted). An edit `at` `tracking` targets the creative's tracking object.
26
34
 
27
35
  @L @native
28
36
  Scenario: L1 — a normal native ad serves with complete, well-formed metadata
@@ -595,3 +603,141 @@ Feature: Cross-SDK decision & tracking contract
595
603
  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
604
  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
605
  And slide 3 is "slide_01JDRGMFSTZXQ7ES1QBCF0DR2X" with contents "image", "headline", "supporting_text", "cta_text", "destination_url", view trackers "slide_view" and click trackers "default"
606
+
607
+ @F @fixture
608
+ Scenario: F16 — a slide's view beacon is sent once per served response, however often the slide is shown
609
+ Keyed on the signed view URL, never on the slideId: re-rendering or scrolling back to a
610
+ slide must not count it again (BR-SDK-04, Q19).
611
+
612
+ Given the app decodes the golden carousel.full response
613
+ And with third-party trackers "tpt_fixture_click_any", "tpt_fixture_click_default", "tpt_fixture_click_other", "tpt_fixture_impression"
614
+ When the app reports slide 1 as viewed
615
+ And the app reports slide 1 as viewed
616
+ And the app reports slide 2 as viewed
617
+ And the app reports slide 1 as viewed
618
+ Then the response decodes
619
+ And exactly these beacons are sent, in this order:
620
+ And slide 1's "slide_view" view beacon
621
+ And slide 2's "slide_view" view beacon
622
+ And no third-party tracker is sent
623
+
624
+ @F @fixture
625
+ Scenario: F17 — the same slide in a new decision response counts again
626
+ A new response carries new signed URLs for the same slides. The runner simulates it by
627
+ decoding the same golden file again with every first-party tracker URL suffixed
628
+ `&response=N` (N = 2, 3, ...); `response` in an expected beacon names which one (default 1).
629
+
630
+ Given the app decodes the golden carousel.full response
631
+ And with third-party trackers "tpt_fixture_click_any", "tpt_fixture_click_default", "tpt_fixture_click_other", "tpt_fixture_impression"
632
+ When the app reports slide 1 as viewed
633
+ And the app decodes a new decision response for the same ad
634
+ And the app reports slide 1 as viewed
635
+ And the app reports slide 1 as viewed
636
+ Then the response decodes
637
+ And exactly these beacons are sent, in this order:
638
+ And slide 1's "slide_view" view beacon
639
+ And slide 1's "slide_view" view beacon from response 2
640
+ And no third-party tracker is sent
641
+
642
+ @F @fixture
643
+ Scenario: F18 — a slide clicked before its view was sent sends the view, then the click, then the creative's applicable third-party click trackers once
644
+ Applicable means a click tracker matching any click, or the `default` click specifically; a
645
+ tracker for another click key and an impression tracker do not fire (BR-SDK-05, Q14, Q18).
646
+
647
+ Given the app decodes the golden carousel.full response
648
+ And with third-party trackers "tpt_fixture_click_any", "tpt_fixture_click_default", "tpt_fixture_click_other", "tpt_fixture_impression"
649
+ When the user clicks slide 2
650
+ Then the response decodes
651
+ And exactly these beacons are sent, in this order:
652
+ And slide 2's "slide_view" view beacon
653
+ And slide 2's "default" click beacon
654
+ And the third-party trackers sent are exactly "tpt_fixture_click_any", "tpt_fixture_click_default"
655
+
656
+ @F @fixture
657
+ Scenario: F19 — a slide clicked after its view sends only the click, on every click
658
+ Given the app decodes the golden carousel.full response
659
+ And with third-party trackers "tpt_fixture_click_any", "tpt_fixture_click_default", "tpt_fixture_click_other", "tpt_fixture_impression"
660
+ When the app reports slide 2 as viewed
661
+ And the user clicks slide 2
662
+ And the user clicks slide 2
663
+ Then the response decodes
664
+ And exactly these beacons are sent, in this order:
665
+ And slide 2's "slide_view" view beacon
666
+ And slide 2's "default" click beacon
667
+ And slide 2's "default" click beacon
668
+ And the third-party trackers sent are exactly "tpt_fixture_click_any", "tpt_fixture_click_default", "tpt_fixture_click_any", "tpt_fixture_click_default"
669
+
670
+ @F @fixture
671
+ Scenario: F20 — slide views never send third-party click trackers
672
+ Given the app decodes the golden carousel.full response
673
+ And with third-party trackers "tpt_fixture_click_any", "tpt_fixture_click_default", "tpt_fixture_click_other", "tpt_fixture_impression"
674
+ When the app reports slide 1 as viewed
675
+ And the app reports slide 2 as viewed
676
+ And the app reports slide 3 as viewed
677
+ Then the response decodes
678
+ And exactly these beacons are sent, in this order:
679
+ And slide 1's "slide_view" view beacon
680
+ And slide 2's "slide_view" view beacon
681
+ And slide 3's "slide_view" view beacon
682
+ And no third-party tracker is sent
683
+
684
+ @F @fixture
685
+ Scenario: F21 — a Carousel has no creative-level click: fireClick sends nothing, so slide clicks go through the slide helper
686
+ Publishers must not route a slide tap through fireClick (BR-SDK-03, Q9).
687
+
688
+ Given the app decodes the golden carousel.full response
689
+ And with third-party trackers "tpt_fixture_click_any", "tpt_fixture_click_default", "tpt_fixture_click_other", "tpt_fixture_impression"
690
+ When the app calls fireClick with no key
691
+ Then the response decodes
692
+ And no first-party beacon is sent
693
+ And no third-party tracker is sent
694
+
695
+ @F @fixture
696
+ Scenario: F22 — fireClick with no key sends the default click of a standard
697
+ Every standard seeds its click with key `default`, which is what fireClick sends without a
698
+ key (BR-SDK-06, Q12).
699
+
700
+ Given the app decodes the golden card.full response
701
+ And with third-party trackers "tpt_fixture_click_any", "tpt_fixture_click_default", "tpt_fixture_click_other", "tpt_fixture_impression"
702
+ When the app calls fireClick with no key
703
+ Then the response decodes
704
+ And exactly these beacons are sent, in this order:
705
+ And the creative's "default" click beacon
706
+ And the third-party trackers sent are exactly "tpt_fixture_click_any", "tpt_fixture_click_default"
707
+
708
+ @F @fixture
709
+ Scenario: F23 — expand and close are sent verbatim as custom events and are not clicks
710
+ The publisher calls them when the banner actually expands or closes; no click is sent and no
711
+ third-party click tracker fires (BR-SDK-07).
712
+
713
+ Given the app decodes the golden expandable_banner.full response
714
+ And with third-party trackers "tpt_fixture_click_any", "tpt_fixture_click_default", "tpt_fixture_click_other", "tpt_fixture_impression"
715
+ When the app sends the custom event "expand"
716
+ And the app sends the custom event "close"
717
+ Then the response decodes
718
+ And exactly these beacons are sent, in this order:
719
+ And the creative's "expand" custom beacon
720
+ And the creative's "close" custom beacon
721
+ And no third-party tracker is sent
722
+
723
+ @F @fixture
724
+ Scenario: F24 — an asset tap is sent verbatim as a custom event and is not a click
725
+ BR-SDK-07.
726
+
727
+ Given the app decodes the golden branded_assets.full response
728
+ And with third-party trackers "tpt_fixture_click_any", "tpt_fixture_click_default", "tpt_fixture_click_other", "tpt_fixture_impression"
729
+ When the app sends the custom event "asset_tap"
730
+ Then the response decodes
731
+ And exactly these beacons are sent, in this order:
732
+ And the creative's "asset_tap" custom beacon
733
+ And no third-party tracker is sent
734
+
735
+ @F @fixture
736
+ Scenario: F25 — a Standard Video without a destination sends no click
737
+ No destination means no click action and no click tracker (BR-SDK-08).
738
+
739
+ Given the app decodes the golden standard_video.minimal response
740
+ When the app calls fireClick with no key
741
+ Then the response decodes
742
+ And no first-party beacon is sent
743
+ And no third-party tracker is sent
package/scenarios.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
- "schemaVersion": 2,
3
- "description": "Shared cross-SDK E2E scenario manifest. ONE definition, executed by a thin interpreter in each SDK, so the three suites cannot drift. Declarative only: given a request, expect an outcome. Sponsored Pin tracking scenarios add `pinTracking`: the point-tracking calls an app makes on the served pins, as data, and the beacons that must reach the engine. Procedural scenarios (log capture, concurrency, retry, TTL waits) stay hand-written per SDK. Mirrored byte-identically into all three repos; a checksum test fails the build if the copies diverge. Every expected value here was verified against a live local decision-engine before being written. `fixtureScenarios` (schemaVersion 2) run offline: each decodes one golden decision-wire file (ui/platform/lib/ad-formats/golden-wire in adhub, shipped in this package under fixtures/golden-wire/) after optional `edits`, and asserts what the publisher's app reads from the decoded creative. `contentKeys` is the exact set of plain content keys (slides and matched points are asserted through their own fields); a key in `contentKeysAbsent` must decode as absent (null), never as an empty string or a placeholder; a null in `metadata` means absent. A runner that does not execute fixtureScenarios must refuse schemaVersion 2.",
2
+ "schemaVersion": 3,
3
+ "description": "Shared cross-SDK E2E scenario manifest. ONE definition, executed by a thin interpreter in each SDK, so the three suites cannot drift. Declarative only: given a request, expect an outcome. Sponsored Pin tracking scenarios add `pinTracking`: the point-tracking calls an app makes on the served pins, as data, and the beacons that must reach the engine. Procedural scenarios (log capture, concurrency, retry, TTL waits) stay hand-written per SDK. Mirrored byte-identically into all three repos; a checksum test fails the build if the copies diverge. Every expected value here was verified against a live local decision-engine before being written. `fixtureScenarios` (schemaVersion 2) run offline: each decodes one golden decision-wire file (ui/platform/lib/ad-formats/golden-wire in adhub, shipped in this package under fixtures/golden-wire/) after optional `edits`, and asserts what the publisher's app reads from the decoded creative. `contentKeys` is the exact set of plain content keys (slides and matched points are asserted through their own fields); a key in `contentKeysAbsent` must decode as absent (null), never as an empty string or a placeholder; a null in `metadata` means absent. A runner that does not execute fixtureScenarios must refuse schemaVersion 2. A fixture scenario may add `slideTracking` (package 1.3.0, schemaVersion 3; a runner that does not execute it must refuse schemaVersion 3): `steps` the app takes on the decoded creative (`slideView`/`slideClick` with a 1-based slide index, `newResponse`, `fireClick` with a key or null for no key, `custom` with a key) and the beacons that must be dispatched: `beacons` is the exact ordered list of first-party beacons, each named by the tracker it must be (`slide`+`view`/`click`, or creative `click`/`custom`, with `response`), and `thirdPartyBeacons` the exact multiset of third-party tracker ids dispatched (their order is not asserted). An edit `at` `tracking` targets the creative's tracking object.",
4
4
  "scenarios": [
5
5
  {
6
6
  "id": "L1",
@@ -1591,6 +1591,634 @@
1591
1591
  }
1592
1592
  ]
1593
1593
  }
1594
+ },
1595
+ {
1596
+ "id": "F16",
1597
+ "title": "a slide's view beacon is sent once per served response, however often the slide is shown",
1598
+ "comment": "Keyed on the signed view URL, never on the slideId: re-rendering or scrolling back to a slide must not count it again (BR-SDK-04, Q19).",
1599
+ "fixture": {
1600
+ "golden": "carousel.full",
1601
+ "edits": [
1602
+ {
1603
+ "at": "tracking",
1604
+ "add": "thirdPartyTrackers",
1605
+ "value": [
1606
+ {
1607
+ "trackerId": "tpt_fixture_click_any",
1608
+ "eventType": "click",
1609
+ "matchType": "any",
1610
+ "url": "https://adserver.example/click?c=any"
1611
+ },
1612
+ {
1613
+ "trackerId": "tpt_fixture_click_default",
1614
+ "eventType": "click",
1615
+ "matchType": "specific",
1616
+ "eventKey": "default",
1617
+ "url": "https://adserver.example/click?c=default"
1618
+ },
1619
+ {
1620
+ "trackerId": "tpt_fixture_click_other",
1621
+ "eventType": "click",
1622
+ "matchType": "specific",
1623
+ "eventKey": "save_offer",
1624
+ "url": "https://adserver.example/click?c=other"
1625
+ },
1626
+ {
1627
+ "trackerId": "tpt_fixture_impression",
1628
+ "eventType": "impression",
1629
+ "url": "https://adserver.example/imp"
1630
+ }
1631
+ ]
1632
+ }
1633
+ ]
1634
+ },
1635
+ "expect": {
1636
+ "decodes": true
1637
+ },
1638
+ "slideTracking": {
1639
+ "steps": [
1640
+ {
1641
+ "slideView": 1
1642
+ },
1643
+ {
1644
+ "slideView": 1
1645
+ },
1646
+ {
1647
+ "slideView": 2
1648
+ },
1649
+ {
1650
+ "slideView": 1
1651
+ }
1652
+ ],
1653
+ "expect": {
1654
+ "beacons": [
1655
+ {
1656
+ "slide": 1,
1657
+ "view": "slide_view"
1658
+ },
1659
+ {
1660
+ "slide": 2,
1661
+ "view": "slide_view"
1662
+ }
1663
+ ],
1664
+ "thirdPartyBeacons": []
1665
+ }
1666
+ }
1667
+ },
1668
+ {
1669
+ "id": "F17",
1670
+ "title": "the same slide in a new decision response counts again",
1671
+ "comment": "A new response carries new signed URLs for the same slides. The runner simulates it by decoding the same golden file again with every first-party tracker URL suffixed `&response=N` (N = 2, 3, ...); `response` in an expected beacon names which one (default 1).",
1672
+ "fixture": {
1673
+ "golden": "carousel.full",
1674
+ "edits": [
1675
+ {
1676
+ "at": "tracking",
1677
+ "add": "thirdPartyTrackers",
1678
+ "value": [
1679
+ {
1680
+ "trackerId": "tpt_fixture_click_any",
1681
+ "eventType": "click",
1682
+ "matchType": "any",
1683
+ "url": "https://adserver.example/click?c=any"
1684
+ },
1685
+ {
1686
+ "trackerId": "tpt_fixture_click_default",
1687
+ "eventType": "click",
1688
+ "matchType": "specific",
1689
+ "eventKey": "default",
1690
+ "url": "https://adserver.example/click?c=default"
1691
+ },
1692
+ {
1693
+ "trackerId": "tpt_fixture_click_other",
1694
+ "eventType": "click",
1695
+ "matchType": "specific",
1696
+ "eventKey": "save_offer",
1697
+ "url": "https://adserver.example/click?c=other"
1698
+ },
1699
+ {
1700
+ "trackerId": "tpt_fixture_impression",
1701
+ "eventType": "impression",
1702
+ "url": "https://adserver.example/imp"
1703
+ }
1704
+ ]
1705
+ }
1706
+ ]
1707
+ },
1708
+ "expect": {
1709
+ "decodes": true
1710
+ },
1711
+ "slideTracking": {
1712
+ "steps": [
1713
+ {
1714
+ "slideView": 1
1715
+ },
1716
+ {
1717
+ "newResponse": true
1718
+ },
1719
+ {
1720
+ "slideView": 1
1721
+ },
1722
+ {
1723
+ "slideView": 1
1724
+ }
1725
+ ],
1726
+ "expect": {
1727
+ "beacons": [
1728
+ {
1729
+ "slide": 1,
1730
+ "view": "slide_view"
1731
+ },
1732
+ {
1733
+ "slide": 1,
1734
+ "view": "slide_view",
1735
+ "response": 2
1736
+ }
1737
+ ],
1738
+ "thirdPartyBeacons": []
1739
+ }
1740
+ }
1741
+ },
1742
+ {
1743
+ "id": "F18",
1744
+ "title": "a slide clicked before its view was sent sends the view, then the click, then the creative's applicable third-party click trackers once",
1745
+ "comment": "Applicable means a click tracker matching any click, or the `default` click specifically; a tracker for another click key and an impression tracker do not fire (BR-SDK-05, Q14, Q18).",
1746
+ "fixture": {
1747
+ "golden": "carousel.full",
1748
+ "edits": [
1749
+ {
1750
+ "at": "tracking",
1751
+ "add": "thirdPartyTrackers",
1752
+ "value": [
1753
+ {
1754
+ "trackerId": "tpt_fixture_click_any",
1755
+ "eventType": "click",
1756
+ "matchType": "any",
1757
+ "url": "https://adserver.example/click?c=any"
1758
+ },
1759
+ {
1760
+ "trackerId": "tpt_fixture_click_default",
1761
+ "eventType": "click",
1762
+ "matchType": "specific",
1763
+ "eventKey": "default",
1764
+ "url": "https://adserver.example/click?c=default"
1765
+ },
1766
+ {
1767
+ "trackerId": "tpt_fixture_click_other",
1768
+ "eventType": "click",
1769
+ "matchType": "specific",
1770
+ "eventKey": "save_offer",
1771
+ "url": "https://adserver.example/click?c=other"
1772
+ },
1773
+ {
1774
+ "trackerId": "tpt_fixture_impression",
1775
+ "eventType": "impression",
1776
+ "url": "https://adserver.example/imp"
1777
+ }
1778
+ ]
1779
+ }
1780
+ ]
1781
+ },
1782
+ "expect": {
1783
+ "decodes": true
1784
+ },
1785
+ "slideTracking": {
1786
+ "steps": [
1787
+ {
1788
+ "slideClick": 2
1789
+ }
1790
+ ],
1791
+ "expect": {
1792
+ "beacons": [
1793
+ {
1794
+ "slide": 2,
1795
+ "view": "slide_view"
1796
+ },
1797
+ {
1798
+ "slide": 2,
1799
+ "click": "default"
1800
+ }
1801
+ ],
1802
+ "thirdPartyBeacons": [
1803
+ "tpt_fixture_click_any",
1804
+ "tpt_fixture_click_default"
1805
+ ]
1806
+ }
1807
+ }
1808
+ },
1809
+ {
1810
+ "id": "F19",
1811
+ "title": "a slide clicked after its view sends only the click, on every click",
1812
+ "fixture": {
1813
+ "golden": "carousel.full",
1814
+ "edits": [
1815
+ {
1816
+ "at": "tracking",
1817
+ "add": "thirdPartyTrackers",
1818
+ "value": [
1819
+ {
1820
+ "trackerId": "tpt_fixture_click_any",
1821
+ "eventType": "click",
1822
+ "matchType": "any",
1823
+ "url": "https://adserver.example/click?c=any"
1824
+ },
1825
+ {
1826
+ "trackerId": "tpt_fixture_click_default",
1827
+ "eventType": "click",
1828
+ "matchType": "specific",
1829
+ "eventKey": "default",
1830
+ "url": "https://adserver.example/click?c=default"
1831
+ },
1832
+ {
1833
+ "trackerId": "tpt_fixture_click_other",
1834
+ "eventType": "click",
1835
+ "matchType": "specific",
1836
+ "eventKey": "save_offer",
1837
+ "url": "https://adserver.example/click?c=other"
1838
+ },
1839
+ {
1840
+ "trackerId": "tpt_fixture_impression",
1841
+ "eventType": "impression",
1842
+ "url": "https://adserver.example/imp"
1843
+ }
1844
+ ]
1845
+ }
1846
+ ]
1847
+ },
1848
+ "expect": {
1849
+ "decodes": true
1850
+ },
1851
+ "slideTracking": {
1852
+ "steps": [
1853
+ {
1854
+ "slideView": 2
1855
+ },
1856
+ {
1857
+ "slideClick": 2
1858
+ },
1859
+ {
1860
+ "slideClick": 2
1861
+ }
1862
+ ],
1863
+ "expect": {
1864
+ "beacons": [
1865
+ {
1866
+ "slide": 2,
1867
+ "view": "slide_view"
1868
+ },
1869
+ {
1870
+ "slide": 2,
1871
+ "click": "default"
1872
+ },
1873
+ {
1874
+ "slide": 2,
1875
+ "click": "default"
1876
+ }
1877
+ ],
1878
+ "thirdPartyBeacons": [
1879
+ "tpt_fixture_click_any",
1880
+ "tpt_fixture_click_default",
1881
+ "tpt_fixture_click_any",
1882
+ "tpt_fixture_click_default"
1883
+ ]
1884
+ }
1885
+ }
1886
+ },
1887
+ {
1888
+ "id": "F20",
1889
+ "title": "slide views never send third-party click trackers",
1890
+ "fixture": {
1891
+ "golden": "carousel.full",
1892
+ "edits": [
1893
+ {
1894
+ "at": "tracking",
1895
+ "add": "thirdPartyTrackers",
1896
+ "value": [
1897
+ {
1898
+ "trackerId": "tpt_fixture_click_any",
1899
+ "eventType": "click",
1900
+ "matchType": "any",
1901
+ "url": "https://adserver.example/click?c=any"
1902
+ },
1903
+ {
1904
+ "trackerId": "tpt_fixture_click_default",
1905
+ "eventType": "click",
1906
+ "matchType": "specific",
1907
+ "eventKey": "default",
1908
+ "url": "https://adserver.example/click?c=default"
1909
+ },
1910
+ {
1911
+ "trackerId": "tpt_fixture_click_other",
1912
+ "eventType": "click",
1913
+ "matchType": "specific",
1914
+ "eventKey": "save_offer",
1915
+ "url": "https://adserver.example/click?c=other"
1916
+ },
1917
+ {
1918
+ "trackerId": "tpt_fixture_impression",
1919
+ "eventType": "impression",
1920
+ "url": "https://adserver.example/imp"
1921
+ }
1922
+ ]
1923
+ }
1924
+ ]
1925
+ },
1926
+ "expect": {
1927
+ "decodes": true
1928
+ },
1929
+ "slideTracking": {
1930
+ "steps": [
1931
+ {
1932
+ "slideView": 1
1933
+ },
1934
+ {
1935
+ "slideView": 2
1936
+ },
1937
+ {
1938
+ "slideView": 3
1939
+ }
1940
+ ],
1941
+ "expect": {
1942
+ "beacons": [
1943
+ {
1944
+ "slide": 1,
1945
+ "view": "slide_view"
1946
+ },
1947
+ {
1948
+ "slide": 2,
1949
+ "view": "slide_view"
1950
+ },
1951
+ {
1952
+ "slide": 3,
1953
+ "view": "slide_view"
1954
+ }
1955
+ ],
1956
+ "thirdPartyBeacons": []
1957
+ }
1958
+ }
1959
+ },
1960
+ {
1961
+ "id": "F21",
1962
+ "title": "a Carousel has no creative-level click: fireClick sends nothing, so slide clicks go through the slide helper",
1963
+ "comment": "Publishers must not route a slide tap through fireClick (BR-SDK-03, Q9).",
1964
+ "fixture": {
1965
+ "golden": "carousel.full",
1966
+ "edits": [
1967
+ {
1968
+ "at": "tracking",
1969
+ "add": "thirdPartyTrackers",
1970
+ "value": [
1971
+ {
1972
+ "trackerId": "tpt_fixture_click_any",
1973
+ "eventType": "click",
1974
+ "matchType": "any",
1975
+ "url": "https://adserver.example/click?c=any"
1976
+ },
1977
+ {
1978
+ "trackerId": "tpt_fixture_click_default",
1979
+ "eventType": "click",
1980
+ "matchType": "specific",
1981
+ "eventKey": "default",
1982
+ "url": "https://adserver.example/click?c=default"
1983
+ },
1984
+ {
1985
+ "trackerId": "tpt_fixture_click_other",
1986
+ "eventType": "click",
1987
+ "matchType": "specific",
1988
+ "eventKey": "save_offer",
1989
+ "url": "https://adserver.example/click?c=other"
1990
+ },
1991
+ {
1992
+ "trackerId": "tpt_fixture_impression",
1993
+ "eventType": "impression",
1994
+ "url": "https://adserver.example/imp"
1995
+ }
1996
+ ]
1997
+ }
1998
+ ]
1999
+ },
2000
+ "expect": {
2001
+ "decodes": true
2002
+ },
2003
+ "slideTracking": {
2004
+ "steps": [
2005
+ {
2006
+ "fireClick": null
2007
+ }
2008
+ ],
2009
+ "expect": {
2010
+ "beacons": [],
2011
+ "thirdPartyBeacons": []
2012
+ }
2013
+ }
2014
+ },
2015
+ {
2016
+ "id": "F22",
2017
+ "title": "fireClick with no key sends the default click of a standard",
2018
+ "comment": "Every standard seeds its click with key `default`, which is what fireClick sends without a key (BR-SDK-06, Q12).",
2019
+ "fixture": {
2020
+ "golden": "card.full",
2021
+ "edits": [
2022
+ {
2023
+ "at": "tracking",
2024
+ "add": "thirdPartyTrackers",
2025
+ "value": [
2026
+ {
2027
+ "trackerId": "tpt_fixture_click_any",
2028
+ "eventType": "click",
2029
+ "matchType": "any",
2030
+ "url": "https://adserver.example/click?c=any"
2031
+ },
2032
+ {
2033
+ "trackerId": "tpt_fixture_click_default",
2034
+ "eventType": "click",
2035
+ "matchType": "specific",
2036
+ "eventKey": "default",
2037
+ "url": "https://adserver.example/click?c=default"
2038
+ },
2039
+ {
2040
+ "trackerId": "tpt_fixture_click_other",
2041
+ "eventType": "click",
2042
+ "matchType": "specific",
2043
+ "eventKey": "save_offer",
2044
+ "url": "https://adserver.example/click?c=other"
2045
+ },
2046
+ {
2047
+ "trackerId": "tpt_fixture_impression",
2048
+ "eventType": "impression",
2049
+ "url": "https://adserver.example/imp"
2050
+ }
2051
+ ]
2052
+ }
2053
+ ]
2054
+ },
2055
+ "expect": {
2056
+ "decodes": true
2057
+ },
2058
+ "slideTracking": {
2059
+ "steps": [
2060
+ {
2061
+ "fireClick": null
2062
+ }
2063
+ ],
2064
+ "expect": {
2065
+ "beacons": [
2066
+ {
2067
+ "click": "default"
2068
+ }
2069
+ ],
2070
+ "thirdPartyBeacons": [
2071
+ "tpt_fixture_click_any",
2072
+ "tpt_fixture_click_default"
2073
+ ]
2074
+ }
2075
+ }
2076
+ },
2077
+ {
2078
+ "id": "F23",
2079
+ "title": "expand and close are sent verbatim as custom events and are not clicks",
2080
+ "comment": "The publisher calls them when the banner actually expands or closes; no click is sent and no third-party click tracker fires (BR-SDK-07).",
2081
+ "fixture": {
2082
+ "golden": "expandable_banner.full",
2083
+ "edits": [
2084
+ {
2085
+ "at": "tracking",
2086
+ "add": "thirdPartyTrackers",
2087
+ "value": [
2088
+ {
2089
+ "trackerId": "tpt_fixture_click_any",
2090
+ "eventType": "click",
2091
+ "matchType": "any",
2092
+ "url": "https://adserver.example/click?c=any"
2093
+ },
2094
+ {
2095
+ "trackerId": "tpt_fixture_click_default",
2096
+ "eventType": "click",
2097
+ "matchType": "specific",
2098
+ "eventKey": "default",
2099
+ "url": "https://adserver.example/click?c=default"
2100
+ },
2101
+ {
2102
+ "trackerId": "tpt_fixture_click_other",
2103
+ "eventType": "click",
2104
+ "matchType": "specific",
2105
+ "eventKey": "save_offer",
2106
+ "url": "https://adserver.example/click?c=other"
2107
+ },
2108
+ {
2109
+ "trackerId": "tpt_fixture_impression",
2110
+ "eventType": "impression",
2111
+ "url": "https://adserver.example/imp"
2112
+ }
2113
+ ]
2114
+ }
2115
+ ]
2116
+ },
2117
+ "expect": {
2118
+ "decodes": true
2119
+ },
2120
+ "slideTracking": {
2121
+ "steps": [
2122
+ {
2123
+ "custom": "expand"
2124
+ },
2125
+ {
2126
+ "custom": "close"
2127
+ }
2128
+ ],
2129
+ "expect": {
2130
+ "beacons": [
2131
+ {
2132
+ "custom": "expand"
2133
+ },
2134
+ {
2135
+ "custom": "close"
2136
+ }
2137
+ ],
2138
+ "thirdPartyBeacons": []
2139
+ }
2140
+ }
2141
+ },
2142
+ {
2143
+ "id": "F24",
2144
+ "title": "an asset tap is sent verbatim as a custom event and is not a click",
2145
+ "comment": "BR-SDK-07.",
2146
+ "fixture": {
2147
+ "golden": "branded_assets.full",
2148
+ "edits": [
2149
+ {
2150
+ "at": "tracking",
2151
+ "add": "thirdPartyTrackers",
2152
+ "value": [
2153
+ {
2154
+ "trackerId": "tpt_fixture_click_any",
2155
+ "eventType": "click",
2156
+ "matchType": "any",
2157
+ "url": "https://adserver.example/click?c=any"
2158
+ },
2159
+ {
2160
+ "trackerId": "tpt_fixture_click_default",
2161
+ "eventType": "click",
2162
+ "matchType": "specific",
2163
+ "eventKey": "default",
2164
+ "url": "https://adserver.example/click?c=default"
2165
+ },
2166
+ {
2167
+ "trackerId": "tpt_fixture_click_other",
2168
+ "eventType": "click",
2169
+ "matchType": "specific",
2170
+ "eventKey": "save_offer",
2171
+ "url": "https://adserver.example/click?c=other"
2172
+ },
2173
+ {
2174
+ "trackerId": "tpt_fixture_impression",
2175
+ "eventType": "impression",
2176
+ "url": "https://adserver.example/imp"
2177
+ }
2178
+ ]
2179
+ }
2180
+ ]
2181
+ },
2182
+ "expect": {
2183
+ "decodes": true
2184
+ },
2185
+ "slideTracking": {
2186
+ "steps": [
2187
+ {
2188
+ "custom": "asset_tap"
2189
+ }
2190
+ ],
2191
+ "expect": {
2192
+ "beacons": [
2193
+ {
2194
+ "custom": "asset_tap"
2195
+ }
2196
+ ],
2197
+ "thirdPartyBeacons": []
2198
+ }
2199
+ }
2200
+ },
2201
+ {
2202
+ "id": "F25",
2203
+ "title": "a Standard Video without a destination sends no click",
2204
+ "comment": "No destination means no click action and no click tracker (BR-SDK-08).",
2205
+ "fixture": {
2206
+ "golden": "standard_video.minimal"
2207
+ },
2208
+ "expect": {
2209
+ "decodes": true
2210
+ },
2211
+ "slideTracking": {
2212
+ "steps": [
2213
+ {
2214
+ "fireClick": null
2215
+ }
2216
+ ],
2217
+ "expect": {
2218
+ "beacons": [],
2219
+ "thirdPartyBeacons": []
2220
+ }
2221
+ }
1594
2222
  }
1595
2223
  ]
1596
2224
  }