prebid.js 7.44.0 → 7.45.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (254) hide show
  1. package/dist/33acrossBidAdapter.js +1 -1
  2. package/dist/33acrossIdSystem.js +1 -1
  3. package/dist/acuityAdsBidAdapter.js +1 -1
  4. package/dist/adagioBidAdapter.js +1 -1
  5. package/dist/adbookpspBidAdapter.js +1 -1
  6. package/dist/adgenerationBidAdapter.js +1 -1
  7. package/dist/adrelevantisBidAdapter.js +1 -1
  8. package/dist/adtrgtmeBidAdapter.js +1 -1
  9. package/dist/adxcgBidAdapter.js +1 -1
  10. package/dist/adyoulikeBidAdapter.js +1 -1
  11. package/dist/ajaBidAdapter.js +1 -1
  12. package/dist/amxBidAdapter.js +1 -1
  13. package/dist/amxIdSystem.js +1 -1
  14. package/dist/appierAnalyticsAdapter.js +1 -1
  15. package/dist/appnexusBidAdapter.js +1 -1
  16. package/dist/appushBidAdapter.js +1 -1
  17. package/dist/asoBidAdapter.js +1 -1
  18. package/dist/axonixBidAdapter.js +1 -1
  19. package/dist/beyondmediaBidAdapter.js +1 -1
  20. package/dist/bidglassBidAdapter.js +1 -1
  21. package/dist/big-richmediaBidAdapter.js +1 -1
  22. package/dist/braveBidAdapter.js +1 -1
  23. package/dist/bridgewellBidAdapter.js +1 -1
  24. package/dist/brightMountainMediaBidAdapter.js +1 -1
  25. package/dist/brightcomBidAdapter.js +1 -1
  26. package/dist/brightcomSSPBidAdapter.js +1 -1
  27. package/dist/carodaBidAdapter.js +1 -1
  28. package/dist/chtnwBidAdapter.js +1 -1
  29. package/dist/coinzillaBidAdapter.js +1 -1
  30. package/dist/compassBidAdapter.js +1 -1
  31. package/dist/concertBidAdapter.js +1 -1
  32. package/dist/connectIdSystem.js +1 -1
  33. package/dist/connectadBidAdapter.js +1 -1
  34. package/dist/consumableBidAdapter.js +1 -1
  35. package/dist/contentexchangeBidAdapter.js +1 -1
  36. package/dist/conversantAnalyticsAdapter.js +1 -1
  37. package/dist/conversantBidAdapter.js +1 -1
  38. package/dist/craftBidAdapter.js +1 -1
  39. package/dist/criteoBidAdapter.js +1 -1
  40. package/dist/cwireBidAdapter.js +1 -1
  41. package/dist/dependencies.json +12 -0
  42. package/dist/domainOverrideToRootDomain.js +1 -0
  43. package/dist/dspxBidAdapter.js +1 -1
  44. package/dist/eplanningBidAdapter.js +1 -1
  45. package/dist/feedadBidAdapter.js +1 -1
  46. package/dist/finativeBidAdapter.js +1 -1
  47. package/dist/freewheel-sspBidAdapter.js +1 -1
  48. package/dist/glimpseBidAdapter.js +1 -1
  49. package/dist/globalsunBidAdapter.js +1 -1
  50. package/dist/gmosspBidAdapter.js +1 -1
  51. package/dist/goldbachBidAdapter.js +1 -1
  52. package/dist/greenbidsAnalyticsAdapter.js +1 -1
  53. package/dist/gridBidAdapter.js +1 -1
  54. package/dist/gridNMBidAdapter.js +1 -1
  55. package/dist/growthCodeIdSystem.js +1 -1
  56. package/dist/gumgumBidAdapter.js +1 -1
  57. package/dist/h12mediaBidAdapter.js +1 -1
  58. package/dist/id5IdSystem.js +1 -1
  59. package/dist/improvedigitalBidAdapter.js +1 -1
  60. package/dist/inmarBidAdapter.js +1 -1
  61. package/dist/insticatorBidAdapter.js +1 -1
  62. package/dist/iqzoneBidAdapter.js +1 -1
  63. package/dist/ivsBidAdapter.js +1 -0
  64. package/dist/ixBidAdapter.js +1 -1
  65. package/dist/justpremiumBidAdapter.js +1 -1
  66. package/dist/jwplayerVideoProvider.js +1 -1
  67. package/dist/kargoBidAdapter.js +1 -1
  68. package/dist/koblerBidAdapter.js +1 -1
  69. package/dist/konduitAnalyticsAdapter.js +1 -1
  70. package/dist/kueezBidAdapter.js +1 -1
  71. package/dist/kueezRtbBidAdapter.js +1 -1
  72. package/dist/kulturemediaBidAdapter.js +1 -1
  73. package/dist/lassoBidAdapter.js +1 -1
  74. package/dist/lifestreetBidAdapter.js +1 -1
  75. package/dist/liveIntentIdSystem.js +1 -1
  76. package/dist/liveyieldAnalyticsAdapter.js +1 -1
  77. package/dist/logicadBidAdapter.js +1 -1
  78. package/dist/loglyliftBidAdapter.js +1 -1
  79. package/dist/luponmediaBidAdapter.js +1 -1
  80. package/dist/magniteAnalyticsAdapter.js +1 -1
  81. package/dist/malltvAnalyticsAdapter.js +1 -1
  82. package/dist/marsmediaBidAdapter.js +1 -1
  83. package/dist/mathildeadsBidAdapter.js +1 -1
  84. package/dist/mediafuseBidAdapter.js +1 -1
  85. package/dist/medianetBidAdapter.js +1 -1
  86. package/dist/mediasquareBidAdapter.js +1 -1
  87. package/dist/mgidBidAdapter.js +1 -1
  88. package/dist/minutemediaBidAdapter.js +1 -1
  89. package/dist/minutemediaplusBidAdapter.js +1 -1
  90. package/dist/nexx360BidAdapter.js +1 -1
  91. package/dist/not-for-prod/prebid.js +158 -156
  92. package/dist/oguryBidAdapter.js +1 -1
  93. package/dist/onetagBidAdapter.js +1 -1
  94. package/dist/onomagicBidAdapter.js +1 -1
  95. package/dist/ooloAnalyticsAdapter.js +1 -1
  96. package/dist/openxBidAdapter.js +1 -1
  97. package/dist/openxOrtbBidAdapter.js +1 -1
  98. package/dist/operaadsBidAdapter.js +1 -1
  99. package/dist/optidigitalBidAdapter.js +1 -1
  100. package/dist/outbrainBidAdapter.js +1 -1
  101. package/dist/parrableIdSystem.js +1 -1
  102. package/dist/pixfutureBidAdapter.js +1 -1
  103. package/dist/prebid-core.js +1 -1
  104. package/dist/publinkIdSystem.js +1 -1
  105. package/dist/pubmaticBidAdapter.js +1 -1
  106. package/dist/pubwiseAnalyticsAdapter.js +1 -1
  107. package/dist/pubxBidAdapter.js +1 -1
  108. package/dist/pxyzBidAdapter.js +1 -1
  109. package/dist/quantcastBidAdapter.js +1 -1
  110. package/dist/readpeakBidAdapter.js +1 -1
  111. package/dist/relaidoBidAdapter.js +1 -1
  112. package/dist/rhythmoneBidAdapter.js +1 -1
  113. package/dist/riseBidAdapter.js +1 -1
  114. package/dist/rubiconAnalyticsAdapter.js +1 -1
  115. package/dist/rubiconBidAdapter.js +1 -1
  116. package/dist/seedingAllianceBidAdapter.js +1 -1
  117. package/dist/seedtagBidAdapter.js +1 -1
  118. package/dist/sharedIdSystem.js +1 -1
  119. package/dist/sharethroughAnalyticsAdapter.js +1 -1
  120. package/dist/sharethroughBidAdapter.js +1 -1
  121. package/dist/shinezBidAdapter.js +1 -1
  122. package/dist/smaatoBidAdapter.js +1 -1
  123. package/dist/smartadserverBidAdapter.js +1 -1
  124. package/dist/smarthubBidAdapter.js +1 -1
  125. package/dist/smartxBidAdapter.js +1 -1
  126. package/dist/smilewantedBidAdapter.js +1 -1
  127. package/dist/sonobiBidAdapter.js +1 -1
  128. package/dist/sovrnAnalyticsAdapter.js +1 -1
  129. package/dist/sovrnBidAdapter.js +1 -1
  130. package/dist/sspBCBidAdapter.js +1 -1
  131. package/dist/stvBidAdapter.js +1 -1
  132. package/dist/sublimeBidAdapter.js +1 -1
  133. package/dist/synacormediaBidAdapter.js +1 -1
  134. package/dist/targetVideoBidAdapter.js +1 -1
  135. package/dist/teadsBidAdapter.js +1 -1
  136. package/dist/trionBidAdapter.js +1 -1
  137. package/dist/tripleliftBidAdapter.js +1 -1
  138. package/dist/truereachBidAdapter.js +1 -1
  139. package/dist/ttdBidAdapter.js +1 -1
  140. package/dist/ucfunnelAnalyticsAdapter.js +1 -1
  141. package/dist/uid2IdSystem.js +1 -1
  142. package/dist/underdogmediaBidAdapter.js +1 -1
  143. package/dist/undertoneBidAdapter.js +1 -1
  144. package/dist/userId.js +1 -1
  145. package/dist/vidazooBidAdapter.js +1 -1
  146. package/dist/videobyteBidAdapter.js +1 -1
  147. package/dist/videoheroesBidAdapter.js +1 -1
  148. package/dist/vidoomyBidAdapter.js +1 -1
  149. package/dist/visiblemeasuresBidAdapter.js +1 -1
  150. package/dist/visxBidAdapter.js +1 -1
  151. package/dist/vrtcalBidAdapter.js +1 -1
  152. package/dist/vuukleBidAdapter.js +1 -1
  153. package/dist/widespaceBidAdapter.js +1 -1
  154. package/dist/winrBidAdapter.js +1 -1
  155. package/dist/yahoosspBidAdapter.js +1 -1
  156. package/dist/yieldmoBidAdapter.js +1 -1
  157. package/dist/yieldoneAnalyticsAdapter.js +1 -1
  158. package/dist/yieldoneBidAdapter.js +1 -1
  159. package/libraries/domainOverrideToRootDomain/index.js +39 -0
  160. package/modules/acuityAdsBidAdapter.js +1 -1
  161. package/modules/amxBidAdapter.js +1 -1
  162. package/modules/amxIdSystem.js +23 -20
  163. package/modules/amxIdSystem.md +7 -7
  164. package/modules/appushBidAdapter.js +1 -1
  165. package/modules/beyondmediaBidAdapter.js +1 -1
  166. package/modules/braveBidAdapter.js +1 -1
  167. package/modules/brightcomBidAdapter.js +1 -1
  168. package/modules/brightcomSSPBidAdapter.js +1 -1
  169. package/modules/coinzillaBidAdapter.js +1 -2
  170. package/modules/compassBidAdapter.js +1 -1
  171. package/modules/connectIdSystem.js +96 -21
  172. package/modules/connectIdSystem.md +6 -5
  173. package/modules/contentexchangeBidAdapter.js +1 -1
  174. package/modules/freewheel-sspBidAdapter.js +8 -0
  175. package/modules/glimpseBidAdapter.js +1 -2
  176. package/modules/globalsunBidAdapter.js +1 -1
  177. package/modules/gridBidAdapter.js +1 -1
  178. package/modules/gridNMBidAdapter.js +1 -1
  179. package/modules/growthCodeIdSystem.js +18 -15
  180. package/modules/gumgumBidAdapter.js +1 -1
  181. package/modules/iqzoneBidAdapter.js +1 -1
  182. package/modules/ivsBidAdapter.js +85 -0
  183. package/modules/ivsBidAdapter.md +34 -0
  184. package/modules/ixBidAdapter.js +42 -105
  185. package/modules/jwplayerVideoProvider.js +25 -32
  186. package/modules/koblerBidAdapter.js +1 -2
  187. package/modules/kueezBidAdapter.js +1 -1
  188. package/modules/liveIntentIdSystem.js +8 -0
  189. package/modules/luponmediaBidAdapter.js +1 -1
  190. package/modules/magniteAnalyticsAdapter.js +76 -3
  191. package/modules/mathildeadsBidAdapter.js +1 -1
  192. package/modules/medianetBidAdapter.js +1 -1
  193. package/modules/mgidBidAdapter.js +178 -26
  194. package/modules/minutemediaBidAdapter.js +1 -1
  195. package/modules/oguryBidAdapter.js +3 -2
  196. package/modules/onomagicBidAdapter.js +1 -2
  197. package/modules/openxBidAdapter.js +192 -563
  198. package/modules/openxBidAdapter.md +22 -20
  199. package/modules/openxOrtbBidAdapter.js +13 -11
  200. package/modules/openxOrtbBidAdapter.md +5 -3
  201. package/modules/operaadsBidAdapter.js +1 -1
  202. package/modules/pubmaticBidAdapter.js +1 -1
  203. package/modules/pubxBidAdapter.js +5 -2
  204. package/modules/riseBidAdapter.js +1 -1
  205. package/modules/sharedIdSystem.js +4 -27
  206. package/modules/sharethroughBidAdapter.js +1 -1
  207. package/modules/shinezBidAdapter.js +1 -1
  208. package/modules/smarthubBidAdapter.js +1 -1
  209. package/modules/synacormediaBidAdapter.js +1 -3
  210. package/modules/truereachBidAdapter.js +1 -2
  211. package/modules/userId/eids.js +18 -0
  212. package/modules/userId/eids.md +16 -0
  213. package/modules/videoheroesBidAdapter.js +1 -1
  214. package/modules/vidoomyBidAdapter.js +22 -1
  215. package/modules/visiblemeasuresBidAdapter.js +1 -1
  216. package/modules/vrtcalBidAdapter.js +1 -1
  217. package/modules/yieldoneBidAdapter.js +1 -1
  218. package/package.json +1 -1
  219. package/src/Renderer.js +2 -1
  220. package/src/native.js +5 -1
  221. package/test/spec/auctionmanager_spec.js +2 -2
  222. package/test/spec/libraries/domainOverrideToRootDomain/index_spec.js +77 -0
  223. package/test/spec/modules/acuityAdsBidAdapter_spec.js +2 -1
  224. package/test/spec/modules/amxIdSystem_spec.js +13 -26
  225. package/test/spec/modules/appushBidAdapter_spec.js +2 -1
  226. package/test/spec/modules/beyondmediaBidAdapter_spec.js +2 -1
  227. package/test/spec/modules/compassBidAdapter_spec.js +2 -1
  228. package/test/spec/modules/connectIdSystem_spec.js +420 -242
  229. package/test/spec/modules/contentexchangeBidAdapter_spec.js +2 -1
  230. package/test/spec/modules/eids_spec.js +30 -0
  231. package/test/spec/modules/freewheel-sspBidAdapter_spec.js +37 -0
  232. package/test/spec/modules/globalsunBidAdapter_spec.js +2 -1
  233. package/test/spec/modules/iqzoneBidAdapter_spec.js +2 -1
  234. package/test/spec/modules/ivsBidAdapter_spec.js +197 -0
  235. package/test/spec/modules/ixBidAdapter_spec.js +84 -71
  236. package/test/spec/modules/koblerBidAdapter_spec.js +0 -20
  237. package/test/spec/modules/liveIntentIdSystem_spec.js +10 -0
  238. package/test/spec/modules/luponmediaBidAdapter_spec.js +1 -1
  239. package/test/spec/modules/magniteAnalyticsAdapter_spec.js +129 -1
  240. package/test/spec/modules/mathildeadsBidAdapter_spec.js +2 -1
  241. package/test/spec/modules/mgidBidAdapter_spec.js +184 -36
  242. package/test/spec/modules/oguryBidAdapter_spec.js +19 -4
  243. package/test/spec/modules/openxBidAdapter_spec.js +1157 -1936
  244. package/test/spec/modules/openxOrtbBidAdapter_spec.js +12 -39
  245. package/test/spec/modules/pubxBidAdapter_spec.js +10 -2
  246. package/test/spec/modules/sharedIdSystem_spec.js +0 -46
  247. package/test/spec/modules/sharethroughBidAdapter_spec.js +2 -1
  248. package/test/spec/modules/smarthubBidAdapter_spec.js +2 -1
  249. package/test/spec/modules/synacormediaBidAdapter_spec.js +0 -26
  250. package/test/spec/modules/videoModule/submodules/jwplayerVideoProvider_spec.js +17 -4
  251. package/test/spec/modules/vidoomyBidAdapter_spec.js +35 -0
  252. package/test/spec/modules/visiblemeasuresBidAdapter_spec.js +2 -1
  253. package/test/spec/modules/vrtcalBidAdapter_spec.js +3 -2
  254. package/test/spec/renderer_spec.js +1 -2
@@ -1,204 +1,81 @@
1
1
  import {expect} from 'chai';
2
- import {spec, USER_ID_CODE_TO_QUERY_ARG} from 'modules/openxBidAdapter.js';
2
+ import {spec, REQUEST_URL, SYNC_URL, DEFAULT_PH} from 'modules/openxOrtbBidAdapter.js';
3
3
  import {newBidder} from 'src/adapters/bidderFactory.js';
4
4
  import {BANNER, VIDEO} from 'src/mediaTypes.js';
5
- import {userSync} from 'src/userSync.js';
6
5
  import {config} from 'src/config.js';
7
6
  import * as utils from 'src/utils.js';
