prebid.js 9.53.1 → 9.53.2

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 (185) hide show
  1. package/dist/33acrossAnalyticsAdapter.js +1 -1
  2. package/dist/33acrossBidAdapter.js +1 -1
  3. package/dist/33acrossIdSystem.js +1 -1
  4. package/dist/BTBidAdapter.js +1 -1
  5. package/dist/adagioAnalyticsAdapter.js +1 -1
  6. package/dist/adagioBidAdapter.js +1 -1
  7. package/dist/adagioUtils.js +1 -1
  8. package/dist/addefendBidAdapter.js +1 -1
  9. package/dist/adgenerationBidAdapter.js +1 -1
  10. package/dist/adlooxRtdProvider.js +1 -1
  11. package/dist/adqueryBidAdapter.js +1 -1
  12. package/dist/adrelevantisBidAdapter.js +1 -1
  13. package/dist/adstirBidAdapter.js +1 -1
  14. package/dist/adtrgtmeBidAdapter.js +1 -1
  15. package/dist/adxcgAnalyticsAdapter.js +1 -1
  16. package/dist/adxcgBidAdapter.js +1 -1
  17. package/dist/adyoulikeBidAdapter.js +1 -1
  18. package/dist/agmaAnalyticsAdapter.js +1 -1
  19. package/dist/ajaBidAdapter.js +1 -1
  20. package/dist/amxBidAdapter.js +1 -1
  21. package/dist/amxIdSystem.js +1 -1
  22. package/dist/aniviewBidAdapter.js +1 -1
  23. package/dist/appierAnalyticsAdapter.js +1 -1
  24. package/dist/appnexusBidAdapter.js +1 -1
  25. package/dist/asoBidAdapter.js +1 -1
  26. package/dist/axonixBidAdapter.js +1 -1
  27. package/dist/beopBidAdapter.js +1 -1
  28. package/dist/bidglassBidAdapter.js +1 -1
  29. package/dist/big-richmediaBidAdapter.js +1 -1
  30. package/dist/bitmediaBidAdapter.js +1 -1
  31. package/dist/bridBidAdapter.js +1 -1
  32. package/dist/bridgeuppBidAdapter.js +1 -1
  33. package/dist/bridgewellBidAdapter.js +1 -1
  34. package/dist/brightMountainMediaBidAdapter.js +1 -1
  35. package/dist/carodaBidAdapter.js +1 -1
  36. package/dist/chtnwBidAdapter.js +1 -1
  37. package/dist/chunk-core.js +1 -1
  38. package/dist/concertBidAdapter.js +1 -1
  39. package/dist/connectadBidAdapter.js +1 -1
  40. package/dist/consumableBidAdapter.js +1 -1
  41. package/dist/contxtfulBidAdapter.js +1 -1
  42. package/dist/conversantAnalyticsAdapter.js +1 -1
  43. package/dist/conversantBidAdapter.js +1 -1
  44. package/dist/craftBidAdapter.js +1 -1
  45. package/dist/criteoBidAdapter.js +1 -1
  46. package/dist/cwireBidAdapter.js +1 -1
  47. package/dist/dailymotionBidAdapter.js +1 -1
  48. package/dist/dependencies.json +6 -1
  49. package/dist/dspxBidAdapter.js +1 -1
  50. package/dist/dxkultureBidAdapter.js +1 -1
  51. package/dist/eplanningBidAdapter.js +1 -1
  52. package/dist/equativBidAdapter.js +1 -1
  53. package/dist/eskimiBidAdapter.js +1 -1
  54. package/dist/euidIdSystem.js +1 -1
  55. package/dist/exadsBidAdapter.js +1 -1
  56. package/dist/excoBidAdapter.js +1 -1
  57. package/dist/fanAdapter.js +1 -1
  58. package/dist/feedadBidAdapter.js +1 -1
  59. package/dist/finativeBidAdapter.js +1 -1
  60. package/dist/freewheel-sspBidAdapter.js +1 -1
  61. package/dist/gmosspBidAdapter.js +1 -1
  62. package/dist/greenbidsAnalyticsAdapter.js +1 -1
  63. package/dist/greenbidsBidAdapter.js +1 -1
  64. package/dist/greenbidsRtdProvider.js +1 -1
  65. package/dist/gridBidAdapter.js +1 -1
  66. package/dist/gumgumBidAdapter.js +1 -1
  67. package/dist/h12mediaBidAdapter.js +1 -1
  68. package/dist/hypelabBidAdapter.js +1 -1
  69. package/dist/id5AnalyticsAdapter.js +1 -1
  70. package/dist/id5IdSystem.js +1 -1
  71. package/dist/imdsBidAdapter.js +1 -1
  72. package/dist/improvedigitalBidAdapter.js +1 -1
  73. package/dist/inmobiBidAdapter.js +1 -1
  74. package/dist/insticatorBidAdapter.js +1 -1
  75. package/dist/intentIqAnalyticsAdapter.js +1 -1
  76. package/dist/ixBidAdapter.js +1 -1
  77. package/dist/jixieBidAdapter.js +1 -1
  78. package/dist/justpremiumBidAdapter.js +1 -1
  79. package/dist/kargoBidAdapter.js +1 -1
  80. package/dist/kimberliteBidAdapter.js +1 -1
  81. package/dist/konduitAnalyticsAdapter.js +1 -1
  82. package/dist/kueezBidAdapter.js +1 -1
  83. package/dist/lassoBidAdapter.js +1 -1
  84. package/dist/lifestreetBidAdapter.js +1 -1
  85. package/dist/liveIntentId.js +1 -1
  86. package/dist/logicadBidAdapter.js +1 -1
  87. package/dist/loglyliftBidAdapter.js +1 -1
  88. package/dist/luceadBidAdapter.js +1 -1
  89. package/dist/mabidderBidAdapter.js +1 -1
  90. package/dist/madsenseBidAdapter.js +1 -1
  91. package/dist/magniteAnalyticsAdapter.js +1 -1
  92. package/dist/malltvAnalyticsAdapter.js +1 -1
  93. package/dist/marsmediaBidAdapter.js +1 -1
  94. package/dist/mediafuseBidAdapter.js +1 -1
  95. package/dist/medianetBidAdapter.js +1 -1
  96. package/dist/medianetUtils.js +1 -1
  97. package/dist/mediasquareBidAdapter.js +1 -1
  98. package/dist/mgidBidAdapter.js +1 -1
  99. package/dist/missenaBidAdapter.js +1 -1
  100. package/dist/mobilefuseBidAdapter.js +1 -1
  101. package/dist/nextMillenniumBidAdapter.js +1 -1
  102. package/dist/nexx360Utils.js +1 -1
  103. package/dist/nobidAnalyticsAdapter.js +1 -1
  104. package/dist/nobidBidAdapter.js +1 -1
  105. package/dist/nodalsAiRtdProvider.js +1 -1
  106. package/dist/not-for-prod/prebid.js +168 -168
  107. package/dist/oguryBidAdapter.js +1 -1
  108. package/dist/onetagBidAdapter.js +1 -1
  109. package/dist/ooloAnalyticsAdapter.js +1 -1
  110. package/dist/openxBidAdapter.js +1 -1
  111. package/dist/optidigitalBidAdapter.js +1 -1
  112. package/dist/orbidderBidAdapter.js +1 -1
  113. package/dist/outbrainBidAdapter.js +1 -1
  114. package/dist/pixfutureBidAdapter.js +1 -1
  115. package/dist/publinkIdSystem.js +1 -1
  116. package/dist/pubmaticAnalyticsAdapter.js +1 -1
  117. package/dist/pubmaticBidAdapter.js +1 -1
  118. package/dist/pubwiseAnalyticsAdapter.js +1 -1
  119. package/dist/pubxaiAnalyticsAdapter.js +1 -1
  120. package/dist/pxyzBidAdapter.js +1 -1
  121. package/dist/quantcastBidAdapter.js +1 -1
  122. package/dist/readpeakBidAdapter.js +1 -1
  123. package/dist/relaidoBidAdapter.js +1 -1
  124. package/dist/retailspotBidAdapter.js +1 -1
  125. package/dist/rhythmoneBidAdapter.js +1 -1
  126. package/dist/riseUtils.js +1 -1
  127. package/dist/rubiconBidAdapter.js +1 -1
  128. package/dist/seedingAllianceBidAdapter.js +1 -1
  129. package/dist/seedtagBidAdapter.js +1 -1
  130. package/dist/sharethroughAnalyticsAdapter.js +1 -1
  131. package/dist/sharethroughBidAdapter.js +1 -1
  132. package/dist/showheroes-bsBidAdapter.js +1 -1
  133. package/dist/smaatoBidAdapter.js +1 -1
  134. package/dist/smartadserverBidAdapter.js +1 -1
  135. package/dist/smartxBidAdapter.js +1 -1
  136. package/dist/smilewantedBidAdapter.js +1 -1
  137. package/dist/snigelBidAdapter.js +1 -1
  138. package/dist/sonobiBidAdapter.js +1 -1
  139. package/dist/sovrnBidAdapter.js +1 -1
  140. package/dist/sparteoBidAdapter.js +1 -1
  141. package/dist/sspBCBidAdapter.js +1 -1
  142. package/dist/stvBidAdapter.js +1 -1
  143. package/dist/sublimeBidAdapter.js +1 -1
  144. package/dist/taboolaBidAdapter.js +1 -1
  145. package/dist/tappxBidAdapter.js +1 -1
  146. package/dist/targetVideoBidAdapter.js +1 -1
  147. package/dist/teadsBidAdapter.js +1 -1
  148. package/dist/terceptAnalyticsAdapter.js +1 -1
  149. package/dist/themoneytizerBidAdapter.js +1 -1
  150. package/dist/trionBidAdapter.js +1 -1
  151. package/dist/tripleliftBidAdapter.js +1 -1
  152. package/dist/ttdBidAdapter.js +1 -1
  153. package/dist/ucfunnelAnalyticsAdapter.js +1 -1
  154. package/dist/uid2IdSystem.js +1 -1
  155. package/dist/underdogmediaBidAdapter.js +1 -1
  156. package/dist/undertoneBidAdapter.js +1 -1
  157. package/dist/unrulyBidAdapter.js +1 -1
  158. package/dist/userId.js +1 -1
  159. package/dist/vidazooUtils.js +1 -1
  160. package/dist/videobyteBidAdapter.js +1 -1
  161. package/dist/visxBidAdapter.js +1 -1
  162. package/dist/vuukleBidAdapter.js +1 -1
  163. package/dist/widespaceBidAdapter.js +1 -1
  164. package/dist/winrBidAdapter.js +1 -1
  165. package/dist/yahooAdsBidAdapter.js +1 -1
  166. package/dist/yandexBidAdapter.js +1 -1
  167. package/dist/yieldmoBidAdapter.js +1 -1
  168. package/dist/yieldoneAnalyticsAdapter.js +1 -1
  169. package/libraries/liveIntentId/shared.js +16 -0
  170. package/modules/fanAdapter.js +318 -124
  171. package/modules/userId/index.js +30 -31
  172. package/package.json +4 -4
  173. package/test/spec/modules/euidIdSystem_spec.js +9 -3
  174. package/test/spec/modules/fanAdapter_spec.js +264 -268
  175. package/test/spec/modules/id5IdSystem_spec.js +57 -101
  176. package/test/spec/modules/idxIdSystem_spec.js +2 -75
  177. package/test/spec/modules/liveIntentExternalIdSystem_spec.js +5 -0
  178. package/test/spec/modules/liveIntentIdMinimalSystem_spec.js +5 -0
  179. package/test/spec/modules/liveIntentIdSystem_spec.js +38 -0
  180. package/test/spec/modules/lmpIdSystem_spec.js +2 -81
  181. package/test/spec/modules/pubmaticBidAdapter_spec.js +411 -126
  182. package/test/spec/modules/sharedIdSystem_spec.js +3 -3
  183. package/test/spec/modules/uid2IdSystem_helpers.js +5 -2
  184. package/test/spec/modules/userId_spec.js +142 -387
  185. package/test/spec/modules/zeotapIdPlusIdSystem_spec.js +3 -69