7
+ // load modules that register ORTB processors
8
+ import 'src/prebid.js'
9
+ import 'modules/currency.js';
10
+ import 'modules/userId/index.js';
11
+ import 'modules/multibid/index.js';
12
+ import 'modules/priceFloors.js';
13
+ import 'modules/consentManagement.js';
14
+ import 'modules/consentManagementUsp.js';
15
+ import 'modules/schain.js';
16
+ import {deepClone} from 'src/utils.js';
17
+ import {syncAddFPDToBidderRequest} from '../../helpers/fpd.js';
18
+ import {hook} from '../../../src/hook.js';
19
+
20
+ const DEFAULT_SYNC = SYNC_URL + '?ph=' + DEFAULT_PH;
21
+
22
+ const BidRequestBuilder = function BidRequestBuilder(options) {
23
+ const defaults = {
24
+ request: {
25
+ auctionId: '4fd1ca2d-846c-4211-b9e5-321dfe1709c9',
26
+ adUnitCode: 'adunit-code',
27
+ bidder: 'openx'
28
+ },
29
+ params: {
30
+ unit: '12345678',
31
+ delDomain: 'test-del-domain'
32
+ },
33
+ sizes: [[300, 250], [300, 600]],
34
+ };
8
35
 
9
- const URLBASE = '/w/1.0/arj';
10
- const URLBASEVIDEO = '/v/1.0/avjp';
11
-
12
- describe('OpenxAdapter', function () {
13
- const adapter = newBidder(spec);
14
-
15
- /**
16
- * Type Definitions
17
- */
18
-
19
- /**
20
- * @typedef {{
21
- * impression: string,
22
- * inview: string,
23
- * click: string
24
- * }}
25
- */
26
- let OxArjTracking;
27
- /**
28
- * @typedef {{
29
- * ads: {
30
- * version: number,
31
- * count: number,
32
- * pixels: string,
33
- * ad: Array<OxArjAdUnit>
34
- * }
35
- * }}
36
- */
37
- let OxArjResponse;
38
- /**
39
- * @typedef {{
40
- * adunitid: number,
41
- * adid:number,
42
- * type: string,
43
- * htmlz: string,
44
- * framed: number,
45
- * is_fallback: number,
46
- * ts: string,
47
- * cpipc: number,
48
- * pub_rev: string,
49
- * tbd: ?string,
50
- * adv_id: string,
51
- * deal_id: string,
52
- * auct_win_is_deal: number,
53
- * brand_id: string,
54
- * currency: string,
55
- * idx: string,
56
- * creative: Array<OxArjCreative>
57
- * }}
58
- */
59
- let OxArjAdUnit;
60
- /**
61
- * @typedef {{
62
- * id: string,
63
- * width: string,
64
- * height: string,
65
- * target: string,
66
- * mime: string,
67
- * media: string,
68
- * tracking: OxArjTracking
69
- * }}
70
- */
71
- let OxArjCreative;
72
-
73
- // HELPER METHODS
74
- /**
75
- * @type {OxArjCreative}
76
- */
77
- const DEFAULT_TEST_ARJ_CREATIVE = {
78
- id: '0',
79
- width: 'test-width',
80
- height: 'test-height',
81
- target: 'test-target',
82
- mime: 'test-mime',
83
- media: 'test-media',
84
- tracking: {
85
- impression: 'test-impression',
86
- inview: 'test-inview',
87
- click: 'test-click'
88
- }
36
+ const request = {
37
+ ...defaults.request,
38
+ ...options
89
39
  };
90
40
 
91
- /**
92
- * @type {OxArjAdUnit}
93
- */
94
- const DEFAULT_TEST_ARJ_AD_UNIT = {
95
- adunitid: 0,
96
- type: 'test-type',
97
- html: 'test-html',
98
- framed: 0,
99
- is_fallback: 0,
100
- ts: 'test-ts',
101
- tbd: 'NaN',
102
- deal_id: undefined,
103
- auct_win_is_deal: undefined,
104
- cpipc: 0,
105
- pub_rev: 'test-pub_rev',
106
- adv_id: 'test-adv_id',
107
- brand_id: 'test-brand_id',
108
- currency: 'test-currency',
109
- idx: '0',
110
- creative: [DEFAULT_TEST_ARJ_CREATIVE]
41
+ this.withParams = (options) => {
42
+ request.params = {
43
+ ...defaults.params,
44
+ ...options
45
+ };
46
+ return this;
111
47
  };
112
48
 
113
- /**
114
- * @type {OxArjResponse}
115
- */
116
- const DEFAULT_ARJ_RESPONSE = {
117
- ads: {
118
- version: 0,
119
- count: 1,
120
- pixels: 'https://testpixels.net',
121
- ad: [DEFAULT_TEST_ARJ_AD_UNIT]
49
+ this.build = () => request;
50
+ };
51
+
52
+ const BidderRequestBuilder = function BidderRequestBuilder(options) {
53
+ const defaults = {
54
+ bidderCode: 'openx',
55
+ auctionId: '4fd1ca2d-846c-4211-b9e5-321dfe1709c9',
56
+ bidderRequestId: '7g36s867Tr4xF90X',
57
+ timeout: 3000,
58
+ refererInfo: {
59
+ numIframes: 0,
60
+ reachedTop: true,
61
+ referer: 'http://test.io/index.html?pbjs_debug=true'
122
62
  }
123
63
  };
124
64
 
125
- // Sample bid requests
65
+ const request = {
66
+ ...defaults,
67
+ ...options
68
+ };
126
69
 
127
- const BANNER_BID_REQUESTS_WITH_MEDIA_TYPES = [{
128
- bidder: 'openx',
129
- params: {
130
- unit: '11',
131
- delDomain: 'test-del-domain'
132
- },
133
- adUnitCode: '/adunit-code/test-path',
134
- mediaTypes: {
135
- banner: {
136
- sizes: [[300, 250], [300, 600]]
137
- }
138
- },
139
- bidId: 'test-bid-id-1',
140
- bidderRequestId: 'test-bid-request-1',
141
- auctionId: 'test-auction-1',
142
- ortb2Imp: { ext: { data: { pbadslot: '/12345/my-gpt-tag-0' } } },
143
- }, {
144
- bidder: 'openx',
145
- params: {
146
- unit: '22',
147
- delDomain: 'test-del-domain'
148
- },
149
- adUnitCode: 'adunit-code',
150
- mediaTypes: {
151
- banner: {
152
- sizes: [[728, 90]]
153
- }
154
- },
155
- bidId: 'test-bid-id-2',
156
- bidderRequestId: 'test-bid-request-2',
157
- auctionId: 'test-auction-2',
158
- ortb2Imp: { ext: { data: { pbadslot: '/12345/my-gpt-tag-1' } } },
159
- }];
160
-
161
- const VIDEO_BID_REQUESTS_WITH_MEDIA_TYPES = [{
162
- bidder: 'openx',
163
- mediaTypes: {
164
- video: {
165
- playerSize: [640, 480]
166
- }
167
- },
168
- params: {
169
- unit: '12345678',
170
- delDomain: 'test-del-domain'
171
- },
172
- adUnitCode: 'adunit-code',
70
+ this.build = () => request;
71
+ };
173
72
 
174
- bidId: '30b31c1838de1e',
175
- bidderRequestId: '22edbae2733bf6',
176
- auctionId: '1d1a030790a475',
177
- transactionId: '4008d88a-8137-410b-aa35-fbfdabcb478e',
178
- ortb2Imp: { ext: { data: { pbadslot: '/12345/my-gpt-tag-0' } } },
179
- }];
73
+ describe('OpenxRtbAdapter', function () {
74
+ before(() => {
75
+ hook.ready();
76
+ });
180
77
 
181
- const MULTI_FORMAT_BID_REQUESTS = [{
182
- bidder: 'openx',
183
- params: {
184
- unit: '12345678',
185
- delDomain: 'test-del-domain'
186
- },
187
- adUnitCode: 'adunit-code',
188
- mediaTypes: {
189
- banner: {
190
- sizes: [[300, 250]]
191
- },
192
- video: {
193
- playerSize: [300, 250]
194
- }
195
- },
196
- bidId: '30b31c1838de1e',
197
- bidderRequestId: '22edbae2733bf6',
198
- auctionId: '1d1a030790a475',
199
- transactionId: '4008d88a-8137-410b-aa35-fbfdabcb478e',
200
- ortb2Imp: { ext: { data: { pbadslot: '/12345/my-gpt-tag-0' } } },
201
- }];
78
+ const adapter = newBidder(spec);
202
79
 
203
80
  describe('inherited functions', function () {
204
81
  it('exists and is a function', function () {
@@ -206,7 +83,7 @@ describe('OpenxAdapter', function () {
206
83
  });
207
84
  });
208
85
 
209
- describe('isBidRequestValid', function () {
86
+ describe('isBidRequestValid()', function () {
210
87
  describe('when request is for a banner ad', function () {
211
88
  let bannerBid;
212
89
  beforeEach(function () {
@@ -259,8 +136,28 @@ describe('OpenxAdapter', function () {
259
136
 
260
137
  describe('when request is for a multiformat ad', function () {
261
138
  describe('and request config uses mediaTypes video and banner', () => {
139
+ const multiformatBid = {
140
+ bidder: 'openx',
141
+ params: {
142
+ unit: '12345678',
143
+ delDomain: 'test-del-domain'
144
+ },
145
+ adUnitCode: 'adunit-code',
146
+ mediaTypes: {
147
+ banner: {
148
+ sizes: [[300, 250]]
149
+ },
150
+ video: {
151
+ playerSize: [300, 250]
152
+ }
153
+ },
154
+ bidId: '30b31c1838de1e',
155
+ bidderRequestId: '22edbae2733bf6',
156
+ auctionId: '1d1a030790a475',
157
+ transactionId: '4008d88a-8137-410b-aa35-fbfdabcb478e'
158
+ };
262
159
  it('should return true multisize when required params found', function () {
263
- expect(spec.isBidRequestValid(MULTI_FORMAT_BID_REQUESTS[0])).to.equal(true);
160
+ expect(spec.isBidRequestValid(multiformatBid)).to.equal(true);
264
161
  });
265
162
  });
266
163
  });
@@ -349,1509 +246,1035 @@ describe('OpenxAdapter', function () {
349
246
  expect(spec.isBidRequestValid(videoBidWithMediaType)).to.equal(false);
350
247
  });
351
248
  });
352
-
353
- describe('and request config uses test', () => {
354
- const videoBidWithTest = {
355
- bidder: 'openx',
356
- params: {
357
- unit: '12345678',
358
- delDomain: 'test-del-domain',
359
- test: true
360
- },
361
- adUnitCode: 'adunit-code',
362
- mediaTypes: {
363
- video: {
364
- playerSize: [640, 480]
365
- }
366
- },
367
- bidId: '30b31c1838de1e',
368
- bidderRequestId: '22edbae2733bf6',
369
- auctionId: '1d1a030790a475',
370
- transactionId: '4008d88a-8137-410b-aa35-fbfdabcb478e'
371
- };
372
-
373
- let mockBidderRequest = {refererInfo: {}};
374
-
375
- it('should return true when required params found', function () {
376
- expect(spec.isBidRequestValid(videoBidWithTest)).to.equal(true);
377
- });
378
-
379
- it('should send video bid request to openx url via GET, with vtest=1 video parameter', function () {
380
- const request = spec.buildRequests([videoBidWithTest], mockBidderRequest);
381
- expect(request[0].data.vtest).to.equal(1);
382
- });
383
- });
384
249
  });
385
250
  });
386
251
 
387
- describe('buildRequests for banner ads', function () {
388
- const bidRequestsWithMediaTypes = BANNER_BID_REQUESTS_WITH_MEDIA_TYPES;
389
-
390
- const bidRequestsWithPlatform = [{
391
- 'bidder': 'openx',
392
- 'params': {
393
- 'unit': '11',
394
- 'platform': '1cabba9e-cafe-3665-beef-f00f00f00f00'
395
- },
396
- 'adUnitCode': '/adunit-code/test-path',
397
- mediaTypes: {
398
- banner: {
399
- sizes: [[300, 250], [300, 600]]
400
- }
401
- },
402
- 'bidId': 'test-bid-id-1',
403
- 'bidderRequestId': 'test-bid-request-1',
404
- 'auctionId': 'test-auction-1'
405
- }, {
406
- 'bidder': 'openx',
407
- 'params': {
408
- 'unit': '11',
409
- 'platform': '1cabba9e-cafe-3665-beef-f00f00f00f00'
410
- },
411
- 'adUnitCode': '/adunit-code/test-path',
412
- mediaTypes: {
413
- banner: {
414
- sizes: [[300, 250], [300, 600]]
415
- }
416
- },
417
- 'bidId': 'test-bid-id-1',
418
- 'bidderRequestId': 'test-bid-request-1',
419
- 'auctionId': 'test-auction-1'
420
- }];
421
-
422
- const mockBidderRequest = {refererInfo: {}};
423
-
424
- it('should send bid request to openx url via GET, with mediaTypes specified with banner type', function () {
425
- const request = spec.buildRequests(bidRequestsWithMediaTypes, mockBidderRequest);
426
- expect(request[0].url).to.equal('https://' + bidRequestsWithMediaTypes[0].params.delDomain + URLBASE);
427
- expect(request[0].data.ph).to.be.undefined;
428
- expect(request[0].method).to.equal('GET');
429
- });
430
-
431
- it('should send bid request to openx platform url via GET, if platform is present', function () {
432
- const request = spec.buildRequests(bidRequestsWithPlatform, mockBidderRequest);
433
- expect(request[0].url).to.equal(`https://u.openx.net${URLBASE}`);
434
- expect(request[0].data.ph).to.equal(bidRequestsWithPlatform[0].params.platform);
435
- expect(request[0].method).to.equal('GET');
436
- });
437
-
438
- it('should send bid request to openx platform url via GET, if both params present', function () {
439
- const bidRequestsWithPlatformAndDelDomain = [{
440
- 'bidder': 'openx',
441
- 'params': {
442
- 'unit': '11',
443
- 'delDomain': 'test-del-domain',
444
- 'platform': '1cabba9e-cafe-3665-beef-f00f00f00f00'
445
- },
446
- 'adUnitCode': '/adunit-code/test-path',
447
- mediaTypes: {
448
- banner: {
449
- sizes: [[300, 250], [300, 600]]
450
- }
451
- },
452
- 'bidId': 'test-bid-id-1',
453
- 'bidderRequestId': 'test-bid-request-1',
454
- 'auctionId': 'test-auction-1'
455
- }, {
456
- 'bidder': 'openx',
457
- 'params': {
458
- 'unit': '11',
459
- 'delDomain': 'test-del-domain',
460
- 'platform': '1cabba9e-cafe-3665-beef-f00f00f00f00'
461
- },
462
- 'adUnitCode': '/adunit-code/test-path',
463
- mediaTypes: {
464
- banner: {
465
- sizes: [[300, 250], [300, 600]]
466
- }
467
- },
468
- 'bidId': 'test-bid-id-1',
469
- 'bidderRequestId': 'test-bid-request-1',
470
- 'auctionId': 'test-auction-1'
471
- }];
472
-
473
- const request = spec.buildRequests(bidRequestsWithPlatformAndDelDomain, mockBidderRequest);
474
- expect(request[0].url).to.equal(`https://u.openx.net${URLBASE}`);
475
- expect(request[0].data.ph).to.equal(bidRequestsWithPlatform[0].params.platform);
476
- expect(request[0].method).to.equal('GET');
477
- });
252
+ describe('buildRequests()', function () {
253
+ let bidRequestsWithMediaTypes;
254
+ let bidRequestsWithPlatform;
255
+ let mockBidderRequest;
478
256
 
479
- it('should send the adunit codes', function () {
480
- const request = spec.buildRequests(bidRequestsWithMediaTypes, mockBidderRequest);
481
- expect(request[0].data.divids).to.equal(`${encodeURIComponent(bidRequestsWithMediaTypes[0].adUnitCode)},${encodeURIComponent(bidRequestsWithMediaTypes[1].adUnitCode)}`);
482
- });
483
-
484
- it('should send the gpids', function () {
485
- const request = spec.buildRequests(bidRequestsWithMediaTypes, mockBidderRequest);
486
- expect(request[0].data.aucs).to.equal(`${encodeURIComponent('/12345/my-gpt-tag-0')},${encodeURIComponent('/12345/my-gpt-tag-1')}`);
487
- });
257
+ beforeEach(function () {
258
+ mockBidderRequest = {refererInfo: {}};
488
259
 
489
- it('should send ad unit ids when any are defined', function () {
490
- const bidRequestsWithUnitIds = [{
491
- 'bidder': 'openx',
492
- 'params': {
493
- 'delDomain': 'test-del-domain'
260
+ bidRequestsWithMediaTypes = [{
261
+ bidder: 'openx',
262
+ params: {
263
+ unit: '11',
264
+ delDomain: 'test-del-domain',
265
+ platform: '1cabba9e-cafe-3665-beef-f00f00f00f00',
494
266
  },
495
- 'adUnitCode': 'adunit-code',
267
+ adUnitCode: '/adunit-code/test-path',
496
268
  mediaTypes: {
497
269
  banner: {
498
270
  sizes: [[300, 250], [300, 600]]
499
271
  }
500
272
  },
501
- 'bidId': 'test-bid-id-1',
502
- 'bidderRequestId': 'test-bid-request-1',
503
- 'auctionId': 'test-auction-1'
504
- }, {
505
- 'bidder': 'openx',
506
- 'params': {
507
- 'unit': '22',
508
- 'delDomain': 'test-del-domain'
509
- },
510
- 'adUnitCode': 'adunit-code',
511
- mediaTypes: {
512
- banner: {
513
- sizes: [[728, 90]]
514
- }
515
- },
516
- 'bidId': 'test-bid-id-2',
517
- 'bidderRequestId': 'test-bid-request-2',
518
- 'auctionId': 'test-auction-2'
519
- }];
520
- const request = spec.buildRequests(bidRequestsWithUnitIds, mockBidderRequest);
521
- expect(request[0].data.auid).to.equal(`,${bidRequestsWithUnitIds[1].params.unit}`);
522
- });
523
-
524
- it('should not send any ad unit ids when none are defined', function () {
525
- const bidRequestsWithoutUnitIds = [{
526
- 'bidder': 'openx',
527
- 'params': {
528
- 'delDomain': 'test-del-domain'
529
- },
530
- 'adUnitCode': 'adunit-code',
531
- mediaTypes: {
532
- banner: {
533
- sizes: [[300, 250], [300, 600]]
273
+ bidId: 'test-bid-id-1',
274
+ bidderRequestId: 'test-bid-request-1',
275
+ auctionId: 'test-auction-1',
276
+ transactionId: 'test-transactionId-1',
277
+ ortb2Imp: {
278
+ ext: {
279
+ ae: 2
534
280
  }
535
- },
536
- 'bidId': 'test-bid-id-1',
537
- 'bidderRequestId': 'test-bid-request-1',
538
- 'auctionId': 'test-auction-1'
281
+ }
539
282
  }, {
540
- 'bidder': 'openx',
541
- 'params': {
542
- 'delDomain': 'test-del-domain'
283
+ bidder: 'openx',
284
+ params: {
285
+ unit: '22',
286
+ delDomain: 'test-del-domain',
287
+ platform: '1cabba9e-cafe-3665-beef-f00f00f00f00',
543
288
  },
544
- 'adUnitCode': 'adunit-code',
289
+ adUnitCode: 'adunit-code',
545
290
  mediaTypes: {
546
- banner: {
547
- sizes: [[728, 90]]
291
+ video: {
292
+ playerSize: [640, 480]
548
293
  }
549
294
  },
550
- 'bidId': 'test-bid-id-2',
551
- 'bidderRequestId': 'test-bid-request-2',
552
- 'auctionId': 'test-auction-2'
295
+ bidId: 'test-bid-id-2',
296
+ bidderRequestId: 'test-bid-request-2',
297
+ auctionId: 'test-auction-2',
298
+ transactionId: 'test-transactionId-2'
553
299
  }];
554
- const request = spec.buildRequests(bidRequestsWithoutUnitIds, mockBidderRequest);
555
- expect(request[0].data).to.not.have.any.keys('auid');
556
300
  });
557
301
 
558
- it('should send out custom params on bids that have customParams specified', function () {
559
- const bidRequest = Object.assign({},
560
- bidRequestsWithMediaTypes[0],
561
- {
562
- params: {
563
- 'unit': '12345678',
564
- 'delDomain': 'test-del-domain',
565
- 'customParams': {'Test1': 'testval1+', 'test2': ['testval2/', 'testval3']}
566
- }
302
+ context('common requests checks', function() {
303
+ it('should be able to handle multiformat requests', () => {
304
+ const multiformat = utils.deepClone(bidRequestsWithMediaTypes[0]);
305
+ multiformat.mediaTypes.video = {
306
+ context: 'outstream',
307
+ playerSize: [640, 480]
567
308
  }
568
- );
309
+ const requests = spec.buildRequests([multiformat], mockBidderRequest);
310
+ const outgoingFormats = requests.flatMap(rq => rq.data.imp.flatMap(imp => ['banner', 'video'].filter(k => imp[k] != null)));
311
+ const expected = FEATURES.VIDEO ? ['banner', 'video'] : ['banner']
312
+ expect(outgoingFormats).to.have.members(expected);
313
+ })
569
314
 
570
- const request = spec.buildRequests([bidRequest], mockBidderRequest);
571
- const dataParams = request[0].data;
315
+ it('should send bid request to openx url via POST', function () {
316
+ const request = spec.buildRequests(bidRequestsWithMediaTypes, mockBidderRequest);
317
+ expect(request[0].url).to.equal(REQUEST_URL);
318
+ expect(request[0].method).to.equal('POST');
319
+ });
572
320
 
573
- expect(dataParams.tps).to.exist;
574
- expect(dataParams.tps).to.equal(btoa('test1=testval1.&test2=testval2_,testval3'));
575
- });
321
+ it('should send delivery domain, if available', function () {
322
+ const request = spec.buildRequests(bidRequestsWithMediaTypes, mockBidderRequest);
323
+ expect(request[0].data.ext.delDomain).to.equal(bidRequestsWithMediaTypes[0].params.delDomain);
324
+ expect(request[0].data.ext.platformId).to.be.undefined;
325
+ });
576
326
 
577
- it('should send out custom bc parameter, if override is present', function () {
578
- const bidRequest = Object.assign({},
579
- bidRequestsWithMediaTypes[0],
580
- {
581
- params: {
582
- 'unit': '12345678',
583
- 'delDomain': 'test-del-domain',
584
- 'bc': 'hb_override'
585
- }
586
- }
587
- );
327
+ it('should send platform id, if available', function () {
328
+ bidRequestsWithMediaTypes[0].params.platform = '1cabba9e-cafe-3665-beef-f00f00f00f00';
329
+ bidRequestsWithMediaTypes[1].params.platform = '1cabba9e-cafe-3665-beef-f00f00f00f00';
588
330
 
589
- const request = spec.buildRequests([bidRequest], mockBidderRequest);
590
- const dataParams = request[0].data;
331
+ const request = spec.buildRequests(bidRequestsWithMediaTypes, mockBidderRequest);
332
+ expect(request[0].data.ext.platform).to.equal(bidRequestsWithMediaTypes[0].params.platform);
333
+ expect(request[1].data.ext.platform).to.equal(bidRequestsWithMediaTypes[0].params.platform);
334
+ });
591
335
 
592
- expect(dataParams.bc).to.exist;
593
- expect(dataParams.bc).to.equal('hb_override');
594
- });
336
+ it('should send openx adunit codes', function () {
337
+ const request = spec.buildRequests(bidRequestsWithMediaTypes, mockBidderRequest);
338
+ expect(request[0].data.imp[0].tagid).to.equal(bidRequestsWithMediaTypes[0].params.unit);
339
+ expect(request[1].data.imp[0].tagid).to.equal(bidRequestsWithMediaTypes[1].params.unit);
340
+ });
595
341
 
596
- it('should not send any consent management properties', function () {
597
- const request = spec.buildRequests(bidRequestsWithMediaTypes, mockBidderRequest);
598
- expect(request[0].data.gdpr).to.equal(undefined);
599
- expect(request[0].data.gdpr_consent).to.equal(undefined);
600
- expect(request[0].data.x_gdpr_f).to.equal(undefined);
601
- });
342
+ it('should send out custom params on bids that have customParams specified', function () {
343
+ const bidRequest = Object.assign({},
344
+ bidRequestsWithMediaTypes[0],
345
+ {
346
+ params: {
347
+ unit: '12345678',
348
+ delDomain: 'test-del-domain',
349
+ customParams: {'Test1': 'testval1+', 'test2': ['testval2/', 'testval3']}
350
+ }
351
+ }
352
+ );
602
353
 
603
- describe('when there is a consent management framework', function () {
604
- let bidRequests;
605
- let mockConfig;
606
- let bidderRequest;
607
- const IAB_CONSENT_FRAMEWORK_CODE = 1;
354
+ mockBidderRequest.bids = [bidRequest];
355
+ const request = spec.buildRequests([bidRequest], mockBidderRequest);
356
+ expect(request[0].data.imp[0].ext.customParams).to.equal(bidRequest.params.customParams);
357
+ })
608
358
 
609
- beforeEach(function () {
610
- bidRequests = [{
611
- bidder: 'openx',
612
- params: {
613
- unit: '12345678-banner',
614
- delDomain: 'test-del-domain'
615
- },
616
- adUnitCode: 'adunit-code',
617
- mediaTypes: {
618
- banner: {
619
- sizes: [[300, 250], [300, 600]]
620
- }
621
- },
622
- bidId: 'test-bid-id',
623
- bidderRequestId: 'test-bidder-request-id',
624
- auctionId: 'test-auction-id'
625
- }, {
626
- 'bidder': 'openx',
627
- 'mediaTypes': {
628
- video: {
629
- playerSize: [640, 480]
359
+ describe('floors', function () {
360
+ it('should send out custom floors on bids that have customFloors, no currency as account currency is used', function () {
361
+ const bidRequest = Object.assign({},
362
+ bidRequestsWithMediaTypes[0],
363
+ {
364
+ params: {
365
+ unit: '12345678',
366
+ delDomain: 'test-del-domain',
367
+ customFloor: 1.500
368
+ }
630
369
  }
631
- },
632
- 'params': {
633
- 'unit': '12345678-video',
634
- 'delDomain': 'test-del-domain'
635
- },
636
- 'adUnitCode': 'adunit-code',
370
+ );
637
371
 
638
- bidId: 'test-bid-id',
639
- bidderRequestId: 'test-bidder-request-id',
640
- auctionId: 'test-auction-id',
641
- transactionId: '4008d88a-8137-410b-aa35-fbfdabcb478e'
642
- }];
643
- });
372
+ const request = spec.buildRequests([bidRequest], mockBidderRequest);
373
+ expect(request[0].data.imp[0].bidfloor).to.equal(bidRequest.params.customFloor);
374
+ expect(request[0].data.imp[0].bidfloorcur).to.equal(undefined);
375
+ });
644
376
 
645
- afterEach(function () {
646
- config.getConfig.restore();
647
- });
377
+ context('with floors module', function () {
378
+ let adServerCurrencyStub;
648
379
 
649
- describe('when us_privacy applies', function () {
650
- beforeEach(function () {
651
- bidderRequest = {
652
- uspConsent: '1YYN',
653
- refererInfo: {}
654
- };
380
+ beforeEach(function () {
381
+ adServerCurrencyStub = sinon
382
+ .stub(config, 'getConfig')
383
+ .withArgs('currency.adServerCurrency')
384
+ });
655
385
 
656
- sinon.stub(config, 'getConfig').callsFake((key) => {
657
- return utils.deepAccess(mockConfig, key);
386
+ afterEach(function () {
387
+ config.getConfig.restore();
658
388
  });
659
- });
660
389
 
661
- it('should send a signal to specify that GDPR applies to this request', function () {
662
- const request = spec.buildRequests(bidRequests, bidderRequest);
663
- expect(request[0].data.us_privacy).to.equal('1YYN');
664
- expect(request[1].data.us_privacy).to.equal('1YYN');
665
- });
666
- });
390
+ it('should send out floors on bids in USD', function () {
391
+ const bidRequest = Object.assign({},
392
+ bidRequestsWithMediaTypes[0],
393
+ {
394
+ getFloor: () => {
395
+ return {
396
+ currency: 'USD',
397
+ floor: 9.99
398
+ }
399
+ }
400
+ }
401
+ );
667
402
 
668
- describe('when us_privacy does not applies', function () {
669
- beforeEach(function () {
670
- bidderRequest = {
671
- refererInfo: {}
672
- };
403
+ const request = spec.buildRequests([bidRequest], mockBidderRequest);
404
+ expect(request[0].data.imp[0].bidfloor).to.equal(9.99);
405
+ expect(request[0].data.imp[0].bidfloorcur).to.equal('USD');
406
+ });
673
407
 
674
- sinon.stub(config, 'getConfig').callsFake((key) => {
675
- return utils.deepAccess(mockConfig, key);
408
+ it('should send not send floors', function () {
409
+ adServerCurrencyStub.returns('EUR');
410
+ const bidRequest = Object.assign({},
411
+ bidRequestsWithMediaTypes[0],
412
+ {
413
+ getFloor: () => {
414
+ return {
415
+ currency: 'BTC',
416
+ floor: 9.99
417
+ }
418
+ }
419
+ }
420
+ );
421
+
422
+ const request = spec.buildRequests([bidRequest], mockBidderRequest);
423
+ expect(request[0].data.imp[0].bidfloor).to.equal(undefined)
424
+ expect(request[0].data.imp[0].bidfloorcur).to.equal(undefined)
676
425
  });
677
- });
426
+ })
427
+ })
678
428
 
679
- it('should not send the consent string, when consent string is undefined', function () {
680
- delete bidderRequest.uspConsent;
681
- const request = spec.buildRequests(bidRequests, bidderRequest);
682
- expect(request[0].data).to.not.have.property('us_privacy');
683
- expect(request[1].data).to.not.have.property('us_privacy');
684
- });
685
- });
429
+ describe('FPD', function() {
430
+ let bidRequests;
431
+ const mockBidderRequest = {refererInfo: {}};
686
432
 
687
- describe('when GDPR applies', function () {
688
433
  beforeEach(function () {
689
- bidderRequest = {
690
- gdprConsent: {
691
- consentString: 'test-gdpr-consent-string',
692
- gdprApplies: true
434
+ bidRequests = [{
435
+ bidder: 'openx',
436
+ params: {
437
+ unit: '12345678-banner',
438
+ delDomain: 'test-del-domain'
693
439
  },
694
- refererInfo: {}
695
- };
440
+ adUnitCode: 'adunit-code',
441
+ mediaTypes: {
442
+ banner: {
443
+ sizes: [[300, 250], [300, 600]]
444
+ }
445
+ },
446
+ bidId: 'test-bid-id',
447
+ bidderRequestId: 'test-bidder-request-id',
448
+ auctionId: 'test-auction-id',
449
+ transactionId: 'test-transaction-id-1'
450
+ }, {
451
+ bidder: 'openx',
452
+ mediaTypes: {
453
+ video: {
454
+ playerSize: [640, 480]
455
+ }
456
+ },
457
+ params: {
458
+ unit: '12345678-video',
459
+ delDomain: 'test-del-domain'
460
+ },
461
+ 'adUnitCode': 'adunit-code',
696
462
 
697
- mockConfig = {
698
- consentManagement: {
699
- cmpApi: 'iab',
700
- timeout: 1111,
701
- allowAuctionWithoutConsent: 'cancel'
702
- }
703
- };
463
+ bidId: 'test-bid-id',
464
+ bidderRequestId: 'test-bidder-request-id',
465
+ auctionId: 'test-auction-id',
466
+ transactionId: 'test-transaction-id-2'
467
+ }];
468
+ });
704
469
 
705
- sinon.stub(config, 'getConfig').callsFake((key) => {
706
- return utils.deepAccess(mockConfig, key);
470
+ it('ortb2.site should be merged in the request', function() {
471
+ const request = spec.buildRequests(bidRequests, {
472
+ ...mockBidderRequest,
473
+ 'ortb2': {
474
+ site: {
475
+ domain: 'page.example.com',
476
+ cat: ['IAB2'],
477
+ sectioncat: ['IAB2-2']
478
+ }
479
+ }
707
480
  });
481
+ let data = request[0].data;
482
+ expect(data.site.domain).to.equal('page.example.com');
483
+ expect(data.site.cat).to.deep.equal(['IAB2']);
484
+ expect(data.site.sectioncat).to.deep.equal(['IAB2-2']);
708
485
  });
709
486
 
710
- it('should send a signal to specify that GDPR applies to this request', function () {
711
- const request = spec.buildRequests(bidRequests, bidderRequest);
712
- expect(request[0].data.gdpr).to.equal(1);
713
- expect(request[1].data.gdpr).to.equal(1);
487
+ it('ortb2.user should be merged in the request', function() {
488
+ const request = spec.buildRequests(bidRequests, {
489
+ ...mockBidderRequest,
490
+ 'ortb2': {
491
+ user: {
492
+ yob: 1985
493
+ }
494
+ }
495
+ });
496
+ let data = request[0].data;
497
+ expect(data.user.yob).to.equal(1985);
714
498
  });
715
499
 
716
- it('should send the consent string', function () {
717
- const request = spec.buildRequests(bidRequests, bidderRequest);
718
- expect(request[0].data.gdpr_consent).to.equal(bidderRequest.gdprConsent.consentString);
719
- expect(request[1].data.gdpr_consent).to.equal(bidderRequest.gdprConsent.consentString);
720
- });
500
+ describe('ortb2Imp', function() {
501
+ describe('ortb2Imp.ext.data.pbadslot', function() {
502
+ beforeEach(function () {
503
+ if (bidRequests[0].hasOwnProperty('ortb2Imp')) {
504
+ delete bidRequests[0].ortb2Imp;
505
+ }
506
+ });
721
507
 
722
- it('should send the consent management framework code', function () {
723
- const request = spec.buildRequests(bidRequests, bidderRequest);
724
- expect(request[0].data.x_gdpr_f).to.equal(IAB_CONSENT_FRAMEWORK_CODE);
725
- expect(request[1].data.x_gdpr_f).to.equal(IAB_CONSENT_FRAMEWORK_CODE);
726
- });
727
- });
508
+ it('should not send if imp[].ext.data object is invalid', function() {
509
+ bidRequests[0].ortb2Imp = {
510
+ ext: {}
511
+ };
512
+ const request = spec.buildRequests(bidRequests, mockBidderRequest);
513
+ let data = request[0].data;
514
+ expect(data.imp[0].ext).to.not.have.property('data');
515
+ });
728
516
 
729
- describe('when GDPR does not apply', function () {
730
- beforeEach(function () {
731
- bidderRequest = {
732
- gdprConsent: {
733
- consentString: 'test-gdpr-consent-string',
734
- gdprApplies: false
735
- },
736
- refererInfo: {}
737
- };
738
-
739
- mockConfig = {
740
- consentManagement: {
741
- cmpApi: 'iab',
742
- timeout: 1111,
743
- allowAuctionWithoutConsent: 'cancel'
744
- }
745
- };
517
+ it('should not send if imp[].ext.data.pbadslot is undefined', function() {
518
+ bidRequests[0].ortb2Imp = {
519
+ ext: {
520
+ data: {
521
+ }
522
+ }
523
+ };
524
+ const request = spec.buildRequests(bidRequests, mockBidderRequest);
525
+ let data = request[0].data;
526
+ if (data.imp[0].ext.data) {
527
+ expect(data.imp[0].ext.data).to.not.have.property('pbadslot');
528
+ } else {
529
+ expect(data.imp[0].ext).to.not.have.property('data');
530
+ }
531
+ });
746
532
 
747
- sinon.stub(config, 'getConfig').callsFake((key) => {
748
- return utils.deepAccess(mockConfig, key);
533
+ it('should send if imp[].ext.data.pbadslot is string', function() {
534
+ bidRequests[0].ortb2Imp = {
535
+ ext: {
536
+ data: {
537
+ pbadslot: 'abcd'
538
+ }
539
+ }
540
+ };
541
+ const request = spec.buildRequests(bidRequests, mockBidderRequest);
542
+ let data = request[0].data;
543
+ expect(data.imp[0].ext.data).to.have.property('pbadslot');
544
+ expect(data.imp[0].ext.data.pbadslot).to.equal('abcd');
545
+ });
749
546
  });
750
- });
751
547
 
752
- it('should not send a signal to specify that GDPR does not apply to this request', function () {
753
- const request = spec.buildRequests(bidRequests, bidderRequest);
754
- expect(request[0].data.gdpr).to.equal(0);
755
- expect(request[1].data.gdpr).to.equal(0);
756
- });
548
+ describe('ortb2Imp.ext.data.adserver', function() {
549
+ beforeEach(function () {
550
+ if (bidRequests[0].hasOwnProperty('ortb2Imp')) {
551
+ delete bidRequests[0].ortb2Imp;
552
+ }
553
+ });
757
554
 
758
- it('should send the consent string', function () {
759
- const request = spec.buildRequests(bidRequests, bidderRequest);
760
- expect(request[0].data.gdpr_consent).to.equal(bidderRequest.gdprConsent.consentString);
761
- expect(request[1].data.gdpr_consent).to.equal(bidderRequest.gdprConsent.consentString);
762
- });
555
+ it('should not send if imp[].ext.data object is invalid', function() {
556
+ bidRequests[0].ortb2Imp = {
557
+ ext: {}
558
+ };
559
+ const request = spec.buildRequests(bidRequests, mockBidderRequest);
560
+ let data = request[0].data;
561
+ expect(data.imp[0].ext).to.not.have.property('data');
562
+ });
763
563
 
764
- it('should send the consent management framework code', function () {
765
- const request = spec.buildRequests(bidRequests, bidderRequest);
766
- expect(request[0].data.x_gdpr_f).to.equal(IAB_CONSENT_FRAMEWORK_CODE);
767
- expect(request[1].data.x_gdpr_f).to.equal(IAB_CONSENT_FRAMEWORK_CODE);
768
- });
769
- });
564
+ it('should not send if imp[].ext.data.adserver is undefined', function() {
565
+ bidRequests[0].ortb2Imp = {
566
+ ext: {
567
+ data: {
568
+ }
569
+ }
570
+ };
571
+ const request = spec.buildRequests(bidRequests, mockBidderRequest);
572
+ let data = request[0].data;
573
+ if (data.imp[0].ext.data) {
574
+ expect(data.imp[0].ext.data).to.not.have.property('adserver');
575
+ } else {
576
+ expect(data.imp[0].ext).to.not.have.property('data');
577
+ }
578
+ });
770
579
 
771
- describe('when GDPR consent has undefined data', function () {
772
- beforeEach(function () {
773
- bidderRequest = {
774
- gdprConsent: {
775
- consentString: 'test-gdpr-consent-string',
776
- gdprApplies: true
777
- },
778
- refererInfo: {}
779
- };
580
+ it('should send', function() {
581
+ let adSlotValue = 'abc';
582
+ bidRequests[0].ortb2Imp = {
583
+ ext: {
584
+ data: {
585
+ adserver: {
586
+ name: 'GAM',
587
+ adslot: adSlotValue
588
+ }
589
+ }
590
+ }
591
+ };
592
+ const request = spec.buildRequests(bidRequests, mockBidderRequest);
593
+ let data = request[0].data;
594
+ expect(data.imp[0].ext.data.adserver.name).to.equal('GAM');
595
+ expect(data.imp[0].ext.data.adserver.adslot).to.equal(adSlotValue);
596
+ });
597
+ });
780
598
 
781
- mockConfig = {
782
- consentManagement: {
783
- cmpApi: 'iab',
784
- timeout: 1111,
785
- allowAuctionWithoutConsent: 'cancel'
786
- }
787
- };
599
+ describe('ortb2Imp.ext.data.other', function() {
600
+ beforeEach(function () {
601
+ if (bidRequests[0].hasOwnProperty('ortb2Imp')) {
602
+ delete bidRequests[0].ortb2Imp;
603
+ }
604
+ });
788
605
 
789
- sinon.stub(config, 'getConfig').callsFake((key) => {
790
- return utils.deepAccess(mockConfig, key);
791
- });
792
- });
606
+ it('should not send if imp[].ext.data object is invalid', function() {
607
+ bidRequests[0].ortb2Imp = {
608
+ ext: {}
609
+ };
610
+ const request = spec.buildRequests(bidRequests, mockBidderRequest);
611
+ let data = request[0].data;
612
+ expect(data.imp[0].ext).to.not.have.property('data');
613
+ });
793
614
 
794
- it('should not send a signal to specify whether GDPR applies to this request, when GDPR application is undefined', function () {
795
- delete bidderRequest.gdprConsent.gdprApplies;
796
- const request = spec.buildRequests(bidRequests, bidderRequest);
797
- expect(request[0].data).to.not.have.property('gdpr');
798
- expect(request[1].data).to.not.have.property('gdpr');
799
- });
615
+ it('should not send if imp[].ext.data.other is undefined', function() {
616
+ bidRequests[0].ortb2Imp = {
617
+ ext: {
618
+ data: {
619
+ }
620
+ }
621
+ };
622
+ const request = spec.buildRequests(bidRequests, mockBidderRequest);
623
+ let data = request[0].data;
624
+ if (data.imp[0].ext.data) {
625
+ expect(data.imp[0].ext.data).to.not.have.property('other');
626
+ } else {
627
+ expect(data.imp[0].ext).to.not.have.property('data');
628
+ }
629
+ });
800
630
 
801
- it('should not send the consent string, when consent string is undefined', function () {
802
- delete bidderRequest.gdprConsent.consentString;
803
- const request = spec.buildRequests(bidRequests, bidderRequest);
804
- expect(request[0].data).to.not.have.property('gdpr_consent');
805
- expect(request[1].data).to.not.have.property('gdpr_consent');
631
+ it('ortb2Imp.ext.data.other', function() {
632
+ bidRequests[0].ortb2Imp = {
633
+ ext: {
634
+ data: {
635
+ other: 1234
636
+ }
637
+ }
638
+ };
639
+ const request = spec.buildRequests(bidRequests, mockBidderRequest);
640
+ let data = request[0].data;
641
+ expect(data.imp[0].ext.data.other).to.equal(1234);
642
+ });
643
+ });
806
644
  });
807
645
 
808
- it('should not send the consent management framework code, when format is undefined', function () {
809
- delete mockConfig.consentManagement.cmpApi;
810
- const request = spec.buildRequests(bidRequests, bidderRequest);
811
- expect(request[0].data).to.not.have.property('x_gdpr_f');
812
- expect(request[1].data).to.not.have.property('x_gdpr_f');
646
+ describe('with user agent client hints', function () {
647
+ it('should add device.sua if available', function () {
648
+ const bidderRequestWithUserAgentClientHints = { refererInfo: {},
649
+ ortb2: {
650
+ device: {
651
+ sua: {
652
+ source: 2,
653
+ platform: {
654
+ brand: 'macOS',
655
+ version: [ '12', '4', '0' ]
656
+ },
657
+ browsers: [
658
+ {
659
+ brand: 'Chromium',
660
+ version: [ '106', '0', '5249', '119' ]
661
+ },
662
+ {
663
+ brand: 'Google Chrome',
664
+ version: [ '106', '0', '5249', '119' ]
665
+ },
666
+ {
667
+ brand: 'Not;A=Brand',
668
+ version: [ '99', '0', '0', '0' ]
669
+ }],
670
+ mobile: 0,
671
+ model: 'Pro',
672
+ bitness: '64',
673
+ architecture: 'x86'
674
+ }
675
+ }
676
+ }};
677
+
678
+ let request = spec.buildRequests(bidRequests, bidderRequestWithUserAgentClientHints);
679
+ expect(request[0].data.device.sua).to.exist;
680
+ expect(request[0].data.device.sua).to.deep.equal(bidderRequestWithUserAgentClientHints.ortb2.device.sua);
681
+ const bidderRequestWithoutUserAgentClientHints = {refererInfo: {}, ortb2: {}};
682
+ request = spec.buildRequests(bidRequests, bidderRequestWithoutUserAgentClientHints);
683
+ expect(request[0].data.device?.sua).to.not.exist;
684
+ });
813
685
  });
814
686
  });
815
- });
816
-
817
- it('should not send a coppa query param when there are no coppa param settings in the bid requests', function () {
818
- const bidRequestsWithoutCoppa = [{
819
- bidder: 'openx',
820
- params: {
821
- unit: '11',
822
- delDomain: 'test-del-domain',
823
- coppa: false
824
- },
825
- adUnitCode: 'adunit-code',
826
- mediaTypes: {
827
- banner: {
828
- sizes: [[300, 250], [300, 600]]
829
- }
830
- },
831
- bidId: 'test-bid-id-1',
832
- bidderRequestId: 'test-bid-request-1',
833
- auctionId: 'test-auction-1'
834
- }, {
835
- bidder: 'openx',
836
- params: {
837
- unit: '22',
838
- delDomain: 'test-del-domain'
839
- },
840
- adUnitCode: 'adunit-code',
841
- mediaTypes: {
842
- banner: {
843
- sizes: [[728, 90]]
844
- }
845
- },
846
- bidId: 'test-bid-id-2',
847
- bidderRequestId: 'test-bid-request-2',
848
- auctionId: 'test-auction-2'
849
- }];
850
- const request = spec.buildRequests(bidRequestsWithoutCoppa, mockBidderRequest);
851
- expect(request[0].data).to.not.have.any.keys('tfcd');
852
- });
853
-
854
- it('should send a coppa flag there is when there is coppa param settings in the bid requests', function () {
855
- const bidRequestsWithCoppa = [{
856
- bidder: 'openx',
857
- params: {
858
- unit: '11',
859
- delDomain: 'test-del-domain',
860
- coppa: false
861
- },
862
- adUnitCode: 'adunit-code',
863
- mediaTypes: {
864
- banner: {
865
- sizes: [[300, 250], [300, 600]]
866
- }
867
- },
868
- bidId: 'test-bid-id-1',
869
- bidderRequestId: 'test-bid-request-1',
870
- auctionId: 'test-auction-1'
871
- }, {
872
- bidder: 'openx',
873
- params: {
874
- unit: '22',
875
- delDomain: 'test-del-domain',
876
- coppa: true
877
- },
878
- adUnitCode: 'adunit-code',
879
- mediaTypes: {
880
- banner: {
881
- sizes: [[728, 90]]
882
- }
883
- },
884
- bidId: 'test-bid-id-2',
885
- bidderRequestId: 'test-bid-request-2',
886
- auctionId: 'test-auction-2'
887
- }];
888
- const request = spec.buildRequests(bidRequestsWithCoppa, mockBidderRequest);
889
- expect(request[0].data.tfcd).to.equal(1);
890
- });
891
687
 
892
- it('should not send a "no segmentation" flag there no DoNotTrack setting that is set to true', function () {
893
- const bidRequestsWithoutDnt = [{
894
- bidder: 'openx',
895
- params: {
896
- unit: '11',
897
- delDomain: 'test-del-domain',
898
- doNotTrack: false
899
- },
900
- adUnitCode: 'adunit-code',
901
- mediaTypes: {
902
- banner: {
903
- sizes: [[300, 250], [300, 600]]
904
- }
905
- },
906
- bidId: 'test-bid-id-1',
907
- bidderRequestId: 'test-bid-request-1',
908
- auctionId: 'test-auction-1'
909
- }, {
910
- bidder: 'openx',
911
- params: {
912
- unit: '22',
913
- delDomain: 'test-del-domain'
914
- },
915
- adUnitCode: 'adunit-code',
916
- mediaTypes: {
917
- banner: {
918
- sizes: [[728, 90]]
919
- }
920
- },
921
- bidId: 'test-bid-id-2',
922
- bidderRequestId: 'test-bid-request-2',
923
- auctionId: 'test-auction-2'
924
- }];
925
- const request = spec.buildRequests(bidRequestsWithoutDnt, mockBidderRequest);
926
- expect(request[0].data).to.not.have.any.keys('ns');
927
- });
688
+ context('when there is a consent management framework', function () {
689
+ let bidRequests;
690
+ let mockConfig;
691
+ let bidderRequest;
928
692
 
929
- it('should send a "no segmentation" flag there is any DoNotTrack setting that is set to true', function () {
930
- const bidRequestsWithDnt = [{
931
- bidder: 'openx',
932
- params: {
933
- unit: '11',
934
- delDomain: 'test-del-domain',
935
- doNotTrack: false
936
- },
937
- adUnitCode: 'adunit-code',
938
- mediaTypes: {
939
- banner: {
940
- sizes: [[300, 250], [300, 600]]
941
- }
942
- },
943
- bidId: 'test-bid-id-1',
944
- bidderRequestId: 'test-bid-request-1',
945
- auctionId: 'test-auction-1'
946
- }, {
947
- bidder: 'openx',
948
- params: {
949
- unit: '22',
950
- delDomain: 'test-del-domain',
951
- doNotTrack: true
952
- },
953
- adUnitCode: 'adunit-code',
954
- mediaTypes: {
955
- banner: {
956
- sizes: [[728, 90]]
957
- }
958
- },
959
- bidId: 'test-bid-id-2',
960
- bidderRequestId: 'test-bid-request-2',
961
- auctionId: 'test-auction-2'
962
- }];
963
- const request = spec.buildRequests(bidRequestsWithDnt, mockBidderRequest);
964
- expect(request[0].data.ns).to.equal(1);
965
- });
966
-
967
- describe('when schain is provided', function () {
968
- let bidRequests;
969
- let schainConfig;
970
- const supplyChainNodePropertyOrder = ['asi', 'sid', 'hp', 'rid', 'name', 'domain'];
971
-
972
- beforeEach(function () {
973
- schainConfig = {
974
- 'ver': '1.0',
975
- 'complete': 1,
976
- 'nodes': [
977
- {
978
- 'asi': 'exchange1.com',
979
- 'sid': '1234',
980
- 'hp': 1,
981
- 'rid': 'bid-request-1',
982
- 'name': 'publisher',
983
- 'domain': 'publisher.com'
984
- // omitted ext
693
+ beforeEach(function () {
694
+ bidRequests = [{
695
+ bidder: 'openx',
696
+ params: {
697
+ unit: '12345678-banner',
698
+ delDomain: 'test-del-domain'
985
699
  },
986
- {
987
- 'asi': 'exchange2.com',
988
- 'sid': 'abcd',
989
- 'hp': 1,
990
- 'rid': 'bid-request-2',
991
- // name field missing
992
- 'domain': 'intermediary.com'
700
+ adUnitCode: 'adunit-code',
701
+ mediaTypes: {
702
+ banner: {
703
+ sizes: [[300, 250], [300, 600]]
704
+ }
993
705
  },
994
- {
995
- 'asi': 'exchange3.com',
996
- 'sid': '4321',
997
- 'hp': 1,
998
- // request id
999
- // name field missing
1000
- 'domain': 'intermediary-2.com'
1001
- }
1002
- ]
1003
- };
706
+ bidId: 'test-bid-id',
707
+ bidderRequestId: 'test-bidder-request-id',
708
+ auctionId: 'test-auction-id',
709
+ transactionId: 'test-transaction-id-1'
710
+ }, {
711
+ bidder: 'openx',
712
+ mediaTypes: {
713
+ video: {
714
+ playerSize: [640, 480]
715
+ }
716
+ },
717
+ params: {
718
+ unit: '12345678-video',
719
+ delDomain: 'test-del-domain'
720
+ },
721
+ 'adUnitCode': 'adunit-code',
1004
722
 
1005
- bidRequests = [{
1006
- 'bidder': 'openx',
1007
- 'params': {
1008
- 'unit': '11',
1009
- 'delDomain': 'test-del-domain'
1010
- },
1011
- 'adUnitCode': '/adunit-code/test-path',
1012
- mediaTypes: {
1013
- banner: {
1014
- sizes: [[300, 250], [300, 600]]
1015
- }
1016
- },
1017
- 'bidId': 'test-bid-id-1',
1018
- 'bidderRequestId': 'test-bid-request-1',
1019
- 'auctionId': 'test-auction-1',
1020
- 'schain': schainConfig
1021
- }];
1022
- });
723
+ bidId: 'test-bid-id',
724
+ bidderRequestId: 'test-bidder-request-id',
725
+ auctionId: 'test-auction-id',
726
+ transactionId: 'test-transaction-id-2'
727
+ }];
728
+ });
1023
729
 
1024
- it('should send a schain parameter with the proper delimiter symbols', function () {
1025
- const request = spec.buildRequests(bidRequests, mockBidderRequest);
1026
- const dataParams = request[0].data;
1027
- const numNodes = schainConfig.nodes.length;
730
+ describe('us_privacy', function () {
731
+ beforeEach(function () {
732
+ bidderRequest = {
733
+ uspConsent: '1YYN',
734
+ refererInfo: {}
735
+ };
1028
736
 
1029
- // each node will have a ! to denote beginning of a new node
1030
- expect(dataParams.schain.match(/!/g).length).to.equal(numNodes);
737
+ sinon.stub(config, 'getConfig').callsFake((key) => {
738
+ return utils.deepAccess(mockConfig, key);
739
+ });
740
+ });
1031
741
 
1032
- // 1 comma in the front for version
1033
- // 5 commas per node
1034
- expect(dataParams.schain.match(/,/g).length).to.equal(numNodes * 5 + 1);
1035
- });
742
+ afterEach(function () {
743
+ config.getConfig.restore();
744
+ });
1036
745
 
1037
- it('should send a schain with the right version', function () {
1038
- const request = spec.buildRequests(bidRequests, mockBidderRequest);
1039
- const dataParams = request[0].data;
1040
- let serializedSupplyChain = dataParams.schain.split('!');
1041
- let version = serializedSupplyChain.shift().split(',')[0];
746
+ it('should send a signal to specify that US Privacy applies to this request', function () {
747
+ const request = spec.buildRequests(bidRequests, syncAddFPDToBidderRequest(bidderRequest));
748
+ expect(request[0].data.regs.ext.us_privacy).to.equal('1YYN');
749
+ expect(request[1].data.regs.ext.us_privacy).to.equal('1YYN');
750
+ });
1042
751
 
1043
- expect(version).to.equal(bidRequests[0].schain.ver);
1044
- });
752
+ it('should not send the regs object, when consent string is undefined', function () {
753
+ delete bidderRequest.uspConsent;
754
+ const request = spec.buildRequests(bidRequests, syncAddFPDToBidderRequest(bidderRequest));
755
+ expect(request[0].data.regs?.us_privacy).to.not.exist;
756
+ });
757
+ });
1045
758
 
1046
- it('should send a schain with the right complete value', function () {
1047
- const request = spec.buildRequests(bidRequests, mockBidderRequest);
1048
- const dataParams = request[0].data;
1049
- let serializedSupplyChain = dataParams.schain.split('!');
1050
- let isComplete = serializedSupplyChain.shift().split(',')[1];
759
+ describe('GDPR', function () {
760
+ beforeEach(function () {
761
+ bidderRequest = {
762
+ gdprConsent: {
763
+ consentString: 'test-gdpr-consent-string',
764
+ addtlConsent: 'test-addtl-consent-string',
765
+ gdprApplies: true
766
+ },
767
+ refererInfo: {}
768
+ };
769
+
770
+ mockConfig = {
771
+ consentManagement: {
772
+ cmpApi: 'iab',
773
+ timeout: 1111,
774
+ allowAuctionWithoutConsent: 'cancel'
775
+ }
776
+ };
1051
777
 
1052
- expect(isComplete).to.equal(String(bidRequests[0].schain.complete));
1053
- });
778
+ sinon.stub(config, 'getConfig').callsFake((key) => {
779
+ return utils.deepAccess(mockConfig, key);
780
+ });
781
+ });
1054
782
 
1055
- it('should send all available params in the right order', function () {
1056
- const request = spec.buildRequests(bidRequests, mockBidderRequest);
1057
- const dataParams = request[0].data;
1058
- let serializedSupplyChain = dataParams.schain.split('!');
1059
- serializedSupplyChain.shift();
783
+ afterEach(function () {
784
+ config.getConfig.restore();
785
+ });
1060
786
 
1061
- serializedSupplyChain.forEach((serializedNode, nodeIndex) => {
1062
- let nodeProperties = serializedNode.split(',');
787
+ it('should send a signal to specify that GDPR applies to this request', function () {
788
+ bidderRequest.bids = bidRequests;
789
+ const request = spec.buildRequests(bidRequests, syncAddFPDToBidderRequest(bidderRequest));
790
+ expect(request[0].data.regs.ext.gdpr).to.equal(1);
791
+ expect(request[1].data.regs.ext.gdpr).to.equal(1);
792
+ });
1063
793
 
1064
- nodeProperties.forEach((nodeProperty, propertyIndex) => {
1065
- let node = schainConfig.nodes[nodeIndex];
1066
- let key = supplyChainNodePropertyOrder[propertyIndex];
794
+ it('should send the consent string', function () {
795
+ bidderRequest.bids = bidRequests;
796
+ const request = spec.buildRequests(bidRequests, syncAddFPDToBidderRequest(bidderRequest));
797
+ expect(request[0].data.user.ext.consent).to.equal(bidderRequest.gdprConsent.consentString);
798
+ expect(request[1].data.user.ext.consent).to.equal(bidderRequest.gdprConsent.consentString);
799
+ });
1067
800
 
1068
- expect(nodeProperty).to.equal(node[key] ? String(node[key]) : '',
1069
- `expected node '${nodeIndex}' property '${nodeProperty}' to key '${key}' to be the same value`)
801
+ it('should send the addtlConsent string', function () {
802
+ bidderRequest.bids = bidRequests;
803
+ const request = spec.buildRequests(bidRequests, syncAddFPDToBidderRequest(bidderRequest));
804
+ expect(request[0].data.user.ext.ConsentedProvidersSettings.consented_providers).to.equal(bidderRequest.gdprConsent.addtlConsent);
805
+ expect(request[1].data.user.ext.ConsentedProvidersSettings.consented_providers).to.equal(bidderRequest.gdprConsent.addtlConsent);
1070
806
  });
1071
- });
1072
- });
1073
- });
1074
807
 
1075
- describe('when there are userid providers', function () {
1076
- const EXAMPLE_DATA_BY_ATTR = {
1077
- britepoolid: '1111-britepoolid',
1078
- criteoId: '1111-criteoId',
1079
- fabrickId: '1111-fabrickid',
1080
- haloId: '1111-haloid',
1081
- id5id: {uid: '1111-id5id'},
1082
- idl_env: '1111-idl_env',
1083
- IDP: '1111-zeotap-idplusid',
1084
- idxId: '1111-idxid',
1085
- intentIqId: '1111-intentiqid',
1086
- lipb: {lipbid: '1111-lipb'},
1087
- lotamePanoramaId: '1111-lotameid',
1088
- merkleId: {id: '1111-merkleid'},
1089
- netId: 'fH5A3n2O8_CZZyPoJVD-eabc6ECb7jhxCicsds7qSg',
1090
- parrableId: { eid: 'eidVersion.encryptionKeyReference.encryptedValue' },
1091
- pubcid: '1111-pubcid',
1092
- quantcastId: '1111-quantcastid',
1093
- tapadId: '111-tapadid',
1094
- tdid: '1111-tdid',
1095
- uid2: {id: '1111-uid2'},
1096
- novatiq: {snowflake: '1111-novatiqid'},
1097
- admixerId: '1111-admixerid',
1098
- deepintentId: '1111-deepintentid',
1099
- dmdId: '111-dmdid',
1100
- nextrollId: '1111-nextrollid',
1101
- mwOpenLinkId: '1111-mwopenlinkid',
1102
- dapId: '1111-dapId',
1103
- amxId: '1111-amxid',
1104
- kpuid: '1111-kpuid',
1105
- publinkId: '1111-publinkid',
1106
- naveggId: '1111-naveggid',
1107
- imuid: '1111-imuid',
1108
- adtelligentId: '1111-adtelligentid'
1109
- };
1110
-
1111
- // generates the same set of tests for each id provider
1112
- utils._each(USER_ID_CODE_TO_QUERY_ARG, (userIdQueryArg, userIdProviderKey) => {
1113
- describe(`with userId attribute: ${userIdProviderKey}`, function () {
1114
- it(`should not send a ${userIdQueryArg} query param when there is no userId.${userIdProviderKey} defined in the bid requests`, function () {
1115
- const request = spec.buildRequests(bidRequestsWithMediaTypes, mockBidderRequest);
1116
- expect(request[0].data).to.not.have.any.keys(userIdQueryArg);
808
+ it('should send a signal to specify that GDPR does not apply to this request', function () {
809
+ bidderRequest.gdprConsent.gdprApplies = false;
810
+ bidderRequest.bids = bidRequests;
811
+ const request = spec.buildRequests(bidRequests, syncAddFPDToBidderRequest(bidderRequest));
812
+ expect(request[0].data.regs.ext.gdpr).to.equal(0);
813
+ expect(request[1].data.regs.ext.gdpr).to.equal(0);
1117
814
  });
1118
815
 
1119
- it(`should send a ${userIdQueryArg} query param when userId.${userIdProviderKey} is defined in the bid requests`, function () {
1120
- const bidRequestsWithUserId = [{
1121
- bidder: 'openx',
1122
- params: {
1123
- unit: '11',
1124
- delDomain: 'test-del-domain'
1125
- },
1126
- userId: {
1127
- },
1128
- adUnitCode: 'adunit-code',
1129
- mediaTypes: {
1130
- banner: {
1131
- sizes: [[300, 250], [300, 600]]
1132
- }
1133
- },
1134
- bidId: 'test-bid-id-1',
1135
- bidderRequestId: 'test-bid-request-1',
1136
- auctionId: 'test-auction-1'
1137
- }];
1138
- // enrich bid request with userId key/value
1139
- bidRequestsWithUserId[0].userId[userIdProviderKey] = EXAMPLE_DATA_BY_ATTR[userIdProviderKey];
1140
-
1141
- const request = spec.buildRequests(bidRequestsWithUserId, mockBidderRequest);
1142
-
1143
- let userIdValue;
1144
- // handle cases where userId key refers to an object
1145
- switch (userIdProviderKey) {
1146
- case 'merkleId':
1147
- userIdValue = EXAMPLE_DATA_BY_ATTR.merkleId.id;
1148
- break;
1149
- case 'uid2':
1150
- userIdValue = EXAMPLE_DATA_BY_ATTR.uid2.id;
1151
- break;
1152
- case 'lipb':
1153
- userIdValue = EXAMPLE_DATA_BY_ATTR.lipb.lipbid;
1154
- break;
1155
- case 'parrableId':
1156
- userIdValue = EXAMPLE_DATA_BY_ATTR.parrableId.eid;
1157
- break;
1158
- case 'id5id':
1159
- userIdValue = EXAMPLE_DATA_BY_ATTR.id5id.uid;
1160
- break;
1161
- case 'novatiq':
1162
- userIdValue = EXAMPLE_DATA_BY_ATTR.novatiq.snowflake;
1163
- break;
1164
- default:
1165
- userIdValue = EXAMPLE_DATA_BY_ATTR[userIdProviderKey];
1166
- }
816
+ it('when GDPR application is undefined, should not send a signal to specify whether GDPR applies to this request, ' +
817
+ 'but can send consent data, ', function () {
818
+ delete bidderRequest.gdprConsent.gdprApplies;
819
+ bidderRequest.bids = bidRequests;
820
+ const request = spec.buildRequests(bidRequests, syncAddFPDToBidderRequest(bidderRequest));
821
+ expect(request[0].data.regs?.ext?.gdpr).to.not.be.ok;
822
+ expect(request[0].data.user.ext.consent).to.equal(bidderRequest.gdprConsent.consentString);
823
+ expect(request[1].data.user.ext.consent).to.equal(bidderRequest.gdprConsent.consentString);
824
+ });
1167
825
 
1168
- expect(request[0].data[USER_ID_CODE_TO_QUERY_ARG[userIdProviderKey]]).to.equal(userIdValue);
826
+ it('when consent string is undefined, should not send the consent string, ', function () {
827
+ delete bidderRequest.gdprConsent.consentString;
828
+ bidderRequest.bids = bidRequests;
829
+ const request = spec.buildRequests(bidRequests, syncAddFPDToBidderRequest(bidderRequest));
830
+ expect(request[0].data.imp[0].ext.consent).to.equal(undefined);
831
+ expect(request[1].data.imp[0].ext.consent).to.equal(undefined);
1169
832
  });
1170
833
  });
1171
834
  });
1172
- });
1173
-
1174
- describe('floors', function () {
1175
- it('should send out custom floors on bids that have customFloors specified', function () {
1176
- const bidRequest = Object.assign({},
1177
- bidRequestsWithMediaTypes[0],
1178
- {
1179
- params: {
1180
- 'unit': '12345678',
1181
- 'delDomain': 'test-del-domain',
1182
- 'customFloor': 1.500001
1183
- }
1184
- }
1185
- );
1186
-
1187
- const request = spec.buildRequests([bidRequest], mockBidderRequest);
1188
- const dataParams = request[0].data;
1189
-
1190
- expect(dataParams.aumfs).to.exist;
1191
- expect(dataParams.aumfs).to.equal('1500');
1192
- });
1193
835
 
1194
- context('with floors module', function () {
1195
- let adServerCurrencyStub;
1196
-
1197
- beforeEach(function () {
1198
- adServerCurrencyStub = sinon
1199
- .stub(config, 'getConfig')
1200
- .withArgs('currency.adServerCurrency')
836
+ context('coppa', function() {
837
+ it('when there are no coppa param settings, should not send a coppa flag', function () {
838
+ const request = spec.buildRequests(bidRequestsWithMediaTypes, syncAddFPDToBidderRequest(mockBidderRequest));
839
+ expect(request[0].data.regs?.coppa).to.be.not.ok;
1201
840
  });
1202
841
 
1203
- afterEach(function () {
1204
- config.getConfig.restore();
1205
- });
1206
-
1207
- it('should send out floors on bids', function () {
1208
- const bidRequest1 = Object.assign({},
1209
- bidRequestsWithMediaTypes[0],
1210
- {
1211
- getFloor: () => {
1212
- return {
1213
- currency: 'AUS',
1214
- floor: 9.99
1215
- }
1216
- }
1217
- }
1218
- );
1219
-
1220
- const bidRequest2 = Object.assign({},
1221
- bidRequestsWithMediaTypes[1],
1222
- {
1223
- getFloor: () => {
1224
- return {
1225
- currency: 'AUS',
1226
- floor: 18.881
1227
- }
1228
- }
1229
- }
1230
- );
842
+ it('should send a coppa flag there is when there is coppa param settings in the bid requests', function () {
843
+ let mockConfig = {
844
+ coppa: true
845
+ };
1231
846
 
1232
- const request = spec.buildRequests([bidRequest1, bidRequest2], mockBidderRequest);
1233
- const dataParams = request[0].data;
847
+ sinon.stub(config, 'getConfig').callsFake((key) => {
848
+ return utils.deepAccess(mockConfig, key);
849
+ });
1234
850
 
1235
- expect(dataParams.aumfs).to.exist;
1236
- expect(dataParams.aumfs).to.equal('9990,18881');
851
+ const request = spec.buildRequests(bidRequestsWithMediaTypes, syncAddFPDToBidderRequest(mockBidderRequest));
852
+ expect(request[0].data.regs.coppa).to.equal(1);
1237
853
  });
1238
854
 
1239
- it('should send out floors on bids in the default currency', function () {
1240
- const bidRequest1 = Object.assign({},
1241
- bidRequestsWithMediaTypes[0],
1242
- {
1243
- getFloor: () => {
1244
- return {};
1245
- }
1246
- }
1247
- );
1248
-
1249
- let getFloorSpy = sinon.spy(bidRequest1, 'getFloor');
1250
-
1251
- spec.buildRequests([bidRequest1], mockBidderRequest);
1252
- expect(getFloorSpy.args[0][0].mediaType).to.equal(BANNER);
1253
- expect(getFloorSpy.args[0][0].currency).to.equal('USD');
855
+ it('should send a coppa flag there is when there is coppa param settings in the bid params', function () {
856
+ const request = spec.buildRequests(bidRequestsWithMediaTypes, syncAddFPDToBidderRequest(mockBidderRequest));
857
+ request.params = {coppa: true};
858
+ expect(request[0].data.regs.coppa).to.equal(1);
1254
859
  });
1255
860
 
1256
- it('should send out floors on bids in the ad server currency if defined', function () {
1257
- adServerCurrencyStub.returns('bitcoin');
1258
-
1259
- const bidRequest1 = Object.assign({},
1260
- bidRequestsWithMediaTypes[0],
1261
- {
1262
- getFloor: () => {
1263
- return {};
1264
- }
1265
- }
1266
- );
1267
-
1268
- let getFloorSpy = sinon.spy(bidRequest1, 'getFloor');
1269
-
1270
- spec.buildRequests([bidRequest1], mockBidderRequest);
1271
- expect(getFloorSpy.args[0][0].mediaType).to.equal(BANNER);
1272
- expect(getFloorSpy.args[0][0].currency).to.equal('bitcoin');
861
+ after(function () {
862
+ config.getConfig.restore()
1273
863
  });
1274
- })
1275
- })
1276
- });
1277
-
1278
- describe('buildRequests for video', function () {
1279
- const bidRequestsWithMediaTypes = VIDEO_BID_REQUESTS_WITH_MEDIA_TYPES;
1280
- const mockBidderRequest = {refererInfo: {}};
1281
-
1282
- it('should send bid request to openx url via GET, with mediaTypes having video parameter', function () {
1283
- const request = spec.buildRequests(bidRequestsWithMediaTypes, mockBidderRequest);
1284
- expect(request[0].url).to.equal('https://' + bidRequestsWithMediaTypes[0].params.delDomain + URLBASEVIDEO);
1285
- expect(request[0].method).to.equal('GET');
1286
- });
1287
- it('should have the correct parameters', function () {
1288
- const request = spec.buildRequests(bidRequestsWithMediaTypes, mockBidderRequest);
1289
- const dataParams = request[0].data;
1290
-
1291
- expect(dataParams.auid).to.equal('12345678');
1292
- expect(dataParams.vht).to.equal(480);
1293
- expect(dataParams.vwd).to.equal(640);
1294
- expect(dataParams.aucs).to.equal(encodeURIComponent('/12345/my-gpt-tag-0'));
1295
- });
1296
-
1297
- it('shouldn\'t have the test parameter', function () {
1298
- const request = spec.buildRequests(bidRequestsWithMediaTypes, mockBidderRequest);
1299
- expect(request[0].data.vtest).to.be.undefined;
1300
- });
1301
-
1302
- it('should send a bc parameter', function () {
1303
- const request = spec.buildRequests(bidRequestsWithMediaTypes, mockBidderRequest);
1304
- const dataParams = request[0].data;
1305
-
1306
- expect(dataParams.bc).to.have.string('hb_pb');
1307
- });
1308
-
1309
- describe('when using the video param', function () {
1310
- let videoBidRequest;
1311
- let mockBidderRequest = {refererInfo: {}};
1312
-
1313
- beforeEach(function () {
1314
- videoBidRequest = {
1315
- 'bidder': 'openx',
1316
- 'mediaTypes': {
1317
- video: {
1318
- context: 'instream',
1319
- playerSize: [640, 480]
1320
- }
1321
- },
1322
- 'params': {
1323
- 'unit': '12345678',
1324
- 'delDomain': 'test-del-domain'
1325
- },
1326
- 'adUnitCode': 'adunit-code',
1327
- 'bidId': '30b31c1838de1e',
1328
- 'bidderRequestId': '22edbae2733bf6',
1329
- 'auctionId': '1d1a030790a475',
1330
- 'transactionId': '4008d88a-8137-410b-aa35-fbfdabcb478e'
1331
- };
1332
- mockBidderRequest = {refererInfo: {}};
1333
- });
1334
-
1335
- it('should not allow you to set a url', function () {
1336
- videoBidRequest.params.video = {
1337
- url: 'test-url'
1338
- };
1339
- const request = spec.buildRequests([videoBidRequest], mockBidderRequest);
1340
-
1341
- expect(request[0].data.url).to.be.undefined;
1342
- });
1343
-
1344
- it('should not allow you to override the javascript url', function () {
1345
- let myUrl = 'my-url';
1346
- videoBidRequest.params.video = {
1347
- ju: myUrl
1348
- };
1349
- const request = spec.buildRequests([videoBidRequest], mockBidderRequest);
1350
-
1351
- expect(request[0].data.ju).to.not.equal(myUrl);
1352
864
  });
1353
865
 
1354
- describe('when using the openrtb video params', function () {
1355
- it('should parse legacy params.video.openrtb', function () {
1356
- let myOpenRTBObject = {mimes: ['application/javascript']};
1357
- videoBidRequest.params.video = {
1358
- openrtb: myOpenRTBObject
1359
- };
1360
- const expected = {imp: [{video: {w: 640, h: 480, mimes: ['application/javascript']}}]}
1361
- const request = spec.buildRequests([videoBidRequest], mockBidderRequest);
866
+ context('do not track (DNT)', function() {
867
+ let doNotTrackStub;
1362
868
 
1363
- expect(request[0].data.openrtb).to.equal(JSON.stringify(expected));
869
+ beforeEach(function () {
870
+ doNotTrackStub = sinon.stub(utils, 'getDNT');
1364
871
  });
1365
-
1366
- it('should parse legacy params.openrtb', function () {
1367
- let myOpenRTBObject = {mimes: ['application/javascript']};
1368
- videoBidRequest.params.openrtb = myOpenRTBObject;
1369
- const expected = {imp: [{video: {w: 640, h: 480, mimes: ['application/javascript']}}]}
1370
- const request = spec.buildRequests([videoBidRequest], mockBidderRequest);
1371
-
1372
- expect(request[0].data.openrtb).to.equal(JSON.stringify(expected));
872
+ afterEach(function() {
873
+ doNotTrackStub.restore();
1373
874
  });
1374
875
 
1375
- it('should parse legacy params.video', function () {
1376
- let myOpenRTBObject = {mimes: ['application/javascript']};
1377
- videoBidRequest.params.video = myOpenRTBObject;
1378
- const expected = {imp: [{video: {w: 640, h: 480, mimes: ['application/javascript']}}]}
1379
- const request = spec.buildRequests([videoBidRequest], mockBidderRequest);
876
+ it('when there is a do not track, should send a dnt', function () {
877
+ doNotTrackStub.returns(1);
1380
878
 
1381
- expect(request[0].data.openrtb).to.equal(JSON.stringify(expected));
879
+ const request = spec.buildRequests(bidRequestsWithMediaTypes, syncAddFPDToBidderRequest(mockBidderRequest));
880
+ expect(request[0].data.device.dnt).to.equal(1);
1382
881
  });
1383
882
 
1384
- it('should parse legacy params.video as full openrtb', function () {
1385
- let myOpenRTBObject = {imp: [{video: {mimes: ['application/javascript']}}]};
1386
- videoBidRequest.params.video = myOpenRTBObject;
1387
- const expected = {imp: [{video: {w: 640, h: 480, mimes: ['application/javascript']}}]}
1388
- const request = spec.buildRequests([videoBidRequest], mockBidderRequest);
883
+ it('when there is not do not track, don\'t send dnt', function () {
884
+ doNotTrackStub.returns(0);
1389
885
 
1390
- expect(request[0].data.openrtb).to.equal(JSON.stringify(expected));
886
+ const request = spec.buildRequests(bidRequestsWithMediaTypes, syncAddFPDToBidderRequest(mockBidderRequest));
887
+ expect(request[0].data.device.dnt).to.equal(0);
1391
888
  });
1392
889
 
1393
- it('should parse legacy video.openrtb', function () {
1394
- let myOpenRTBObject = {mimes: ['application/javascript']};
1395
- videoBidRequest.params.video = {
1396
- openrtb: myOpenRTBObject
1397
- };
1398
- const expected = {imp: [{video: {w: 640, h: 480, mimes: ['application/javascript']}}]}
1399
- const request = spec.buildRequests([videoBidRequest], mockBidderRequest);
890
+ it('when there is no defined do not track, don\'t send dnt', function () {
891
+ doNotTrackStub.returns(null);
1400
892
 
1401
- expect(request[0].data.openrtb).to.equal(JSON.stringify(expected));
893
+ const request = spec.buildRequests(bidRequestsWithMediaTypes, syncAddFPDToBidderRequest(mockBidderRequest));
894
+ expect(request[0].data.device.dnt).to.equal(0);
1402
895
  });
896
+ });
1403
897
 
1404
- it('should omit filtered values for legacy', function () {
1405
- let myOpenRTBObject = {mimes: ['application/javascript'], dont: 'use'};
1406
- videoBidRequest.params.video = {
1407
- openrtb: myOpenRTBObject
898
+ context('supply chain (schain)', function () {
899
+ let bidRequests;
900
+ let schainConfig;
901
+ const supplyChainNodePropertyOrder = ['asi', 'sid', 'hp', 'rid', 'name', 'domain'];
902
+
903
+ beforeEach(function () {
904
+ schainConfig = {
905
+ ver: '1.0',
906
+ complete: 1,
907
+ nodes: [
908
+ {
909
+ asi: 'exchange1.com',
910
+ sid: '1234',
911
+ hp: 1,
912
+ rid: 'bid-request-1',
913
+ name: 'publisher',
914
+ domain: 'publisher.com'
915
+ // omitted ext
916
+ },
917
+ {
918
+ asi: 'exchange2.com',
919
+ sid: 'abcd',
920
+ hp: 1,
921
+ rid: 'bid-request-2',
922
+ // name field missing
923
+ domain: 'intermediary.com'
924
+ },
925
+ {
926
+ asi: 'exchange3.com',
927
+ sid: '4321',
928
+ hp: 1,
929
+ // request id
930
+ // name field missing
931
+ domain: 'intermediary-2.com'
932
+ }
933
+ ]
1408
934
  };
1409
- const expected = {imp: [{video: {w: 640, h: 480, mimes: ['application/javascript']}}]}
1410
- const request = spec.buildRequests([videoBidRequest], mockBidderRequest);
1411
935
 
1412
- expect(request[0].data.openrtb).to.equal(JSON.stringify(expected));
936
+ bidRequests = [{
937
+ bidder: 'openx',
938
+ params: {
939
+ unit: '11',
940
+ delDomain: 'test-del-domain'
941
+ },
942
+ adUnitCode: '/adunit-code/test-path',
943
+ mediaTypes: {
944
+ banner: {
945
+ sizes: [[300, 250], [300, 600]]
946
+ }
947
+ },
948
+ bidId: 'test-bid-id-1',
949
+ bidderRequestId: 'test-bid-request-1',
950
+ auctionId: 'test-auction-1',
951
+ schain: schainConfig
952
+ }];
1413
953
  });
1414
954
 
1415
- it('should parse mediatypes.video', function () {
1416
- videoBidRequest.mediaTypes.video.mimes = ['application/javascript']
1417
- videoBidRequest.mediaTypes.video.minduration = 15
1418
- const request = spec.buildRequests([videoBidRequest], mockBidderRequest);
1419
- const openRtbRequestParams = JSON.parse(request[0].data.openrtb);
1420
- expect(openRtbRequestParams.imp[0].video.mimes).to.eql(['application/javascript']);
1421
- expect(openRtbRequestParams.imp[0].video.minduration).to.equal(15);
955
+ it('should send a supply chain object', function () {
956
+ const request = spec.buildRequests(bidRequests, mockBidderRequest);
957
+ expect(request[0].data.source.ext.schain).to.equal(schainConfig);
1422
958
  });
1423
959
 
1424
- it('should filter mediatypes.video', function () {
1425
- videoBidRequest.mediaTypes.video.mimes = ['application/javascript']
1426
- videoBidRequest.mediaTypes.video.minnothing = 15
1427
- const request = spec.buildRequests([videoBidRequest], mockBidderRequest);
1428
- const openRtbRequestParams = JSON.parse(request[0].data.openrtb);
1429
- expect(openRtbRequestParams.imp[0].video.mimes).to.eql(['application/javascript']);
1430
- expect(openRtbRequestParams.imp[0].video.minnothing).to.equal(undefined);
960
+ it('should send the supply chain object with the right version', function () {
961
+ const request = spec.buildRequests(bidRequests, mockBidderRequest);
962
+ expect(request[0].data.source.ext.schain.ver).to.equal(schainConfig.ver);
1431
963
  });
1432
964
 
1433
- it("should use the bidRequest's playerSize", function () {
1434
- const width = 200;
1435
- const height = 100;
1436
- const myOpenRTBObject = {v: height, w: width};
1437
- videoBidRequest.params.video = {
1438
- openrtb: myOpenRTBObject
1439
- };
1440
- const request = spec.buildRequests([videoBidRequest], mockBidderRequest);
1441
- const openRtbRequestParams = JSON.parse(request[0].data.openrtb);
1442
-
1443
- expect(openRtbRequestParams.imp[0].video.w).to.equal(640);
1444
- expect(openRtbRequestParams.imp[0].video.h).to.equal(480);
965
+ it('should send the supply chain object with the right complete value', function () {
966
+ const request = spec.buildRequests(bidRequests, mockBidderRequest);
967
+ expect(request[0].data.source.ext.schain.complete).to.equal(schainConfig.complete);
1445
968
  });
1446
969
  });
1447
- });
1448
970
 
1449
- describe('floors', function () {
1450
- it('should send out custom floors on bids that have customFloors specified', function () {
1451
- const bidRequest = Object.assign({},
1452
- bidRequestsWithMediaTypes[0],
971
+ context('when there are userid providers', function () {
972
+ const userIdAsEids = [
1453
973
  {
1454
- params: {
1455
- 'unit': '12345678',
1456
- 'delDomain': 'test-del-domain',
1457
- 'customFloor': 1.500001
1458
- }
974
+ source: 'adserver.org',
975
+ uids: [{
976
+ id: 'some-random-id-value',
977
+ atype: 1,
978
+ ext: {
979
+ rtiPartner: 'TDID'
980
+ }
981
+ }]
982
+ },
983
+ {
984
+ source: 'id5-sync.com',
985
+ uids: [{
986
+ id: 'some-random-id-value',
987
+ atype: 1
988
+ }]
989
+ },
990
+ {
991
+ source: 'sharedid.org',
992
+ uids: [{
993
+ id: 'some-random-id-value',
994
+ atype: 1,
995
+ ext: {
996
+ third: 'some-random-id-value'
997
+ }
998
+ }]
1459
999
  }
1460
- );
1461
-
1462
- const request = spec.buildRequests([bidRequest], mockBidderRequest);
1463
- const dataParams = request[0].data;
1464
-
1465
- expect(dataParams.aumfs).to.exist;
1466
- expect(dataParams.aumfs).to.equal('1500');
1467
- });
1000
+ ];
1468
1001
 
1469
- context('with floors module', function () {
1470
- let adServerCurrencyStub;
1471
- function makeBidWithFloorInfo(floorInfo) {
1472
- return Object.assign(utils.deepClone(bidRequestsWithMediaTypes[0]),
1473
- {
1474
- getFloor: () => {
1475
- return floorInfo;
1002
+ it(`should send the user id under the extended ids`, function () {
1003
+ const bidRequestsWithUserId = [{
1004
+ bidder: 'openx',
1005
+ params: {
1006
+ unit: '11',
1007
+ delDomain: 'test-del-domain'
1008
+ },
1009
+ userId: {
1010
+ },
1011
+ adUnitCode: 'adunit-code',
1012
+ mediaTypes: {
1013
+ banner: {
1014
+ sizes: [[300, 250], [300, 600]]
1476
1015
  }
1477
- });
1478
- }
1479
-
1480
- beforeEach(function () {
1481
- adServerCurrencyStub = sinon
1482
- .stub(config, 'getConfig')
1483
- .withArgs('currency.adServerCurrency')
1016
+ },
1017
+ bidId: 'test-bid-id-1',
1018
+ bidderRequestId: 'test-bid-request-1',
1019
+ auctionId: 'test-auction-1',
1020
+ userIdAsEids: userIdAsEids
1021
+ }];
1022
+ // enrich bid request with userId key/value
1023
+
1024
+ const request = spec.buildRequests(bidRequestsWithUserId, mockBidderRequest);
1025
+ expect(request[0].data.user.ext.eids).to.equal(userIdAsEids);
1484
1026
  });
1485
1027
 
1486
- afterEach(function () {
1487
- config.getConfig.restore();
1028
+ it(`when no user ids are available, it should not send any extended ids`, function () {
1029
+ const request = spec.buildRequests(bidRequestsWithMediaTypes, mockBidderRequest);
1030
+ expect(request[0].data).to.not.have.any.keys('user');
1488
1031
  });
1032
+ });
1489
1033
 
1490
- it('should send out floors on bids', function () {
1491
- const floors = [9.99, 18.881];
1492
- const bidRequests = floors.map(floor => {
1493
- return makeBidWithFloorInfo({
1494
- currency: 'AUS',
1495
- floor: floor
1496
- });
1034
+ context('FLEDGE', function() {
1035
+ it('when FLEDGE is enabled, should send whatever is set in ortb2imp.ext.ae in all bid requests', function () {
1036
+ const request = spec.buildRequests(bidRequestsWithMediaTypes, {
1037
+ ...mockBidderRequest,
1038
+ fledgeEnabled: true
1497
1039
  });
1498
- const request = spec.buildRequests(bidRequests, mockBidderRequest);
1499
-
1500
- expect(request[0].data.aumfs).to.exist;
1501
- expect(request[0].data.aumfs).to.equal('9990');
1502
- expect(request[1].data.aumfs).to.exist;
1503
- expect(request[1].data.aumfs).to.equal('18881');
1040
+ expect(request[0].data.imp[0].ext.ae).to.equal(2);
1504
1041
  });
1042
+ });
1043
+ });
1505
1044
 
1506
- it('should send out floors on bids in the default currency', function () {
1507
- const bidRequest1 = makeBidWithFloorInfo({});
1508
-
1509
- let getFloorSpy = sinon.spy(bidRequest1, 'getFloor');
1045
+ context('banner', function () {
1046
+ it('should send bid request with a mediaTypes specified with banner type', function () {
1047
+ const request = spec.buildRequests(bidRequestsWithMediaTypes, mockBidderRequest);
1048
+ expect(request[0].data.imp[0]).to.have.any.keys(BANNER);
1049
+ });
1050
+ });
1510
1051
 
1511
- spec.buildRequests([bidRequest1], mockBidderRequest);
1512
- expect(getFloorSpy.args[0][0].mediaType).to.equal(VIDEO);
1513
- expect(getFloorSpy.args[0][0].currency).to.equal('USD');
1052
+ if (FEATURES.VIDEO) {
1053
+ context('video', function () {
1054
+ it('should send bid request with a mediaTypes specified with video type', function () {
1055
+ const request = spec.buildRequests(bidRequestsWithMediaTypes, mockBidderRequest);
1056
+ expect(request[1].data.imp[0]).to.have.any.keys(VIDEO);
1514
1057
  });
1515
1058
 
1516
- it('should send out floors on bids in the ad server currency if defined', function () {
1517
- adServerCurrencyStub.returns('bitcoin');
1518
-
1519
- const bidRequest1 = makeBidWithFloorInfo({});
1520
-
1521
- let getFloorSpy = sinon.spy(bidRequest1, 'getFloor');
1522
-
1523
- spec.buildRequests([bidRequest1], mockBidderRequest);
1524
- expect(getFloorSpy.args[0][0].mediaType).to.equal(VIDEO);
1525
- expect(getFloorSpy.args[0][0].currency).to.equal('bitcoin');
1059
+ it('Update imp.video with OpenRTB options from mimeTypes and params', function() {
1060
+ const bid01 = new BidRequestBuilder({
1061
+ adUnitCode: 'adunit-code-01',
1062
+ mediaTypes: {
1063
+ banner: { sizes: [[300, 250]] },
1064
+ video: {
1065
+ context: 'outstream',
1066
+ playerSize: [[300, 250]],
1067
+ mimes: ['video/mp4'],
1068
+ protocols: [8]
1069
+ }
1070
+ },
1071
+ }).withParams({
1072
+ // options in video, will merge
1073
+ video: {
1074
+ skip: 1,
1075
+ skipafter: 4,
1076
+ minduration: 10,
1077
+ maxduration: 30
1078
+ }
1079
+ }).build();
1080
+
1081
+ const bidderRequest = new BidderRequestBuilder().build();
1082
+ const expected = {
1083
+ mimes: ['video/mp4'],
1084
+ skip: 1,
1085
+ skipafter: 4,
1086
+ minduration: 10,
1087
+ maxduration: 30,
1088
+ placement: 4,
1089
+ protocols: [8],
1090
+ w: 300,
1091
+ h: 250
1092
+ };
1093
+ const requests = spec.buildRequests([bid01], bidderRequest);
1094
+ expect(requests).to.have.lengthOf(2);
1095
+ expect(requests[1].data.imp[0].video).to.deep.equal(expected);
1526
1096
  });
1527
- })
1528
- })
1097
+ });
1098
+ }
1529
1099
  });
1530
1100
 
1531
- describe('buildRequest for multi-format ad', function () {
1532
- const multiformatBid = MULTI_FORMAT_BID_REQUESTS[0];
1533
- let mockBidderRequest = {refererInfo: {}};
1101
+ describe('interpretResponse()', function () {
1102
+ let bidRequestConfigs;
1103
+ let bidRequest;
1104
+ let bidResponse;
1105
+ let bid;
1534
1106
 
1535
- it('should default to a banner request', function () {
1536
- const request = spec.buildRequests([multiformatBid], mockBidderRequest);
1537
- const dataParams = request[0].data;
1538
-
1539
- expect(dataParams.divids).to.have.string(multiformatBid.adUnitCode);
1540
- });
1541
- });
1542
-
1543
- describe('buildRequests for all kinds of ads', function () {
1544
- utils._each({
1545
- banner: BANNER_BID_REQUESTS_WITH_MEDIA_TYPES[0],
1546
- video: VIDEO_BID_REQUESTS_WITH_MEDIA_TYPES[0],
1547
- multi: MULTI_FORMAT_BID_REQUESTS[0]
1548
- }, (bidRequest, name) => {
1549
- describe('with segments', function () {
1550
- const TESTS = [
1551
- {
1552
- name: 'should send proprietary segment data from ortb2.user.data',
1553
- config: {
1554
- ortb2: {
1555
- user: {
1556
- data: [
1557
- {name: 'dmp1', ext: {segtax: 4}, segment: [{id: 'foo'}, {id: 'bar'}]},
1558
- {name: 'dmp2', segment: [{id: 'baz'}]},
1559
- ]
1560
- }
1561
- }
1562
- },
1563
- expect: {sm: 'dmp1/4:foo|bar,dmp2:baz'},
1564
- },
1565
- {
1566
- name: 'should send proprietary segment data from ortb2.site.content.data',
1567
- config: {
1568
- ortb2: {
1569
- site: {
1570
- content: {
1571
- data: [
1572
- {name: 'dmp1', ext: {segtax: 4}, segment: [{id: 'foo'}, {id: 'bar'}]},
1573
- {name: 'dmp2', segment: [{id: 'baz'}]},
1574
- ]
1575
- }
1576
- }
1577
- }
1578
- },
1579
- expect: {scsm: 'dmp1/4:foo|bar,dmp2:baz'},
1580
- },
1581
- {
1582
- name: 'should send proprietary segment data from both ortb2.site.content.data and ortb2.user.data',
1583
- config: {
1584
- ortb2: {
1585
- user: {
1586
- data: [
1587
- {name: 'dmp1', ext: {segtax: 4}, segment: [{id: 'foo'}, {id: 'bar'}]},
1588
- {name: 'dmp2', segment: [{id: 'baz'}]},
1589
- ]
1590
- },
1591
- site: {
1592
- content: {
1593
- data: [
1594
- {name: 'dmp3', ext: {segtax: 5}, segment: [{id: 'foo2'}, {id: 'bar2'}]},
1595
- {name: 'dmp4', segment: [{id: 'baz2'}]},
1596
- ]
1597
- }
1598
- }
1599
- }
1600
- },
1601
- expect: {
1602
- sm: 'dmp1/4:foo|bar,dmp2:baz',
1603
- scsm: 'dmp3/5:foo2|bar2,dmp4:baz2'
1604
- },
1605
- },
1606
- {
1607
- name: 'should combine same provider segment data from ortb2.user.data',
1608
- config: {
1609
- ortb2: {
1610
- user: {
1611
- data: [
1612
- {name: 'dmp1', ext: {segtax: 4}, segment: [{id: 'foo'}, {id: 'bar'}]},
1613
- {name: 'dmp1', ext: {}, segment: [{id: 'baz'}]},
1614
- ]
1615
- }
1616
- }
1617
- },
1618
- expect: {sm: 'dmp1/4:foo|bar,dmp1:baz'},
1619
- },
1620
- {
1621
- name: 'should combine same provider segment data from ortb2.site.content.data',
1622
- config: {
1623
- ortb2: {
1624
- site: {
1625
- content: {
1626
- data: [
1627
- {name: 'dmp1', ext: {segtax: 4}, segment: [{id: 'foo'}, {id: 'bar'}]},
1628
- {name: 'dmp1', ext: {}, segment: [{id: 'baz'}]},
1629
- ]
1630
- }
1631
- }
1632
- }
1633
- },
1634
- expect: {scsm: 'dmp1/4:foo|bar,dmp1:baz'},
1635
- },
1636
- {
1637
- name: 'should not send any segment data if first party config is incomplete',
1638
- config: {
1639
- ortb2: {
1640
- user: {
1641
- data: [
1642
- {name: 'provider-with-no-segments'},
1643
- {segment: [{id: 'segments-with-no-provider'}]},
1644
- {},
1645
- ]
1646
- }
1647
- }
1648
- }
1107
+ context('when there is an nbr response', function () {
1108
+ let bids;
1109
+ beforeEach(function () {
1110
+ bidRequestConfigs = [{
1111
+ bidder: 'openx',
1112
+ params: {
1113
+ unit: '12345678',
1114
+ delDomain: 'test-del-domain'
1649
1115
  },
1650
- {
1651
- name: 'should send first party data segments and liveintent segments from request',
1652
- config: {
1653
- ortb2: {
1654
- user: {
1655
- data: [
1656
- {name: 'dmp1', segment: [{id: 'foo'}, {id: 'bar'}]},
1657
- {name: 'dmp2', segment: [{id: 'baz'}]},
1658
- ]
1659
- },
1660
- site: {
1661
- content: {
1662
- data: [
1663
- {name: 'dmp3', ext: {segtax: 5}, segment: [{id: 'foo2'}, {id: 'bar2'}]},
1664
- {name: 'dmp4', segment: [{id: 'baz2'}]},
1665
- ]
1666
- }
1667
- }
1668
- }
1669
- },
1670
- request: {
1671
- userId: {
1672
- lipb: {
1673
- lipbid: 'aaa',
1674
- segments: ['l1', 'l2']
1675
- },
1676
- },
1677
- },
1678
- expect: {
1679
- sm: 'dmp1:foo|bar,dmp2:baz,liveintent:l1|l2',
1680
- scsm: 'dmp3/5:foo2|bar2,dmp4:baz2'
1116
+ adUnitCode: 'adunit-code',
1117
+ mediaTypes: {
1118
+ banner: {
1119
+ sizes: [[300, 250], [300, 600]],
1681
1120
  },
1682
1121
  },
1683
- {
1684
- name: 'should send just liveintent segment from request if no first party config',
1685
- config: {},
1686
- request: {
1687
- userId: {
1688
- lipb: {
1689
- lipbid: 'aaa',
1690
- segments: ['l1', 'l2']
1691
- },
1692
- },
1693
- },
1694
- expect: {sm: 'liveintent:l1|l2'},
1122
+ bidId: 'test-bid-id',
1123
+ bidderRequestId: 'test-bidder-request-id',
1124
+ auctionId: 'test-auction-id'
1125
+ }];
1126
+
1127
+ bidRequest = spec.buildRequests(bidRequestConfigs, {refererInfo: {}})[0];
1128
+
1129
+ bidResponse = {nbr: 0}; // Unknown error
1130
+ bids = spec.interpretResponse({body: bidResponse}, bidRequest);
1131
+ });
1132
+
1133
+ it('should not return any bids', function () {
1134
+ expect(bids.length).to.equal(0);
1135
+ });
1136
+ });
1137
+
1138
+ context('when no seatbid in response', function () {
1139
+ let bids;
1140
+ beforeEach(function () {
1141
+ bidRequestConfigs = [{
1142
+ bidder: 'openx',
1143
+ params: {
1144
+ unit: '12345678',
1145
+ delDomain: 'test-del-domain'
1695
1146
  },
1696
- {
1697
- name: 'should send nothing if lipb section does not contain segments',
1698
- config: {},
1699
- request: {
1700
- userId: {
1701
- lipb: {
1702
- lipbid: 'aaa',
1703
- },
1704
- },
1147
+ adUnitCode: 'adunit-code',
1148
+ mediaTypes: {
1149
+ banner: {
1150
+ sizes: [[300, 250], [300, 600]],
1705
1151
  },
1706
1152
  },
1707
- ];
1708
- utils._each(TESTS, (t) => {
1709
- context('in ortb2.user.data', function () {
1710
- let bidRequests;
1711
- beforeEach(function () {
1712
- bidRequests = [{...bidRequest, ...t.request}];
1713
- });
1153
+ bidId: 'test-bid-id',
1154
+ bidderRequestId: 'test-bidder-request-id',
1155
+ auctionId: 'test-auction-id'
1156
+ }];
1714
1157
 
1715
- const mockBidderRequest = {refererInfo: {}, ortb2: t.config.ortb2};
1716
- it(`${t.name} for type ${name}`, function () {
1717
- const request = spec.buildRequests(bidRequests, mockBidderRequest)
1718
- expect(request.length).to.equal(1);
1719
- if (t.expect) {
1720
- for (const key in t.expect) {
1721
- expect(request[0].data[key]).to.exist;
1722
- expect(request[0].data[key]).to.equal(t.expect[key]);
1723
- }
1724
- } else {
1725
- expect(request[0].data.sm).to.not.exist;
1726
- expect(request[0].data.scsm).to.not.exist;
1727
- }
1728
- });
1729
- });
1730
- });
1158
+ bidRequest = spec.buildRequests(bidRequestConfigs, {refererInfo: {}})[0];
1159
+
1160
+ bidResponse = {ext: {}, id: 'test-bid-id'};
1161
+ bids = spec.interpretResponse({body: bidResponse}, bidRequest);
1731
1162
  });
1732
- describe('with user agent client hints', function () {
1733
- it('should add json query param sua with BidRequest.device.sua if available', function () {
1734
- const bidderRequestWithUserAgentClientHints = { refererInfo: {},
1735
- ortb2: {
1736
- device: {
1737
- sua: {
1738
- source: 2,
1739
- platform: {
1740
- brand: 'macOS',
1741
- version: [ '12', '4', '0' ]
1742
- },
1743
- browsers: [
1744
- {
1745
- brand: 'Chromium',
1746
- version: [ '106', '0', '5249', '119' ]
1747
- },
1748
- {
1749
- brand: 'Google Chrome',
1750
- version: [ '106', '0', '5249', '119' ]
1751
- },
1752
- {
1753
- brand: 'Not;A=Brand',
1754
- version: [ '99', '0', '0', '0' ]
1755
- }],
1756
- mobile: 0,
1757
- model: 'Pro',
1758
- bitness: '64',
1759
- architecture: 'x86'
1760
- }
1761
- }
1762
- }};
1763
-
1764
- let request = spec.buildRequests([bidRequest], bidderRequestWithUserAgentClientHints);
1765
- expect(request[0].data.sua).to.exist;
1766
- const payload = JSON.parse(request[0].data.sua);
1767
- expect(payload).to.deep.equal(bidderRequestWithUserAgentClientHints.ortb2.device.sua);
1768
- const bidderRequestWithoutUserAgentClientHints = {refererInfo: {}, ortb2: {}};
1769
- request = spec.buildRequests([bidRequest], bidderRequestWithoutUserAgentClientHints);
1770
- expect(request[0].data.sua).to.not.exist;
1771
- });
1163
+
1164
+ it('should not return any bids', function () {
1165
+ expect(bids.length).to.equal(0);
1772
1166
  });
1773
1167
  });
1774
- })
1775
1168
 
1776
- describe('interpretResponse for banner ads', function () {
1777
- beforeEach(function () {
1778
- sinon.spy(userSync, 'registerSync');
1779
- });
1169
+ context('when there is no response', function () {
1170
+ let bids;
1171
+ beforeEach(function () {
1172
+ bidRequestConfigs = [{
1173
+ bidder: 'openx',
1174
+ params: {
1175
+ unit: '12345678',
1176
+ delDomain: 'test-del-domain'
1177
+ },
1178
+ adUnitCode: 'adunit-code',
1179
+ mediaTypes: {
1180
+ banner: {
1181
+ sizes: [[300, 250], [300, 600]],
1182
+ },
1183
+ },
1184
+ bidId: 'test-bid-id',
1185
+ bidderRequestId: 'test-bidder-request-id',
1186
+ auctionId: 'test-auction-id'
1187
+ }];
1188
+
1189
+ bidRequest = spec.buildRequests(bidRequestConfigs, {refererInfo: {}})[0];
1780
1190
 
1781
- afterEach(function () {
1782
- userSync.registerSync.restore();
1191
+ bidResponse = ''; // Unknown error
1192
+ bids = spec.interpretResponse({body: bidResponse}, bidRequest);
1193
+ });
1194
+
1195
+ it('should not return any bids', function () {
1196
+ expect(bids.length).to.equal(0);
1197
+ });
1783
1198
  });
1784
1199
 
1785
- describe('when there is a standard response', function () {
1786
- const creativeOverride = {
1787
- id: 234,
1788
- width: '300',
1789
- height: '250',
1790
- tracking: {
1791
- impression: 'https://openx-d.openx.net/v/1.0/ri?ts=ts'
1200
+ const SAMPLE_BID_REQUESTS = [{
1201
+ bidder: 'openx',
1202
+ params: {
1203
+ unit: '12345678',
1204
+ delDomain: 'test-del-domain'
1205
+ },
1206
+ adUnitCode: 'adunit-code',
1207
+ mediaTypes: {
1208
+ banner: {
1209
+ sizes: [[300, 250], [300, 600]],
1210
+ },
1211
+ },
1212
+ bidId: 'test-bid-id',
1213
+ bidderRequestId: 'test-bidder-request-id',
1214
+ auctionId: 'test-auction-id'
1215
+ }];
1216
+
1217
+ const SAMPLE_BID_RESPONSE = {
1218
+ seatbid: [{
1219
+ bid: [{
1220
+ impid: 'test-bid-id',
1221
+ price: 2,
1222
+ w: 300,
1223
+ h: 250,
1224
+ crid: 'test-creative-id',
1225
+ dealid: 'test-deal-id',
1226
+ adm: 'test-ad-markup',
1227
+ adomain: ['brand.com'],
1228
+ ext: {
1229
+ dsp_id: '123',
1230
+ buyer_id: '456',
1231
+ brand_id: '789',
1232
+ paf: {
1233
+ content_id: 'paf_content_id'
1234
+ }
1235
+ }
1236
+ }]
1237
+ }],
1238
+ cur: 'AUS',
1239
+ ext: {
1240
+ paf: {
1241
+ transmission: {version: '12'}
1792
1242
  }
1793
- };
1794
-
1795
- const adUnitOverride = {
1796
- ts: 'test-1234567890-ts',
1797
- idx: '0',
1798
- currency: 'USD',
1799
- pub_rev: '10000',
1800
- html: '<div>OpenX Ad</div>'
1801
- };
1802
- let adUnit;
1803
- let bidResponse;
1804
-
1805
- let bid;
1806
- let bidRequest;
1807
- let bidRequestConfigs;
1243
+ }
1244
+ };
1808
1245
 
1246
+ context('when there is a response, the common response properties', function () {
1809
1247
  beforeEach(function () {
1810
- bidRequestConfigs = [{
1811
- 'bidder': 'openx',
1812
- 'params': {
1813
- 'unit': '12345678',
1814
- 'delDomain': 'test-del-domain'
1815
- },
1816
- 'adUnitCode': 'adunit-code',
1817
- 'mediaType': 'banner',
1818
- 'sizes': [[300, 250], [300, 600]],
1819
- 'bidId': '30b31c1838de1e',
1820
- 'bidderRequestId': '22edbae2733bf6',
1821
- 'auctionId': '1d1a030790a475'
1822
- }];
1823
-
1824
- bidRequest = {
1825
- method: 'GET',
1826
- url: 'https://openx-d.openx.net/v/1.0/arj',
1827
- data: {},
1828
- payload: {'bids': bidRequestConfigs, 'startTime': new Date()}
1829
- };
1248
+ bidRequestConfigs = deepClone(SAMPLE_BID_REQUESTS);
1249
+ bidRequest = spec.buildRequests(bidRequestConfigs, {refererInfo: {}})[0];
1250
+ bidResponse = deepClone(SAMPLE_BID_RESPONSE);
1830
1251
 
1831
- adUnit = mockAdUnit(adUnitOverride, creativeOverride);
1832
- bidResponse = mockArjResponse(undefined, [adUnit]);
1833
1252
  bid = spec.interpretResponse({body: bidResponse}, bidRequest)[0];
1834
1253
  });
1835
1254
 
1836
1255
  it('should return a price', function () {
1837
- expect(bid.cpm).to.equal(parseInt(adUnitOverride.pub_rev, 10) / 1000);
1256
+ expect(bid.cpm).to.equal(bidResponse.seatbid[0].bid[0].price);
1838
1257
  });
1839
1258
 
1840
1259
  it('should return a request id', function () {
1841
- expect(bid.requestId).to.equal(bidRequest.payload.bids[0].bidId);
1260
+ expect(bid.requestId).to.equal(bidResponse.seatbid[0].bid[0].impid);
1842
1261
  });
1843
1262
 
1844
1263
  it('should return width and height for the creative', function () {
1845
- expect(bid.width).to.equal(creativeOverride.width);
1846
- expect(bid.height).to.equal(creativeOverride.height);
1264
+ expect(bid.width).to.equal(bidResponse.seatbid[0].bid[0].w);
1265
+ expect(bid.height).to.equal(bidResponse.seatbid[0].bid[0].h);
1847
1266
  });
1848
1267
 
1849
1268
  it('should return a creativeId', function () {
1850
- expect(bid.creativeId).to.equal(creativeOverride.id);
1269
+ expect(bid.creativeId).to.equal(bidResponse.seatbid[0].bid[0].crid);
1851
1270
  });
1852
1271
 
1853
1272
  it('should return an ad', function () {
1854
- expect(bid.ad).to.equal(adUnitOverride.html);
1273
+ expect(bid.ad).to.equal(bidResponse.seatbid[0].bid[0].adm);
1274
+ });
1275
+
1276
+ it('should return a deal id if it exists', function () {
1277
+ expect(bid.dealId).to.equal(bidResponse.seatbid[0].bid[0].dealid);
1855
1278
  });
1856
1279
 
1857
1280
  it('should have a time-to-live of 5 minutes', function () {
@@ -1863,415 +1286,293 @@ describe('OpenxAdapter', function () {
1863
1286
  });
1864
1287
 
1865
1288
  it('should return a currency', function () {
1866
- expect(bid.currency).to.equal(adUnitOverride.currency);
1867
- });
1868
-
1869
- it('should return a transaction state', function () {
1870
- expect(bid.ts).to.equal(adUnitOverride.ts);
1289
+ expect(bid.currency).to.equal(bidResponse.cur);
1871
1290
  });
1872
1291
 
1873
1292
  it('should return a brand ID', function () {
1874
- expect(bid.meta.brandId).to.equal(DEFAULT_TEST_ARJ_AD_UNIT.brand_id);
1293
+ expect(bid.meta.brandId).to.equal(bidResponse.seatbid[0].bid[0].ext.brand_id);
1875
1294
  });
1876
1295
 
1877
- it('should return an adomain', function () {
1878
- expect(bid.meta.advertiserDomains).to.deep.equal([]);
1296
+ it('should return a dsp ID', function () {
1297
+ expect(bid.meta.networkId).to.equal(bidResponse.seatbid[0].bid[0].ext.dsp_id);
1879
1298
  });
1880
1299
 
1881
- it('should return a dsp ID', function () {
1882
- expect(bid.meta.dspid).to.equal(DEFAULT_TEST_ARJ_AD_UNIT.adv_id);
1300
+ it('should return a buyer ID', function () {
1301
+ expect(bid.meta.advertiserId).to.equal(bidResponse.seatbid[0].bid[0].ext.buyer_id);
1883
1302
  });
1884
- });
1885
1303
 
1886
- describe('when there is a deal', function () {
1887
- const adUnitOverride = {
1888
- deal_id: 'ox-1000'
1889
- };
1890
- let adUnit;
1891
- let bidResponse;
1304
+ it('should return adomain', function () {
1305
+ expect(bid.meta.advertiserDomains).to.equal(bidResponse.seatbid[0].bid[0].adomain);
1306
+ });
1892
1307
 
1893
- let bid;
1894
- let bidRequestConfigs;
1895
- let bidRequest;
1308
+ it('should return paf fields', function () {
1309
+ const paf = {
1310
+ transmission: {version: '12'},
1311
+ content_id: 'paf_content_id'
1312
+ }
1313
+ expect(bid.meta.paf).to.deep.equal(paf);
1314
+ });
1315
+ });
1896
1316
 
1317
+ context('when there is more than one response', () => {
1318
+ let bids;
1897
1319
  beforeEach(function () {
1898
- bidRequestConfigs = [{
1899
- 'bidder': 'openx',
1900
- 'params': {
1901
- 'unit': '12345678',
1902
- 'delDomain': 'test-del-domain'
1903
- },
1904
- 'adUnitCode': 'adunit-code',
1905
- 'mediaType': 'banner',
1906
- 'sizes': [[300, 250], [300, 600]],
1907
- 'bidId': '30b31c1838de1e',
1908
- 'bidderRequestId': '22edbae2733bf6',
1909
- 'auctionId': '1d1a030790a475'
1910
- }];
1320
+ bidRequestConfigs = deepClone(SAMPLE_BID_REQUESTS);
1321
+ bidRequest = spec.buildRequests(bidRequestConfigs, {refererInfo: {}})[0];
1322
+ bidResponse = deepClone(SAMPLE_BID_RESPONSE);
1323
+ bidResponse.seatbid[0].bid.push(deepClone(bidResponse.seatbid[0].bid[0]));
1324
+ bidResponse.seatbid[0].bid[1].ext.paf.content_id = 'second_paf'
1911
1325
 
1912
- bidRequest = {
1913
- method: 'GET',
1914
- url: 'https://openx-d.openx.net/v/1.0/arj',
1915
- data: {},
1916
- payload: {'bids': bidRequestConfigs, 'startTime': new Date()}
1917
- };
1918
- adUnit = mockAdUnit(adUnitOverride);
1919
- bidResponse = mockArjResponse(null, [adUnit]);
1920
- bid = spec.interpretResponse({body: bidResponse}, bidRequest)[0];
1921
- mockArjResponse();
1326
+ bids = spec.interpretResponse({body: bidResponse}, bidRequest);
1922
1327
  });
1923
1328
 
1924
- it('should return a deal id', function () {
1925
- expect(bid.dealId).to.equal(adUnitOverride.deal_id);
1329
+ it('should not confuse paf content_id', () => {
1330
+ expect(bids.map(b => b.meta.paf.content_id)).to.eql(['paf_content_id', 'second_paf']);
1926
1331
  });
1927
- });
1928
-
1929
- describe('when there is no bids in the response', function () {
1930
- let bidRequest;
1931
- let bidRequestConfigs;
1332
+ })
1932
1333
 
1334
+ context('when the response is a banner', function() {
1933
1335
  beforeEach(function () {
1934
1336
  bidRequestConfigs = [{
1935
- 'bidder': 'openx',
1936
- 'params': {
1937
- 'unit': '12345678',
1938
- 'delDomain': 'test-del-domain'
1337
+ bidder: 'openx',
1338
+ params: {
1339
+ unit: '12345678',
1340
+ delDomain: 'test-del-domain'
1939
1341
  },
1940
- 'adUnitCode': 'adunit-code',
1941
- 'mediaType': 'banner',
1942
- 'sizes': [[300, 250], [300, 600]],
1943
- 'bidId': '30b31c1838de1e',
1944
- 'bidderRequestId': '22edbae2733bf6',
1945
- 'auctionId': '1d1a030790a475'
1342
+ adUnitCode: 'adunit-code',
1343
+ mediaTypes: {
1344
+ banner: {
1345
+ sizes: [[300, 250], [300, 600]],
1346
+ },
1347
+ },
1348
+ bidId: 'test-bid-id',
1349
+ bidderRequestId: 'test-bidder-request-id',
1350
+ auctionId: 'test-auction-id'
1946
1351
  }];
1947
1352
 
1948
- bidRequest = {
1949
- method: 'GET',
1950
- url: 'https://openx-d.openx.net/v/1.0/arj',
1951
- data: {},
1952
- payload: {'bids': bidRequestConfigs, 'startTime': new Date()}
1953
- };
1954
- });
1955
-
1956
- it('handles nobid responses', function () {
1957
- const bidResponse = {
1958
- 'ads':
1959
- {
1960
- 'version': 1,
1961
- 'count': 1,
1962
- 'pixels': 'https://testpixels.net',
1963
- 'ad': []
1964
- }
1353
+ bidRequest = spec.buildRequests(bidRequestConfigs, {refererInfo: {}})[0];
1354
+
1355
+ bidResponse = {
1356
+ seatbid: [{
1357
+ bid: [{
1358
+ impid: 'test-bid-id',
1359
+ price: 2,
1360
+ w: 300,
1361
+ h: 250,
1362
+ crid: 'test-creative-id',
1363
+ dealid: 'test-deal-id',
1364
+ adm: 'test-ad-markup'
1365
+ }]
1366
+ }],
1367
+ cur: 'AUS'
1965
1368
  };
1966
1369
 
1967
- const result = spec.interpretResponse({body: bidResponse}, bidRequest);
1968
- expect(result.length).to.equal(0);
1370
+ bid = spec.interpretResponse({body: bidResponse}, bidRequest)[0];
1969
1371
  });
1970
- });
1971
1372
 
1972
- describe('when adunits return out of order', function () {
1973
- const bidRequests = [{
1974
- bidder: 'openx',
1975
- params: {
1976
- unit: '12345678',
1977
- delDomain: 'test-del-domain'
1978
- },
1979
- adUnitCode: 'adunit-code',
1980
- mediaTypes: {
1981
- banner: {
1982
- sizes: [[100, 111]]
1983
- }
1984
- },
1985
- bidId: 'test-bid-request-id-1',
1986
- bidderRequestId: 'test-request-1',
1987
- auctionId: 'test-auction-id-1'
1988
- }, {
1989
- bidder: 'openx',
1990
- params: {
1991
- unit: '12345678',
1992
- delDomain: 'test-del-domain'
1993
- },
1994
- adUnitCode: 'adunit-code',
1995
- mediaTypes: {
1996
- banner: {
1997
- sizes: [[200, 222]]
1998
- }
1999
- },
2000
- bidId: 'test-bid-request-id-2',
2001
- bidderRequestId: 'test-request-1',
2002
- auctionId: 'test-auction-id-1'
2003
- }, {
2004
- bidder: 'openx',
2005
- params: {
2006
- unit: '12345678',
2007
- delDomain: 'test-del-domain'
2008
- },
2009
- adUnitCode: 'adunit-code',
2010
- mediaTypes: {
2011
- banner: {
2012
- sizes: [[300, 333]]
2013
- }
2014
- },
2015
- 'bidId': 'test-bid-request-id-3',
2016
- 'bidderRequestId': 'test-request-1',
2017
- 'auctionId': 'test-auction-id-1'
2018
- }];
2019
- const bidRequest = {
2020
- method: 'GET',
2021
- url: 'https://openx-d.openx.net/v/1.0/arj',
2022
- data: {},
2023
- payload: {'bids': bidRequests, 'startTime': new Date()}
2024
- };
2025
-
2026
- let outOfOrderAdunits = [
2027
- mockAdUnit({
2028
- idx: '1'
2029
- }, {
2030
- width: bidRequests[1].mediaTypes.banner.sizes[0][0],
2031
- height: bidRequests[1].mediaTypes.banner.sizes[0][1]
2032
- }),
2033
- mockAdUnit({
2034
- idx: '2'
2035
- }, {
2036
- width: bidRequests[2].mediaTypes.banner.sizes[0][0],
2037
- height: bidRequests[2].mediaTypes.banner.sizes[0][1]
2038
- }),
2039
- mockAdUnit({
2040
- idx: '0'
2041
- }, {
2042
- width: bidRequests[0].mediaTypes.banner.sizes[0][0],
2043
- height: bidRequests[0].mediaTypes.banner.sizes[0][1]
2044
- })
2045
- ];
2046
-
2047
- let bidResponse = mockArjResponse(undefined, outOfOrderAdunits);
2048
-
2049
- it('should return map adunits back to the proper request', function () {
2050
- const bids = spec.interpretResponse({body: bidResponse}, bidRequest);
2051
- expect(bids[0].requestId).to.equal(bidRequests[1].bidId);
2052
- expect(bids[0].width).to.equal(bidRequests[1].mediaTypes.banner.sizes[0][0]);
2053
- expect(bids[0].height).to.equal(bidRequests[1].mediaTypes.banner.sizes[0][1]);
2054
- expect(bids[1].requestId).to.equal(bidRequests[2].bidId);
2055
- expect(bids[1].width).to.equal(bidRequests[2].mediaTypes.banner.sizes[0][0]);
2056
- expect(bids[1].height).to.equal(bidRequests[2].mediaTypes.banner.sizes[0][1]);
2057
- expect(bids[2].requestId).to.equal(bidRequests[0].bidId);
2058
- expect(bids[2].width).to.equal(bidRequests[0].mediaTypes.banner.sizes[0][0]);
2059
- expect(bids[2].height).to.equal(bidRequests[0].mediaTypes.banner.sizes[0][1]);
1373
+ it('should return the proper mediaType', function () {
1374
+ it('should return a creativeId', function () {
1375
+ expect(bid.mediaType).to.equal(Object.keys(bidRequestConfigs[0].mediaTypes)[0]);
1376
+ });
2060
1377
  });
2061
1378
  });
2062
- });
2063
-
2064
- describe('interpretResponse for video ads', function () {
2065
- beforeEach(function () {
2066
- sinon.spy(userSync, 'registerSync');
2067
- });
2068
1379
 
2069
- afterEach(function () {
2070
- userSync.registerSync.restore();
2071
- });
2072
-
2073
- const bidsWithMediaTypes = [{
2074
- 'bidder': 'openx',
2075
- 'mediaTypes': {video: {}},
2076
- 'params': {
2077
- 'unit': '12345678',
2078
- 'delDomain': 'test-del-domain'
2079
- },
2080
- 'adUnitCode': 'adunit-code',
2081
- 'sizes': [640, 480],
2082
- 'bidId': '30b31c1838de1e',
2083
- 'bidderRequestId': '22edbae2733bf6',
2084
- 'auctionId': '1d1a030790a475',
2085
- 'transactionId': '4008d88a-8137-410b-aa35-fbfdabcb478e'
2086
- }];
2087
- const bidsWithMediaType = [{
2088
- 'bidder': 'openx',
2089
- 'mediaType': 'video',
2090
- 'params': {
2091
- 'unit': '12345678',
2092
- 'delDomain': 'test-del-domain'
2093
- },
2094
- 'adUnitCode': 'adunit-code',
2095
- 'sizes': [640, 480],
2096
- 'bidId': '30b31c1838de1e',
2097
- 'bidderRequestId': '22edbae2733bf6',
2098
- 'auctionId': '1d1a030790a475',
2099
- 'transactionId': '4008d88a-8137-410b-aa35-fbfdabcb478e'
2100
- }];
2101
- const bidRequestsWithMediaTypes = {
2102
- method: 'GET',
2103
- url: 'https://openx-d.openx.net/v/1.0/avjp',
2104
- data: {},
2105
- payload: {'bid': bidsWithMediaTypes[0], 'startTime': new Date()}
2106
- };
2107
- const bidRequestsWithMediaType = {
2108
- method: 'GET',
2109
- url: 'https://openx-d.openx.net/v/1.0/avjp',
2110
- data: {},
2111
- payload: {'bid': bidsWithMediaType[0], 'startTime': new Date()}
2112
- };
2113
- const bidResponse = {
2114
- 'pub_rev': '1000',
2115
- 'width': '640',
2116
- 'height': '480',
2117
- 'adid': '5678',
2118
- 'currency': 'AUD',
2119
- 'vastUrl': 'https://testvast.com',
2120
- 'pixels': 'https://testpixels.net'
2121
- };
1380
+ if (FEATURES.VIDEO) {
1381
+ context('when the response is a video', function() {
1382
+ beforeEach(function () {
1383
+ bidRequestConfigs = [{
1384
+ bidder: 'openx',
1385
+ params: {
1386
+ unit: '12345678',
1387
+ delDomain: 'test-del-domain'
1388
+ },
1389
+ adUnitCode: 'adunit-code',
1390
+ mediaTypes: {
1391
+ video: {
1392
+ playerSize: [[640, 360], [854, 480]],
1393
+ },
1394
+ },
1395
+ bidId: 'test-bid-id',
1396
+ bidderRequestId: 'test-bidder-request-id',
1397
+ auctionId: 'test-auction-id'
1398
+ }];
1399
+
1400
+ bidRequest = spec.buildRequests(bidRequestConfigs, {refererInfo: {}})[0];
1401
+
1402
+ bidResponse = {
1403
+ seatbid: [{
1404
+ bid: [{
1405
+ impid: 'test-bid-id',
1406
+ price: 2,
1407
+ w: 854,
1408
+ h: 480,
1409
+ crid: 'test-creative-id',
1410
+ dealid: 'test-deal-id',
1411
+ adm: 'test-ad-markup',
1412
+ }]
1413
+ }],
1414
+ cur: 'AUS'
1415
+ };
1416
+ });
2122
1417
 
2123
- it('should return correct bid response with MediaTypes', function () {
2124
- const expectedResponse = {
2125
- 'requestId': '30b31c1838de1e',
2126
- 'cpm': 1,
2127
- 'width': 640,
2128
- 'height': 480,
2129
- 'mediaType': 'video',
2130
- 'creativeId': '5678',
2131
- 'vastUrl': 'https://testvast.com',
2132
- 'ttl': 300,
2133
- 'netRevenue': true,
2134
- 'currency': 'AUD'
2135
- };
2136
-
2137
- const result = spec.interpretResponse({body: bidResponse}, bidRequestsWithMediaTypes);
2138
- expect(result[0]).to.eql(expectedResponse);
2139
- });
1418
+ it('should return the proper mediaType', function () {
1419
+ bid = spec.interpretResponse({body: bidResponse}, bidRequest)[0];
1420
+ expect(bid.mediaType).to.equal(Object.keys(bidRequestConfigs[0].mediaTypes)[0]);
1421
+ });
2140
1422
 
2141
- it('should return correct bid response with MediaType', function () {
2142
- const expectedResponse = [
2143
- {
2144
- 'requestId': '30b31c1838de1e',
2145
- 'cpm': 1,
2146
- 'width': '640',
2147
- 'height': '480',
2148
- 'mediaType': 'video',
2149
- 'creativeId': '5678',
2150
- 'vastUrl': 'https://testvast.com',
2151
- 'ttl': 300,
2152
- 'netRevenue': true,
2153
- 'currency': 'USD'
2154
- }
2155
- ];
1423
+ it('should return the proper mediaType', function () {
1424
+ const winUrl = 'https//my.win.url';
1425
+ bidResponse.seatbid[0].bid[0].nurl = winUrl
1426
+ bid = spec.interpretResponse({body: bidResponse}, bidRequest)[0];
2156
1427
 
2157
- const result = spec.interpretResponse({body: bidResponse}, bidRequestsWithMediaType);
2158
- expect(JSON.stringify(Object.keys(result[0]).sort())).to.eql(JSON.stringify(Object.keys(expectedResponse[0]).sort()));
2159
- });
1428
+ expect(bid.vastUrl).to.equal(winUrl);
1429
+ });
1430
+ });
1431
+ }
2160
1432
 
2161
- it('should return correct bid response with MediaType and deal_id', function () {
2162
- const bidResponseOverride = { 'deal_id': 'OX-mydeal' };
2163
- const bidResponseWithDealId = Object.assign({}, bidResponse, bidResponseOverride);
2164
- const result = spec.interpretResponse({body: bidResponseWithDealId}, bidRequestsWithMediaType);
2165
- expect(result[0].dealId).to.equal(bidResponseOverride.deal_id);
2166
- });
1433
+ context('when the response contains FLEDGE interest groups config', function() {
1434
+ let response;
2167
1435
 
2168
- it('should handle nobid responses for bidRequests with MediaTypes', function () {
2169
- const bidResponse = {'vastUrl': '', 'pub_rev': '', 'width': '', 'height': '', 'adid': '', 'pixels': ''};
2170
- const result = spec.interpretResponse({body: bidResponse}, bidRequestsWithMediaTypes);
2171
- expect(result.length).to.equal(0);
2172
- });
1436
+ beforeEach(function () {
1437
+ sinon.stub(config, 'getConfig')
1438
+ .withArgs('fledgeEnabled')
1439
+ .returns(true);
2173
1440
 
2174
- it('should handle nobid responses for bidRequests with MediaType', function () {
2175
- const bidResponse = {'vastUrl': '', 'pub_rev': '', 'width': '', 'height': '', 'adid': '', 'pixels': ''};
2176
- const result = spec.interpretResponse({body: bidResponse}, bidRequestsWithMediaType);
2177
- expect(result.length).to.equal(0);
2178
- });
2179
- });
1441
+ bidRequestConfigs = [{
1442
+ bidder: 'openx',
1443
+ params: {
1444
+ unit: '12345678',
1445
+ delDomain: 'test-del-domain'
1446
+ },
1447
+ adUnitCode: 'adunit-code',
1448
+ mediaTypes: {
1449
+ banner: {
1450
+ sizes: [[300, 250], [300, 600]],
1451
+ },
1452
+ },
1453
+ bidId: 'test-bid-id',
1454
+ bidderRequestId: 'test-bidder-request-id',
1455
+ auctionId: 'test-auction-id'
1456
+ }];
2180
1457
 
2181
- describe('user sync', function () {
2182
- const syncUrl = 'https://testpixels.net';
1458
+ bidRequest = spec.buildRequests(bidRequestConfigs, {refererInfo: {}})[0];
1459
+
1460
+ bidResponse = {
1461
+ seatbid: [{
1462
+ bid: [{
1463
+ impid: 'test-bid-id',
1464
+ price: 2,
1465
+ w: 300,
1466
+ h: 250,
1467
+ crid: 'test-creative-id',
1468
+ dealid: 'test-deal-id',
1469
+ adm: 'test-ad-markup'
1470
+ }]
1471
+ }],
1472
+ cur: 'AUS',
1473
+ ext: {
1474
+ fledge_auction_configs: {
1475
+ 'test-bid-id': {
1476
+ seller: 'codinginadtech.com',
1477
+ interestGroupBuyers: ['somedomain.com'],
1478
+ sellerTimeout: 0,
1479
+ perBuyerSignals: {
1480
+ 'somedomain.com': {
1481
+ base_bid_micros: 0.1,
1482
+ disallowed_advertiser_ids: [
1483
+ '1234',
1484
+ '2345'
1485
+ ],
1486
+ multiplier: 1.3,
1487
+ use_bid_multiplier: true,
1488
+ win_reporting_id: '1234567asdf'
1489
+ }
1490
+ }
1491
+ }
1492
+ }
1493
+ }
1494
+ };
2183
1495
 
2184
- describe('iframe sync', function () {
2185
- it('should register the pixel iframe from banner ad response', function () {
2186
- let syncs = spec.getUserSyncs(
2187
- {iframeEnabled: true},
2188
- [{body: {ads: {pixels: syncUrl}}}]
2189
- );
2190
- expect(syncs).to.deep.equal([{type: 'iframe', url: syncUrl}]);
1496
+ response = spec.interpretResponse({body: bidResponse}, bidRequest);
2191
1497
  });
2192
1498
 
2193
- it('should register the pixel iframe from video ad response', function () {
2194
- let syncs = spec.getUserSyncs(
2195
- {iframeEnabled: true},
2196
- [{body: {pixels: syncUrl}}]
2197
- );
2198
- expect(syncs).to.deep.equal([{type: 'iframe', url: syncUrl}]);
1499
+ afterEach(function () {
1500
+ config.getConfig.restore();
2199
1501
  });
2200
1502
 
2201
- it('should register the default iframe if no pixels available', function () {
2202
- let syncs = spec.getUserSyncs(
2203
- {iframeEnabled: true},
2204
- []
2205
- );
2206
- expect(syncs).to.deep.equal([{type: 'iframe', url: 'https://u.openx.net/w/1.0/pd'}]);
1503
+ it('should return FLEDGE auction_configs alongside bids', function () {
1504
+ expect(response).to.have.property('bids');
1505
+ expect(response).to.have.property('fledgeAuctionConfigs');
1506
+ expect(response.fledgeAuctionConfigs.length).to.equal(1);
1507
+ expect(response.fledgeAuctionConfigs[0].bidId).to.equal('test-bid-id');
2207
1508
  });
2208
1509
  });
1510
+ });
2209
1511
 
2210
- describe('pixel sync', function () {
2211
- it('should register the image pixel from banner ad response', function () {
2212
- let syncs = spec.getUserSyncs(
2213
- {pixelEnabled: true},
2214
- [{body: {ads: {pixels: syncUrl}}}]
2215
- );
2216
- expect(syncs).to.deep.equal([{type: 'image', url: syncUrl}]);
2217
- });
1512
+ describe('user sync', function () {
1513
+ it('should register the default image pixel if no pixels available', function () {
1514
+ let syncs = spec.getUserSyncs(
1515
+ {pixelEnabled: true},
1516
+ []
1517
+ );
1518
+ expect(syncs).to.deep.equal([{type: 'image', url: DEFAULT_SYNC}]);
1519
+ });
2218
1520
 
2219
- it('should register the image pixel from video ad response', function () {
2220
- let syncs = spec.getUserSyncs(
2221
- {pixelEnabled: true},
2222
- [{body: {pixels: syncUrl}}]
2223
- );
2224
- expect(syncs).to.deep.equal([{type: 'image', url: syncUrl}]);
2225
- });
1521
+ it('should register custom syncUrl when exists', function () {
1522
+ let syncs = spec.getUserSyncs(
1523
+ {pixelEnabled: true},
1524
+ [{body: {ext: {delDomain: 'www.url.com'}}}]
1525
+ );
1526
+ expect(syncs).to.deep.equal([{type: 'image', url: 'https://www.url.com/w/1.0/pd'}]);
1527
+ });
2226
1528
 
2227
- it('should register the default image pixel if no pixels available', function () {
2228
- let syncs = spec.getUserSyncs(
2229
- {pixelEnabled: true},
2230
- []
2231
- );
2232
- expect(syncs).to.deep.equal([{type: 'image', url: 'https://u.openx.net/w/1.0/pd'}]);
2233
- });
1529
+ it('should register custom syncUrl when exists', function () {
1530
+ let syncs = spec.getUserSyncs(
1531
+ {pixelEnabled: true},
1532
+ [{body: {ext: {platform: 'abc'}}}]
1533
+ );
1534
+ expect(syncs).to.deep.equal([{type: 'image', url: SYNC_URL + '?ph=abc'}]);
1535
+ });
1536
+
1537
+ it('when iframe sync is allowed, it should register an iframe sync', function () {
1538
+ let syncs = spec.getUserSyncs(
1539
+ {iframeEnabled: true},
1540
+ []
1541
+ );
1542
+ expect(syncs).to.deep.equal([{type: 'iframe', url: DEFAULT_SYNC}]);
2234
1543
  });
2235
1544
 
2236
1545
  it('should prioritize iframe over image for user sync', function () {
2237
1546
  let syncs = spec.getUserSyncs(
2238
1547
  {iframeEnabled: true, pixelEnabled: true},
2239
- [{body: {ads: {pixels: syncUrl}}}]
1548
+ []
2240
1549
  );
2241
- expect(syncs).to.deep.equal([{type: 'iframe', url: syncUrl}]);
1550
+ expect(syncs).to.deep.equal([{type: 'iframe', url: DEFAULT_SYNC}]);
2242
1551
  });
2243
1552
 
2244
1553
  describe('when gdpr applies', function () {
2245
1554
  let gdprConsent;
2246
1555
  let gdprPixelUrl;
1556
+ const consentString = 'gdpr-pixel-consent';
1557
+ const gdprApplies = '1';
2247
1558
  beforeEach(() => {
2248
1559
  gdprConsent = {
2249
- consentString: 'test-gdpr-consent-string',
1560
+ consentString,
2250
1561
  gdprApplies: true
2251
1562
  };
2252
1563
 
2253
- gdprPixelUrl = 'https://testpixels.net?gdpr=1&gdpr_consent=gdpr-pixel-consent'
1564
+ gdprPixelUrl = `${SYNC_URL}&gdpr=${gdprApplies}&gdpr_consent=${consentString}`;
2254
1565
  });
2255
1566
 
2256
1567
  it('when there is a response, it should have the gdpr query params', () => {
2257
- let [{url}] = spec.getUserSyncs(
2258
- {iframeEnabled: true, pixelEnabled: true},
2259
- [{body: {ads: {pixels: gdprPixelUrl}}}],
2260
- gdprConsent
2261
- );
2262
-
2263
- expect(url).to.have.string('gdpr_consent=gdpr-pixel-consent');
2264
- expect(url).to.have.string('gdpr=1');
2265
- });
2266
-
2267
- it('when there is no response, it should append gdpr query params', () => {
2268
1568
  let [{url}] = spec.getUserSyncs(
2269
1569
  {iframeEnabled: true, pixelEnabled: true},
2270
1570
  [],
2271
1571
  gdprConsent
2272
1572
  );
2273
- expect(url).to.have.string('gdpr_consent=test-gdpr-consent-string');
2274
- expect(url).to.have.string('gdpr=1');
1573
+
1574
+ expect(url).to.have.string(`gdpr_consent=${consentString}`);
1575
+ expect(url).to.have.string(`gdpr=${gdprApplies}`);
2275
1576
  });
2276
1577
 
2277
1578
  it('should not send signals if no consent object is available', function () {
@@ -2287,28 +1588,19 @@ describe('OpenxAdapter', function () {
2287
1588
  describe('when ccpa applies', function () {
2288
1589
  let usPrivacyConsent;
2289
1590
  let uspPixelUrl;
1591
+ const privacyString = 'TEST';
2290
1592
  beforeEach(() => {
2291
1593
  usPrivacyConsent = 'TEST';
2292
- uspPixelUrl = 'https://testpixels.net?us_privacy=AAAA'
1594
+ uspPixelUrl = `${DEFAULT_SYNC}&us_privacy=${privacyString}`
2293
1595
  });
2294
- it('when there is a response, it should send the us privacy string from the response, ', () => {
2295
- let [{url}] = spec.getUserSyncs(
2296
- {iframeEnabled: true, pixelEnabled: true},
2297
- [{body: {ads: {pixels: uspPixelUrl}}}],
2298
- undefined,
2299
- usPrivacyConsent
2300
- );
2301
-
2302
- expect(url).to.have.string('us_privacy=AAAA');
2303
- });
2304
- it('when there is no response, it send have the us privacy string', () => {
1596
+ it('should send the us privacy string, ', () => {
2305
1597
  let [{url}] = spec.getUserSyncs(
2306
1598
  {iframeEnabled: true, pixelEnabled: true},
2307
1599
  [],
2308
1600
  undefined,
2309
1601
  usPrivacyConsent
2310
1602
  );
2311
- expect(url).to.have.string(`us_privacy=${usPrivacyConsent}`);
1603
+ expect(url).to.have.string(`us_privacy=${privacyString}`);
2312
1604
  });
2313
1605
 
2314
1606
  it('should not send signals if no consent string is available', function () {
@@ -2320,75 +1612,4 @@ describe('OpenxAdapter', function () {
2320
1612
  });
2321
1613
  });
2322
1614
  });
2323
-
2324
- /**
2325
- * Makes sure the override object does not introduce
2326
- * new fields against the contract
2327
- *
2328
- * This does a shallow check in order to make key checking simple
2329
- * with respect to what a helper handles. For helpers that have
2330
- * nested fields, either check your design on maybe breaking it up
2331
- * to smaller, manageable pieces
2332
- *
2333
- * OR just call this on your nth level field if necessary.
2334
- *
2335
- * @param {Object} override Object with keys that overrides the default
2336
- * @param {Object} contract Original object contains the default fields
2337
- * @param {string} typeName Name of the type we're checking for error messages
2338
- * @throws {AssertionError}
2339
- */
2340
- function overrideKeyCheck(override, contract, typeName) {
2341
- expect(contract).to.include.all.keys(Object.keys(override));
2342
- }
2343
-
2344
- /**
2345
- * Creates a mock ArjResponse
2346
- * @param {OxArjResponse=} response
2347
- * @param {Array<OxArjAdUnit>=} adUnits
2348
- * @throws {AssertionError}
2349
- * @return {OxArjResponse}
2350
- */
2351
- function mockArjResponse(response, adUnits = []) {
2352
- let mockedArjResponse = utils.deepClone(DEFAULT_ARJ_RESPONSE);
2353
-
2354
- if (response) {
2355
- overrideKeyCheck(response, DEFAULT_ARJ_RESPONSE, 'OxArjResponse');
2356
- overrideKeyCheck(response.ads, DEFAULT_ARJ_RESPONSE.ads, 'OxArjResponse');
2357
- Object.assign(mockedArjResponse, response);
2358
- }
2359
-
2360
- if (adUnits.length) {
2361
- mockedArjResponse.ads.count = adUnits.length;
2362
- mockedArjResponse.ads.ad = adUnits.map((adUnit) => {
2363
- overrideKeyCheck(adUnit, DEFAULT_TEST_ARJ_AD_UNIT, 'OxArjAdUnit');
2364
- return Object.assign(utils.deepClone(DEFAULT_TEST_ARJ_AD_UNIT), adUnit);
2365
- });
2366
- }
2367
-
2368
- return mockedArjResponse;
2369
- }
2370
-
2371
- /**
2372
- * Creates a mock ArjAdUnit
2373
- * @param {OxArjAdUnit=} adUnit
2374
- * @param {OxArjCreative=} creative
2375
- * @throws {AssertionError}
2376
- * @return {OxArjAdUnit}
2377
- */
2378
- function mockAdUnit(adUnit, creative) {
2379
- overrideKeyCheck(adUnit, DEFAULT_TEST_ARJ_AD_UNIT, 'OxArjAdUnit');
2380
-
2381
- let mockedAdUnit = Object.assign(utils.deepClone(DEFAULT_TEST_ARJ_AD_UNIT), adUnit);
2382
-
2383
- if (creative) {
2384
- overrideKeyCheck(creative, DEFAULT_TEST_ARJ_CREATIVE);
2385
- if (creative.tracking) {
2386
- overrideKeyCheck(creative.tracking, DEFAULT_TEST_ARJ_CREATIVE.tracking, 'OxArjCreative');
2387
- }
2388
- Object.assign(mockedAdUnit.creative[0], creative);
2389
- }
2390
-
2391
- return mockedAdUnit;
2392
- }
2393
- })
2394
- ;
1615
+ });