@@ -1,315 +1,311 @@
1
- import * as ajax from 'src/ajax.js';
2
- import { expect } from 'chai';
3
1
  import { spec } from 'modules/fanAdapter.js';
4
- import { newBidder } from 'src/adapters/bidderFactory.js';
5
- import { BANNER, NATIVE } from 'src/mediaTypes.js';
2
+ import { BANNER, VIDEO } from 'src/mediaTypes.js';
3
+ import * as utils from 'src/utils.js';
4
+ import { config } from 'src/config.js';
5
+ import { expect } from 'chai';
6
+ import sinon from 'sinon';
7
+
8
+ describe('freedomadnetworkAdapter', function() {
9
+ const BIDDER_CODE = 'freedomadnetwork';
10
+ const DEFAULT_CURRENCY = 'USD';
11
+ const DEFAULT_TTL = 300;
12
+
13
+ let validBidRequestBanner;
14
+ let validBidRequestVideo;
15
+ let bidderRequest;
16
+
17
+ beforeEach(function() {
18
+ // A minimal valid banner bid request
19
+ validBidRequestBanner = {
20
+ bidder: BIDDER_CODE,
21
+ params: {
22
+ placementId: 'placement123',
23
+ network: 'test'
24
+ },
25
+ mediaTypes: {
26
+ banner: {
27
+ sizes: [[300, 250]]
28
+ }
29
+ },
30
+ adUnitCode: 'adunit-code-banner',
31
+ auctionId: 'auction-1',
32
+ bidId: 'bid-1',
33
+ bidderRequestId: 'br-1',
34
+ auctionStart: Date.now()
35
+ };
36
+
37
+ // A minimal valid video bid request
38
+ validBidRequestVideo = {
39
+ bidder: BIDDER_CODE,
40
+ params: {
41
+ placementId: 'placementVideo',
42
+ network: 'fan',
43
+ bidFloor: 1.5,
44
+ bidFloorCur: 'USD'
45
+ },
46
+ mediaTypes: {
47
+ video: {
48
+ mimes: ['video/mp4'],
49
+ playerSize: [[640, 480]]
50
+ }
51
+ },
52
+ adUnitCode: 'adunit-code-video',
53
+ auctionId: 'auction-2',
54
+ bidId: 'bid-2',
55
+ bidderRequestId: 'br-2',
56
+ auctionStart: Date.now()
57
+ };
6
58
 
7
- describe('Freedom Ad Network Bid Adapter', function () {
8
- describe('Test isBidRequestValid', function () {
9
- it('undefined bid should return false', function () {
10
- expect(spec.isBidRequestValid()).to.be.false;
59
+ // Stub bidderRequest used by buildRequests
60
+ bidderRequest = {
61
+ refererInfo: { referer: 'http://example.com' },
62
+ auctionId: 'auction-1',
63
+ timeout: 3000,
64
+ gdprConsent: null,
65
+ uspConsent: null,
66
+ gppConsent: null
67
+ };
68
+
69
+ // Reset any config overrides
70
+ config.setConfig({});
71
+ });
72
+
73
+ describe('isBidRequestValid', function() {
74
+ it('should return true when required params for banner are present', function() {
75
+ expect(spec.isBidRequestValid(validBidRequestBanner)).to.be.true;
11
76
  });
12
77
 
13
- it('null bid should return false', function () {
14
- expect(spec.isBidRequestValid(null)).to.be.false;
78
+ it('should return true when required params for video are present', function() {
79
+ expect(spec.isBidRequestValid(validBidRequestVideo)).to.be.true;
15
80
  });
16
81
 
17
- it('bid.params should be set', function () {
18
- expect(spec.isBidRequestValid({})).to.be.false;
82
+ it('should return false when params object is missing', function() {
83
+ const bid = Object.assign({}, validBidRequestBanner, { params: null });
84
+ expect(spec.isBidRequestValid(bid)).to.be.false;
19
85
  });
20
86
 
21
- it('bid.params.placementId should be set', function () {
22
- expect(spec.isBidRequestValid({
23
- params: { foo: 'bar' }
24
- })).to.be.false;
87
+ it('should return false when placementId is missing', function() {
88
+ const bid = Object.assign({}, validBidRequestBanner, { params: {} });
89
+ expect(spec.isBidRequestValid(bid)).to.be.false;
25
90
  });
26
91
 
27
- it('valid bid should return true', function () {
28
- expect(spec.isBidRequestValid({
29
- mediaTypes: {
30
- [BANNER]: {
31
- sizes: [[300, 250]]
32
- }
33
- },
92
+ it('should return false when network param is invalid', function() {
93
+ const bid = Object.assign({}, validBidRequestBanner, {
34
94
  params: {
35
- placementId: 'e6203f1e-bd6d-4f42-9895-d1a19cdb83c8'
95
+ placementId: 'placement123',
96
+ network: 'invalidNetwork'
36
97
  }
37
- })).to.be.true;
98
+ });
99
+ expect(spec.isBidRequestValid(bid)).to.be.false;
38
100
  });
39
- });
40
-
41
- describe('Test buildRequests', function () {
42
- const bidderRequest = {
43
- auctionId: 'b06c5141-fe8f-4cdf-9d7d-54415490a917',
44
- auctionStart: Date.now(),
45
- bidderCode: 'myBidderCode',
46
- bidderRequestId: '15246a574e859f',
47
- refererInfo: {
48
- page: 'http://example.com',
49
- stack: ['http://example.com']
50
- },
51
- gdprConsent: {
52
- gdprApplies: true,
53
- consentString: 'IwuyYwpjmnsauyYasIUWwe'
54
- },
55
- uspConsent: 'Oush3@jmUw82has',
56
- timeout: 3000
57
- };
58
101
 
59
- it('build request object', function () {
60
- const bidRequests = [
61
- {
62
- adUnitCode: 'test-div',
63
- auctionId: 'b06c5141-fe8f-4cdf-9d7d-54415490a917',
64
- bidId: '8064026a1776',
65
- bidder: 'freedomadnetwork',
66
- bidderRequestId: '15246a574e859f',
67
- mediaTypes: {
68
- banner: { sizes: [[300, 250]] }
69
- },
70
- params: {
71
- placementId: 'e6203f1e-bd6d-4f42-9895-d1a19cdb83c8'
72
- }
73
- },
74
- {
75
- adUnitCode: 'test-native',
76
- auctionId: 'b06c5141-fe8f-4cdf-9d7d-54415490a917',
77
- bidId: '8064026a1777',
78
- bidder: 'freedomadnetwork',
79
- bidderRequestId: '15246a574e859f',
80
- mediaTypes: {
81
- native: {
82
- title: {
83
- required: true,
84
- len: 20,
85
- },
86
- image: {
87
- required: true,
88
- sizes: [300, 250],
89
- aspect_ratios: [{
90
- ratio_width: 1,
91
- ratio_height: 1
92
- }]
93
- },
94
- icon: {
95
- required: true,
96
- sizes: [60, 60],
97
- aspect_ratios: [{
98
- ratio_width: 1,
99
- ratio_height: 1
100
- }]
101
- },
102
- sponsoredBy: {
103
- required: true,
104
- len: 20
105
- },
106
- body: {
107
- required: true,
108
- len: 140
109
- },
110
- cta: {
111
- required: true,
112
- len: 20,
113
- }
114
- }
115
- },
116
- params: {
117
- placementId: '3f50a79e-5582-4e5c-b1f4-9dcc1c82cece'
118
- }
119
- },
120
- {
121
- adUnitCode: 'test-native2',
122
- auctionId: 'b06c5141-fe8f-4cdf-9d7d-54415490a917',
123
- bidId: '8064026a1778',
124
- bidder: 'freedomadnetwork',
125
- bidderRequestId: '15246a574e859f',
126
- mediaTypes: {
127
- native: {
128
- title: {},
129
- image: {},
130
- icon: {},
131
- sponsoredBy: {},
132
- body: {},
133
- cta: {}
134
- }
135
- },
136
- params: {
137
- placementId: '2015defc-19db-4cf6-926d-d2d0d32122fa',
138
- }
139
- },
140
- {
141
- adUnitCode: 'test-native3',
142
- auctionId: 'b06c5141-fe8f-4cdf-9d7d-54415490a917',
143
- bidId: '8064026a1779',
144
- bidder: 'freedomadnetwork',
145
- bidderRequestId: '15246a574e859f',
146
- mediaTypes: {
147
- native: {},
148
- },
149
- params: {
150
- placementId: '8064026a-9932-45ae-b804-03491302ad88'
151
- }
152
- }
153
- ];
154
-
155
- let reqs;
156
-
157
- expect(function () {
158
- reqs = spec.buildRequests(bidRequests, bidderRequest);
159
- }).to.not.throw();
160
-
161
- expect(reqs).to.be.an('array').that.have.lengthOf(bidRequests.length);
162
-
163
- for (let i = 0, len = reqs.length; i < len; i++) {
164
- const req = reqs[i];
165
- const bidRequest = bidRequests[i];
166
-
167
- expect(req.method).to.equal('POST');
168
- expect(req.url).to.equal('https://srv.freedomadnetwork.com/pb/req');
169
-
170
- expect(req.options).to.be.an('object');
171
- expect(req.options.contentType).to.contain('application/json');
172
- expect(req.options.customHeaders).to.be.an('object');
102
+ it('should return false when mediaTypes is unsupported', function() {
103
+ const bid = Object.assign({}, validBidRequestBanner, {
104
+ mediaTypes: { native: {} }
105
+ });
106
+ expect(spec.isBidRequestValid(bid)).to.be.false;
107
+ });
173
108
 
174
- expect(req.originalBidRequest).to.equal(bidRequest);
109
+ it('should return false when video params missing required fields', function() {
110
+ const badVideoBid1 = JSON.parse(JSON.stringify(validBidRequestVideo));
111
+ delete badVideoBid1.mediaTypes.video.mimes;
112
+ expect(spec.isBidRequestValid(badVideoBid1)).to.be.false;
175
113
 
176
- var data = JSON.parse(req.data);
177
- expect(data.id).to.equal(bidRequest.bidId);
178
- expect(data.placements[0]).to.equal(bidRequest.params.placementId);
179
- }
114
+ const badVideoBid2 = JSON.parse(JSON.stringify(validBidRequestVideo));
115
+ delete badVideoBid2.mediaTypes.video.playerSize;
116
+ expect(spec.isBidRequestValid(badVideoBid2)).to.be.false;
180
117
  });
181
118
  });
182
119
 
183
- describe('Test adapter request', function () {
184
- const adapter = newBidder(spec);
185
-
186
- it('adapter.callBids exists and is a function', function () {
187
- expect(adapter.callBids).to.be.a('function');
120
+ describe('buildRequests', function() {
121
+ it('should group bids by network and produce valid HTTP requests', function() {
122
+ // Create two bids, one to 'test' network, one to FAN
123
+ const bidTest = JSON.parse(JSON.stringify(validBidRequestBanner));
124
+ const bidFan = JSON.parse(JSON.stringify(validBidRequestBanner));
125
+ bidFan.params.network = 'fan';
126
+ bidFan.params.placementId = 'placement456';
127
+ bidFan.bidId = 'bid-3';
128
+
129
+ const requests = spec.buildRequests([bidTest, bidFan], bidderRequest);
130
+
131
+ // Expect two separate requests (one per network)
132
+ expect(requests).to.have.lengthOf(2);
133
+
134
+ // Find the request for 'test'
135
+ const reqTest = requests.find(r => r.url === 'http://localhost:8001/ortb');
136
+ expect(reqTest).to.exist;
137
+ expect(reqTest.method).to.equal('POST');
138
+ expect(reqTest.options.contentType).to.equal('application/json');
139
+ expect(reqTest.options.withCredentials).to.be.false;
140
+
141
+ // The data payload should have 'imp' array with one impression
142
+ expect(reqTest.data.imp).to.be.an('array').with.lengthOf(1);
143
+ const impTest = reqTest.data.imp[0];
144
+ expect(impTest.tagid).to.equal('placement123');
145
+
146
+ // Source.tid must equal auctionId
147
+ expect(reqTest.data.source.tid).to.equal(bidderRequest.auctionId);
148
+ expect(reqTest.data.at).to.equal(1);
149
+ expect(reqTest.data.cur).to.deep.equal([DEFAULT_CURRENCY]);
150
+ expect(reqTest.data.ext.prebid.channel).to.equal(BIDDER_CODE);
151
+ expect(reqTest.data.ext.prebid.version).to.exist;
152
+
153
+ // Find the request for FAN
154
+ const reqFan = requests.find(r => r.url === 'https://srv.freedomadnetwork.com/ortb');
155
+ expect(reqFan).to.exist;
156
+ expect(reqFan.method).to.equal('POST');
157
+ expect(reqFan.data.imp[0].tagid).to.equal('placement456');
158
+
159
+ // Validate bidfloor and bidfloorcur were set for video
160
+ const videoBid = validBidRequestVideo;
161
+ const reqVideo = spec.buildRequests([videoBid], bidderRequest)[0];
162
+ const impVideo = reqVideo.data.imp[0];
163
+ expect(impVideo.bidfloor).to.equal(parseFloat(videoBid.params.bidFloor));
164
+ expect(impVideo.bidfloorcur).to.equal(videoBid.params.bidFloorCur);
188
165
  });
189
166
  });
190
167
 
191
- describe('Test response interpretResponse', function () {
192
- it('Test main interpretResponse', function () {
193
- const serverResponse = {
194
- body: [{
195
- id: '8064026a1776',
196
- bidid: '78e10bd4-aa67-40a6-b282-0f2697251eb3',
197
- impid: '88faf7e7-bef8-43a5-9ef3-73db10c2af6b',
198
- userId: '944c9c880be09af1e90da1f883538607',
199
- cpm: 17.76,
200
- currency: 'USD',
201
- width: 300,
202
- height: 250,
203
- ttl: 60,
204
- netRevenue: false,
205
- crid: '03f3ed6f-1a9e-4276-8ad7-0dc5efae289e',
206
- payload: '<img />',
207
- trackers: [],
208
- mediaType: 'native',
209
- domains: ['foo.com'],
210
- }]
211
- };
168
+ describe('interpretResponse', function() {
169
+ it('should return an empty array when response body is missing', function() {
170
+ const builtRequests = spec.buildRequests([validBidRequestBanner], bidderRequest);
171
+ const fakeRequest = builtRequests[0];
212
172
 
213
- const bidResponses = spec.interpretResponse(serverResponse, {
214
- originalBidRequest: {
215
- adUnitCode: 'test-div',
216
- auctionId: 'b06c5141-fe8f-4cdf-9d7d-54415490a917',
217
- bidId: '8064026a1776',
218
- bidder: 'freedomadnetwork',
219
- bidderRequestId: '15246a574e859f',
220
- mediaTypes: {
221
- banner: { sizes: [[300, 250]] }
222
- },
223
- params: {
224
- placementId: 'e6203f1e-bd6d-4f42-9895-d1a19cdb83c8'
225
- }
226
- }
227
- });
228
-
229
- expect(bidResponses).to.be.an('array').that.is.not.empty;
230
-
231
- const bid = serverResponse.body[0];
232
- const bidResponse = bidResponses[0];
233
-
234
- expect(bidResponse.requestId).to.equal(bid.id);
235
- expect(bidResponse.bidid).to.equal(bid.bidid);
236
- expect(bidResponse.impid).to.equal(bid.impid);
237
- expect(bidResponse.userId).to.equal(bid.userId);
238
- expect(bidResponse.cpm).to.equal(bid.cpm);
239
- expect(bidResponse.currency).to.equal(bid.currency);
240
- expect(bidResponse.width).to.equal(bid.width);
241
- expect(bidResponse.height).to.equal(bid.height);
242
- expect(bidResponse.ad).to.equal(bid.payload);
243
- expect(bidResponse.ttl).to.equal(bid.ttl);
244
- expect(bidResponse.creativeId).to.equal(bid.crid);
245
- expect(bidResponse.netRevenue).to.equal(bid.netRevenue);
246
- expect(bidResponse.trackers).to.equal(bid.trackers);
247
- expect(bidResponse.meta.mediaType).to.equal(bid.mediaType);
248
- expect(bidResponse.meta.advertiserDomains).to.equal(bid.domains);
173
+ const result = spec.interpretResponse({ body: null }, fakeRequest);
174
+ expect(result).to.be.an('array').and.have.lengthOf(0);
249
175
  });
250
176
 
251
- it('Test empty server response', function () {
252
- const bidResponses = spec.interpretResponse({}, {});
177
+ it('should return proper bid objects for a valid ORTB response', function() {
178
+ const builtRequests = spec.buildRequests([validBidRequestBanner], bidderRequest);
179
+ const fakeRequest = builtRequests[0];
180
+
181
+ const ortbResponse = {
182
+ id: fakeRequest.data.id,
183
+ cur: 'USD',
184
+ seatbid: [
185
+ {
186
+ bid: [
187
+ {
188
+ id: '123',
189
+ impid: fakeRequest.data.imp[0].id,
190
+ price: 2.5,
191
+ adm: '<div>Ad</div>',
192
+ w: 300,
193
+ h: 250,
194
+ crid: 'cr123',
195
+ mtype: 1,
196
+ }
197
+ ]
198
+ }
199
+ ],
200
+ };
253
201
 
254
- expect(bidResponses).to.be.an('array').that.is.empty;
255
- });
202
+ const serverResponse = { body: ortbResponse };
203
+ const bidResponses = spec.interpretResponse(serverResponse, fakeRequest);
256
204
 
257
- it('Test empty bid response', function () {
258
- const bidResponses = spec.interpretResponse({ body: [] }, {});
205
+ expect(bidResponses).to.be.an('array').with.lengthOf(1);
259
206
 
260
- expect(bidResponses).to.be.an('array').that.is.empty;
207
+ const bid = bidResponses[0];
208
+ expect(bid.requestId).to.equal('bid-1');
209
+ expect(bid.cpm).to.equal(2.5);
210
+ expect(bid.ad).to.equal('<div>Ad</div>');
211
+ expect(bid.width).to.equal(300);
212
+ expect(bid.height).to.equal(250);
213
+ expect(bid.creativeId).to.equal('cr123');
214
+ expect(bid.currency).to.equal('USD');
215
+ expect(bid.ttl).to.equal(300);
261
216
  });
262
217
  });
263
218
 
264
- describe('Test getUserSyncs', function () {
265
- it('getUserSyncs should return empty', function () {
266
- const serverResponse = {};
267
- const syncOptions = {}
268
- const userSyncPixels = spec.getUserSyncs(syncOptions, [serverResponse])
269
- expect(userSyncPixels).to.have.lengthOf(0);
219
+ describe('getUserSyncs', function() {
220
+ const gdprConsent = { gdprApplies: true, consentString: 'CONSENT123' };
221
+ const uspConsent = '1YNN';
222
+ const gppConsent = { gppString: 'GPPSTRING', applicableSections: [6, 7] };
223
+
224
+ it('should return empty array when syncOptions disabled', function() {
225
+ const syncs = spec.getUserSyncs({ iframeEnabled: false, pixelEnabled: false }, [], gdprConsent, uspConsent, gppConsent);
226
+ expect(syncs).to.deep.equal([]);
270
227
  });
271
- });
272
228
 
273
- describe('Test onTimeout', function () {
274
- it('onTimeout should not throw', function () {
275
- expect(spec.onTimeout()).to.not.throw;
229
+ it('should return iframe and image sync URLs without duplicates', function() {
230
+ const serverResponses = [{
231
+ body: {
232
+ ext: {
233
+ sync: {
234
+ iframe: [{ url: 'https://sync.iframe/endpoint' }],
235
+ image: [{ url: 'https://sync.image/endpoint' }]
236
+ }
237
+ }
238
+ }
239
+ }, {
240
+ body: {
241
+ ext: {
242
+ sync: {
243
+ iframe: [{ url: 'https://sync.iframe/endpoint' }], // duplicate
244
+ image: [{ url: 'https://sync.image/endpoint2' }]
245
+ }
246
+ }
247
+ }
248
+ }];
249
+
250
+ const syncOptions = { iframeEnabled: true, pixelEnabled: true };
251
+ const syncs = spec.getUserSyncs(syncOptions, serverResponses, gdprConsent, uspConsent, gppConsent);
252
+
253
+ // Should have exactly three sync entries (unique URLs)
254
+ expect(syncs).to.have.lengthOf(3);
255
+
256
+ // Validate type and URL parameters for GDPR and US Privacy
257
+ const iframeSync = syncs.find(s => s.type === 'iframe' && s.url.startsWith('https://sync.iframe/endpoint'));
258
+ expect(iframeSync).to.exist;
259
+ expect(iframeSync.url).to.match(/gdpr=1/);
260
+ expect(iframeSync.url).to.match(/gdpr_consent=CONSENT123/);
261
+ expect(iframeSync.url).to.match(/us_privacy=1YNN/);
262
+ expect(iframeSync.url).to.match(/gpp=GPPSTRING/);
263
+ // The comma in '6,7' will be percent-encoded as '%2C'
264
+ expect(iframeSync.url).to.match(/gpp_sid=6%2C7/);
265
+
266
+ const imageSync1 = syncs.find(s => s.type === 'image' && s.url.startsWith('https://sync.image/endpoint'));
267
+ expect(imageSync1).to.exist;
268
+ const imageSync2 = syncs.find(s => s.type === 'image' && s.url.startsWith('https://sync.image/endpoint2'));
269
+ expect(imageSync2).to.exist;
276
270
  });
277
271
  });
278
272
 
279
- describe('Test onBidWon', function () {
280
- let sandbox, ajaxStub;
273
+ describe('Win Events', function() {
274
+ let triggerPixelStub;
281
275
 
282
- beforeEach(function () {
283
- sandbox = sinon.createSandbox();
284
- ajaxStub = sandbox.stub(ajax, 'ajax');
276
+ beforeEach(function() {
277
+ triggerPixelStub = sinon.stub(utils, 'triggerPixel');
285
278
  });
286
279
 
287
- afterEach(function () {
288
- sandbox.restore();
289
- ajaxStub.restore();
280
+ afterEach(function() {
281
+ triggerPixelStub.restore();
290
282
  });
291
283
 
292
- const bid = {
293
- bidid: '78e10bd4-aa67-40a6-b282-0f2697251eb3',
294
- impid: '88faf7e7-bef8-43a5-9ef3-73db10c2af6b',
295
- cpm: 17.76,
296
- trackers: ['foo.com'],
297
- }
284
+ it('onBidWon should fire nurl and win tracking pixel', function() {
285
+ const fakeBid = {
286
+ requestId: 'req123',
287
+ auctionId: 'auc123',
288
+ cpm: 5.0,
289
+ currency: 'USD',
290
+ creativeId: 'creative123',
291
+ nurl: 'https://win.nurl/track?bid=req123',
292
+ meta: {
293
+ libertas: {
294
+ pxl: [
295
+ {url: 'https://pxl.nurl/track?bid=req456', type: 0}
296
+ ],
297
+ },
298
+ },
299
+ };
298
300
 
299
- it('onBidWon empty bid should not throw', function () {
300
- expect(spec.onBidWon({})).to.not.throw;
301
- expect(ajaxStub.calledOnce).to.equal(true);
302
- });
301
+ spec.onBidWon(fakeBid);
303
302
 
304
- it('onBidWon valid bid should not throw', function () {
305
- expect(spec.onBidWon(bid)).to.not.throw;
306
- expect(ajaxStub.calledOnce).to.equal(true);
307
- });
308
- });
303
+ // First call: nurl
304
+ expect(triggerPixelStub.calledWith('https://win.nurl/track?bid=req123')).to.be.true;
309
305
 
310
- describe('Test onSetTargeting', function () {
311
- it('onSetTargeting should not throw', function () {
312
- expect(spec.onSetTargeting()).to.not.throw;
306
+ // Second call: win tracking URL must start with base
307
+ const winCallArgs = triggerPixelStub.getCall(1).args[0];
308
+ expect(winCallArgs).to.match(/^https:\/\/pxl\.nurl\/track\?bid=req456/);
313
309
  });
314
310
  });
315
311
  });