prebid.js 7.19.0 → 7.20.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 (237) hide show
  1. package/dist/33acrossBidAdapter.js +1 -1
  2. package/dist/33acrossIdSystem.js +1 -1
  3. package/dist/adWMGAnalyticsAdapter.js +1 -1
  4. package/dist/adagioAnalyticsAdapter.js +1 -1
  5. package/dist/adagioBidAdapter.js +1 -1
  6. package/dist/adbookpspBidAdapter.js +1 -1
  7. package/dist/adgenerationBidAdapter.js +1 -1
  8. package/dist/adkernelAdnAnalyticsAdapter.js +1 -1
  9. package/dist/adkernelBidAdapter.js +1 -1
  10. package/dist/adlooxAdServerVideo.js +1 -1
  11. package/dist/adlooxAnalyticsAdapter.js +1 -1
  12. package/dist/adlooxRtdProvider.js +1 -1
  13. package/dist/adomikAnalyticsAdapter.js +1 -1
  14. package/dist/adrelevantisBidAdapter.js +1 -1
  15. package/dist/adtrgtmeBidAdapter.js +1 -1
  16. package/dist/adxcgAnalyticsAdapter.js +1 -1
  17. package/dist/adxcgBidAdapter.js +1 -1
  18. package/dist/adxpremiumAnalyticsAdapter.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/aolBidAdapter.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/atsAnalyticsAdapter.js +1 -1
  27. package/dist/axonixBidAdapter.js +1 -1
  28. package/dist/bidViewability.js +1 -1
  29. package/dist/bidglassBidAdapter.js +1 -1
  30. package/dist/bidwatchAnalyticsAdapter.js +1 -1
  31. package/dist/big-richmediaBidAdapter.js +1 -1
  32. package/dist/bridgewellBidAdapter.js +1 -1
  33. package/dist/brightMountainMediaBidAdapter.js +1 -1
  34. package/dist/byDataAnalyticsAdapter.js +1 -1
  35. package/dist/carodaBidAdapter.js +1 -1
  36. package/dist/categoryTranslation.js +1 -1
  37. package/dist/concertAnalyticsAdapter.js +1 -1
  38. package/dist/concertBidAdapter.js +1 -1
  39. package/dist/connectIdSystem.js +1 -1
  40. package/dist/connectadBidAdapter.js +1 -1
  41. package/dist/consentManagement.js +1 -1
  42. package/dist/consentManagementUsp.js +1 -1
  43. package/dist/consumableBidAdapter.js +1 -1
  44. package/dist/conversantAnalyticsAdapter.js +1 -1
  45. package/dist/conversantBidAdapter.js +1 -1
  46. package/dist/craftBidAdapter.js +1 -1
  47. package/dist/criteoBidAdapter.js +1 -1
  48. package/dist/currency.js +1 -1
  49. package/dist/datablocksAnalyticsAdapter.js +1 -1
  50. package/dist/dchain.js +1 -1
  51. package/dist/debugging-standalone.js +1 -1
  52. package/dist/debugging.js +1 -1
  53. package/dist/dependencies.json +3 -0
  54. package/dist/dfpAdServerVideo.js +1 -1
  55. package/dist/dspxBidAdapter.js +1 -1
  56. package/dist/eplanningAnalyticsAdapter.js +1 -1
  57. package/dist/eplanningBidAdapter.js +1 -1
  58. package/dist/finativeBidAdapter.js +1 -1
  59. package/dist/fintezaAnalyticsAdapter.js +1 -1
  60. package/dist/ftrackIdSystem.js +1 -1
  61. package/dist/gdprEnforcement.js +1 -1
  62. package/dist/glimpseBidAdapter.js +1 -1
  63. package/dist/gmosspBidAdapter.js +1 -1
  64. package/dist/goldbachBidAdapter.js +1 -1
  65. package/dist/googleAnalyticsAdapter.js +1 -1
  66. package/dist/gridBidAdapter.js +1 -1
  67. package/dist/gridNMBidAdapter.js +1 -1
  68. package/dist/gumgumBidAdapter.js +1 -1
  69. package/dist/h12mediaBidAdapter.js +1 -1
  70. package/dist/hadronAnalyticsAdapter.js +1 -1
  71. package/dist/id5AnalyticsAdapter.js +1 -1
  72. package/dist/id5IdSystem.js +1 -1
  73. package/dist/improvedigitalBidAdapter.js +1 -1
  74. package/dist/inmarBidAdapter.js +1 -1
  75. package/dist/insticatorBidAdapter.js +1 -1
  76. package/dist/invisiblyAnalyticsAdapter.js +1 -1
  77. package/dist/ixBidAdapter.js +1 -1
  78. package/dist/justpremiumBidAdapter.js +1 -1
  79. package/dist/kargoAnalyticsAdapter.js +1 -1
  80. package/dist/kinessoIdSystem.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/liveIntentAnalyticsAdapter.js +1 -1
  86. package/dist/liveIntentIdSystem.js +1 -1
  87. package/dist/livewrappedAnalyticsAdapter.js +1 -1
  88. package/dist/liveyieldAnalyticsAdapter.js +1 -1
  89. package/dist/logicadBidAdapter.js +1 -1
  90. package/dist/loglyliftBidAdapter.js +1 -1
  91. package/dist/lotamePanoramaIdSystem.js +1 -1
  92. package/dist/magniteAnalyticsAdapter.js +1 -0
  93. package/dist/malltvAnalyticsAdapter.js +1 -1
  94. package/dist/marsmediaAnalyticsAdapter.js +1 -1
  95. package/dist/marsmediaBidAdapter.js +1 -1
  96. package/dist/mass.js +1 -1
  97. package/dist/mediafuseBidAdapter.js +1 -1
  98. package/dist/medianetAnalyticsAdapter.js +1 -1
  99. package/dist/mediasquareBidAdapter.js +1 -1
  100. package/dist/mgidBidAdapter.js +1 -1
  101. package/dist/minutemediaBidAdapter.js +1 -1
  102. package/dist/multibid.js +1 -1
  103. package/dist/not-for-prod/prebid.js +186 -184
  104. package/dist/oguryBidAdapter.js +1 -1
  105. package/dist/onetagBidAdapter.js +1 -1
  106. package/dist/ooloAnalyticsAdapter.js +1 -1
  107. package/dist/openxAnalyticsAdapter.js +1 -1
  108. package/dist/optimonAnalyticsAdapter.js +1 -1
  109. package/dist/outbrainBidAdapter.js +1 -1
  110. package/dist/parrableIdSystem.js +1 -1
  111. package/dist/pianoDmpAnalyticsAdapter.js +1 -1
  112. package/dist/pixfutureBidAdapter.js +1 -1
  113. package/dist/prebid-core.js +2 -2
  114. package/dist/prebidServerBidAdapter.js +1 -1
  115. package/dist/prebidmanagerAnalyticsAdapter.js +1 -1
  116. package/dist/priceFloors.js +1 -1
  117. package/dist/publinkIdSystem.js +1 -1
  118. package/dist/pubmaticAnalyticsAdapter.js +1 -1
  119. package/dist/pubmaticBidAdapter.js +1 -1
  120. package/dist/pubperfAnalyticsAdapter.js +1 -1
  121. package/dist/pubstackAnalyticsAdapter.js +1 -1
  122. package/dist/pubwiseAnalyticsAdapter.js +1 -1
  123. package/dist/pubxaiAnalyticsAdapter.js +1 -1
  124. package/dist/pulsepointAnalyticsAdapter.js +1 -1
  125. package/dist/pxyzBidAdapter.js +1 -1
  126. package/dist/quantcastBidAdapter.js +1 -1
  127. package/dist/quantcastIdSystem.js +1 -1
  128. package/dist/readpeakBidAdapter.js +1 -1
  129. package/dist/realvuAnalyticsAdapter.js +1 -1
  130. package/dist/relaidoBidAdapter.js +1 -1
  131. package/dist/relevantAnalyticsAdapter.js +1 -1
  132. package/dist/rhythmoneBidAdapter.js +1 -1
  133. package/dist/riseBidAdapter.js +1 -1
  134. package/dist/rivrAnalyticsAdapter.js +1 -1
  135. package/dist/roxotAnalyticsAdapter.js +1 -1
  136. package/dist/rtdModule.js +1 -1
  137. package/dist/rubiconAnalyticsAdapter.js +1 -1
  138. package/dist/rubiconBidAdapter.js +1 -1
  139. package/dist/s2sTesting.js +1 -1
  140. package/dist/scaleableAnalyticsAdapter.js +1 -1
  141. package/dist/schain.js +1 -1
  142. package/dist/seedingAllianceBidAdapter.js +1 -1
  143. package/dist/seedtagBidAdapter.js +1 -1
  144. package/dist/sharedIdSystem.js +1 -1
  145. package/dist/sharethroughAnalyticsAdapter.js +1 -1
  146. package/dist/sharethroughBidAdapter.js +1 -1
  147. package/dist/shinezBidAdapter.js +1 -1
  148. package/dist/sigmoidAnalyticsAdapter.js +1 -1
  149. package/dist/smaatoBidAdapter.js +1 -1
  150. package/dist/smartadserverBidAdapter.js +1 -1
  151. package/dist/smartxBidAdapter.js +1 -1
  152. package/dist/smilewantedBidAdapter.js +1 -1
  153. package/dist/sonobiAnalyticsAdapter.js +1 -1
  154. package/dist/sonobiBidAdapter.js +1 -1
  155. package/dist/sovrnAnalyticsAdapter.js +1 -1
  156. package/dist/sovrnBidAdapter.js +1 -1
  157. package/dist/sspBCBidAdapter.js +1 -1
  158. package/dist/staqAnalyticsAdapter.js +1 -1
  159. package/dist/sublimeBidAdapter.js +1 -1
  160. package/dist/synacormediaBidAdapter.js +1 -1
  161. package/dist/taboolaBidAdapter.js +1 -1
  162. package/dist/tapadIdSystem.js +1 -1
  163. package/dist/targetVideoBidAdapter.js +1 -1
  164. package/dist/teadsBidAdapter.js +1 -1
  165. package/dist/teadsIdSystem.js +1 -0
  166. package/dist/terceptAnalyticsAdapter.js +1 -1
  167. package/dist/trionBidAdapter.js +1 -1
  168. package/dist/tripleliftBidAdapter.js +1 -1
  169. package/dist/ttdBidAdapter.js +1 -1
  170. package/dist/ucfunnelAnalyticsAdapter.js +1 -1
  171. package/dist/underdogmediaBidAdapter.js +1 -1
  172. package/dist/undertoneBidAdapter.js +1 -1
  173. package/dist/userId.js +1 -1
  174. package/dist/vidazooBidAdapter.js +1 -1
  175. package/dist/videobyteBidAdapter.js +1 -1
  176. package/dist/visxBidAdapter.js +1 -1
  177. package/dist/vrtcalBidAdapter.js +1 -1
  178. package/dist/vuukleBidAdapter.js +1 -1
  179. package/dist/weboramaRtdProvider.js +1 -1
  180. package/dist/widespaceBidAdapter.js +1 -1
  181. package/dist/winrBidAdapter.js +1 -1
  182. package/dist/yahoosspBidAdapter.js +1 -1
  183. package/dist/yieldmoBidAdapter.js +1 -1
  184. package/dist/yieldoneAnalyticsAdapter.js +1 -1
  185. package/dist/yuktamediaAnalyticsAdapter.js +1 -1
  186. package/dist/zeta_global_sspAnalyticsAdapter.js +1 -1
  187. package/modules/.submodules.json +1 -0
  188. package/modules/adkernelBidAdapter.js +2 -2
  189. package/modules/aolBidAdapter.js +25 -2
  190. package/modules/appnexusBidAdapter.js +19 -2
  191. package/modules/categoryTranslation.js +4 -4
  192. package/modules/connectIdSystem.js +16 -1
  193. package/modules/currency.js +11 -11
  194. package/modules/dchain.js +2 -2
  195. package/modules/debugging/legacy.js +2 -2
  196. package/modules/eplanningBidAdapter.js +48 -2
  197. package/modules/lotamePanoramaIdSystem.js +10 -6
  198. package/modules/magniteAnalyticsAdapter.js +902 -0
  199. package/modules/magniteAnalyticsAdapter.md +18 -0
  200. package/modules/mass.js +2 -2
  201. package/modules/multibid/index.js +5 -5
  202. package/modules/pixfutureBidAdapter.js +46 -15
  203. package/modules/prebidServerBidAdapter/index.js +10 -6
  204. package/modules/priceFloors.js +8 -22
  205. package/modules/rubiconAnalyticsAdapter.js +14 -9
  206. package/modules/taboolaBidAdapter.js +4 -4
  207. package/modules/teadsIdSystem.js +234 -0
  208. package/modules/teadsIdSystem.md +22 -0
  209. package/modules/userId/index.js +21 -14
  210. package/modules/vrtcalBidAdapter.js +7 -1
  211. package/modules/yahoosspBidAdapter.js +1 -1
  212. package/package.json +1 -1
  213. package/src/adapters/bidderFactory.js +13 -11
  214. package/src/auction.js +140 -69
  215. package/src/constants.json +8 -0
  216. package/src/prebid.js +2 -3
  217. package/src/targeting.js +31 -14
  218. package/test/fixtures/fixtures.js +2 -1
  219. package/test/spec/auctionmanager_spec.js +109 -21
  220. package/test/spec/modules/aolBidAdapter_spec.js +42 -9
  221. package/test/spec/modules/appnexusBidAdapter_spec.js +24 -0
  222. package/test/spec/modules/connectIdSystem_spec.js +20 -0
  223. package/test/spec/modules/currency_spec.js +14 -6
  224. package/test/spec/modules/eplanningBidAdapter_spec.js +285 -1
  225. package/test/spec/modules/lotamePanoramaIdSystem_spec.js +0 -1
  226. package/test/spec/modules/magniteAnalyticsAdapter_spec.js +1942 -0
  227. package/test/spec/modules/prebidServerBidAdapter_spec.js +43 -11
  228. package/test/spec/modules/priceFloors_spec.js +5 -5
  229. package/test/spec/modules/rubiconAnalyticsAdapter_spec.js +2 -3
  230. package/test/spec/modules/taboolaBidAdapter_spec.js +110 -11
  231. package/test/spec/modules/teadsIdSystem_spec.js +271 -0
  232. package/test/spec/modules/userId_spec.js +39 -4
  233. package/test/spec/modules/vrtcalBidAdapter_spec.js +12 -1
  234. package/test/spec/modules/yahoosspBidAdapter_spec.js +45 -0
  235. package/test/spec/unit/core/bidderFactory_spec.js +66 -11
  236. package/test/spec/unit/core/targeting_spec.js +28 -9
  237. package/test/spec/unit/pbjs_api_spec.js +4 -2
@@ -536,6 +536,8 @@ describe('S2S Adapter', function () {
536
536
  addBidResponse = sinon.spy(),
537
537
  done = sinon.spy();
538
538
 
539
+ addBidResponse.reject = sinon.spy();
540
+
539
541
  function prepRequest(req) {
540
542
  req.ad_units.forEach((adUnit) => {
541
543
  delete adUnit.nativeParams
@@ -595,6 +597,7 @@ describe('S2S Adapter', function () {
595
597
 
596
598
  afterEach(function () {
597
599
  addBidResponse.resetHistory();
600
+ addBidResponse.reject = sinon.spy();
598
601
  done.resetHistory();
599
602
  });
600
603
 
@@ -2903,6 +2906,16 @@ describe('S2S Adapter', function () {
2903
2906
  });
2904
2907
  }
2905
2908
 
2909
+ it('should reject invalid bids', () => {
2910
+ config.setConfig({ s2sConfig: CONFIG });
2911
+ adapter.callBids(REQUEST, BID_REQUESTS, addBidResponse, done, ajax);
2912
+ const response = deepClone(RESPONSE_OPENRTB);
2913
+ Object.assign(response.seatbid[0].bid[0], {w: null, h: null});
2914
+ server.requests[0].respond(200, {}, JSON.stringify(response));
2915
+ expect(addBidResponse.reject.calledOnce).to.be.true;
2916
+ expect(addBidResponse.called).to.be.false;
2917
+ });
2918
+
2906
2919
  it('does not (by default) allow bids that were not requested', function () {
2907
2920
  config.setConfig({ s2sConfig: CONFIG });
2908
2921
  adapter.callBids(REQUEST, BID_REQUESTS, addBidResponse, done, ajax);
@@ -2911,6 +2924,7 @@ describe('S2S Adapter', function () {
2911
2924
  server.requests[0].respond(200, {}, JSON.stringify(response));
2912
2925
 
2913
2926
  expect(addBidResponse.called).to.be.false;
2927
+ expect(addBidResponse.reject.calledOnce).to.be.true;
2914
2928
  });
2915
2929
 
2916
2930
  it('allows unrequested bids if config.allowUnknownBidderCodes', function () {
@@ -2924,17 +2938,35 @@ describe('S2S Adapter', function () {
2924
2938
  expect(addBidResponse.calledWith(sinon.match.any, sinon.match({ bidderCode: 'unknown' }))).to.be.true;
2925
2939
  });
2926
2940
 
2927
- it('uses "null" request\'s ID for all responses, when a null request is present', function () {
2928
- const cfg = {...CONFIG, allowUnknownBidderCodes: true};
2929
- config.setConfig({s2sConfig: cfg});
2930
- const req = {...REQUEST, s2sConfig: cfg, ad_units: [{...REQUEST.ad_units[0], bids: [{bidder: null, bid_id: 'testId'}]}]};
2931
- const bidReq = {...BID_REQUESTS[0], bidderCode: null, bids: [{...BID_REQUESTS[0].bids[0], bidder: null, bidId: 'testId'}]}
2932
- adapter.callBids(req, [bidReq], addBidResponse, done, ajax);
2933
- const response = deepClone(RESPONSE_OPENRTB);
2934
- response.seatbid[0].seat = 'storedImpression';
2935
- server.requests[0].respond(200, {}, JSON.stringify(response));
2936
- sinon.assert.calledWith(addBidResponse, sinon.match.any, sinon.match({bidderCode: 'storedImpression', requestId: 'testId'}))
2937
- });
2941
+ describe('stored impressions', () => {
2942
+ let bidReq, response;
2943
+
2944
+ function mks2sReq(s2sConfig = CONFIG) {
2945
+ return {...REQUEST, s2sConfig, ad_units: [{...REQUEST.ad_units[0], bids: [{bidder: null, bid_id: 'testId'}]}]};
2946
+ }
2947
+
2948
+ beforeEach(() => {
2949
+ bidReq = {...BID_REQUESTS[0], bidderCode: null, bids: [{...BID_REQUESTS[0].bids[0], bidder: null, bidId: 'testId'}]}
2950
+ response = deepClone(RESPONSE_OPENRTB);
2951
+ response.seatbid[0].seat = 'storedImpression';
2952
+ })
2953
+
2954
+ it('uses "null" request\'s ID for all responses, when a null request is present', function () {
2955
+ const cfg = {...CONFIG, allowUnknownBidderCodes: true};
2956
+ config.setConfig({s2sConfig: cfg});
2957
+ adapter.callBids(mks2sReq(cfg), [bidReq], addBidResponse, done, ajax);
2958
+ server.requests[0].respond(200, {}, JSON.stringify(response));
2959
+ sinon.assert.calledWith(addBidResponse, sinon.match.any, sinon.match({bidderCode: 'storedImpression', requestId: 'testId'}))
2960
+ });
2961
+
2962
+ it('does not allow null requests (= stored impressions) if allowUnknownBidderCodes is not set', () => {
2963
+ config.setConfig({s2sConfig: CONFIG});
2964
+ adapter.callBids(mks2sReq(), [bidReq], addBidResponse, done, ajax);
2965
+ server.requests[0].respond(200, {}, JSON.stringify(response));
2966
+ expect(addBidResponse.called).to.be.false;
2967
+ expect(addBidResponse.reject.calledOnce).to.be.true;
2968
+ });
2969
+ })
2938
2970
 
2939
2971
  it('copies ortb2Imp to response when there is only a null bid', () => {
2940
2972
  const cfg = {...CONFIG};
@@ -1665,7 +1665,7 @@ describe('the price floors module', function () {
1665
1665
  });
1666
1666
  describe('bidResponseHook tests', function () {
1667
1667
  const AUCTION_ID = '123456';
1668
- let returnedBidResponse, indexStub;
1668
+ let returnedBidResponse, indexStub, reject;
1669
1669
  let adUnit = {
1670
1670
  transactionId: 'au',
1671
1671
  code: 'test_div_1'
@@ -1681,6 +1681,7 @@ describe('the price floors module', function () {
1681
1681
  };
1682
1682
  beforeEach(function () {
1683
1683
  returnedBidResponse = {};
1684
+ reject = sinon.stub().returns({status: 'rejected'});
1684
1685
  indexStub = sinon.stub(auctionManager, 'index');
1685
1686
  indexStub.get(() => stubAuctionIndex({adUnits: [adUnit]}));
1686
1687
  });
@@ -1693,7 +1694,7 @@ describe('the price floors module', function () {
1693
1694
  let next = (adUnitCode, bid) => {
1694
1695
  returnedBidResponse = bid;
1695
1696
  };
1696
- addBidResponseHook(next, bidResp.adUnitCode, Object.assign(createBid(CONSTANTS.STATUS.GOOD, {auctionId: AUCTION_ID}), bidResp));
1697
+ addBidResponseHook(next, bidResp.adUnitCode, Object.assign(createBid(CONSTANTS.STATUS.GOOD, {auctionId: AUCTION_ID}), bidResp), reject);
1697
1698
  };
1698
1699
  it('continues with the auction if not floors data is present without any flooring', function () {
1699
1700
  runBidResponse();
@@ -1710,9 +1711,8 @@ describe('the price floors module', function () {
1710
1711
  _floorDataForAuction[AUCTION_ID] = utils.deepClone(basicFloorConfig);
1711
1712
  _floorDataForAuction[AUCTION_ID].data.values = { 'banner': 1.0 };
1712
1713
  runBidResponse();
1713
- expect(returnedBidResponse).to.haveOwnProperty('floorData');
1714
- expect(returnedBidResponse.status).to.equal(CONSTANTS.BID_STATUS.BID_REJECTED);
1715
- expect(returnedBidResponse.cpm).to.equal(0);
1714
+ expect(reject.calledOnce).to.be.true;
1715
+ expect(returnedBidResponse.status).to.equal('rejected');
1716
1716
  });
1717
1717
  it('if it finds a rule and does not floor should update the bid accordingly', function () {
1718
1718
  _floorDataForAuction[AUCTION_ID] = utils.deepClone(basicFloorConfig);
@@ -4,6 +4,7 @@ import rubiconAnalyticsAdapter, {
4
4
  getHostNameFromReferer,
5
5
  storage,
6
6
  rubiConf,
7
+ resetRubiConf
7
8
  } from 'modules/rubiconAnalyticsAdapter.js';
8
9
  import CONSTANTS from 'src/constants.json';
9
10
  import { config } from 'src/config.js';
@@ -667,6 +668,7 @@ describe('rubicon analytics adapter', function () {
667
668
  expect(utils.generateUUID.called).to.equal(true);
668
669
  });
669
670
  it('should merge in and preserve older set configs', function () {
671
+ resetRubiConf();
670
672
  config.setConfig({
671
673
  rubicon: {
672
674
  wrapperName: '1001_general',
@@ -689,7 +691,6 @@ describe('rubicon analytics adapter', function () {
689
691
  fpkvs: {
690
692
  source: 'fb'
691
693
  },
692
- updatePageView: true
693
694
  });
694
695
 
695
696
  // update it with stuff
@@ -714,7 +715,6 @@ describe('rubicon analytics adapter', function () {
714
715
  source: 'fb',
715
716
  link: 'email'
716
717
  },
717
- updatePageView: true
718
718
  });
719
719
 
720
720
  // overwriting specific edge keys should update them
@@ -740,7 +740,6 @@ describe('rubicon analytics adapter', function () {
740
740
  link: 'iMessage',
741
741
  source: 'twitter'
742
742
  },
743
- updatePageView: true
744
743
  });
745
744
  });
746
745
  });
@@ -4,7 +4,7 @@ import {config} from '../../../src/config'
4
4
  import * as utils from '../../../src/utils'
5
5
 
6
6
  describe('Taboola Adapter', function () {
7
- let hasLocalStorage, cookiesAreEnabled, getDataFromLocalStorage, localStorageIsEnabled, getCookie;
7
+ let hasLocalStorage, cookiesAreEnabled, getDataFromLocalStorage, localStorageIsEnabled, getCookie, commonBidRequest;
8
8
 
9
9
  beforeEach(() => {
10
10
  hasLocalStorage = sinon.stub(userData.storageManager, 'hasLocalStorage');
@@ -12,7 +12,7 @@ describe('Taboola Adapter', function () {
12
12
  getCookie = sinon.stub(userData.storageManager, 'getCookie');
13
13
  getDataFromLocalStorage = sinon.stub(userData.storageManager, 'getDataFromLocalStorage');
14
14
  localStorageIsEnabled = sinon.stub(userData.storageManager, 'localStorageIsEnabled');
15
-
15
+ commonBidRequest = createBidRequest();
16
16
  $$PREBID_GLOBAL$$.bidderSettings = {
17
17
  taboola: {
18
18
  storageAllowed: true
@@ -30,19 +30,19 @@ describe('Taboola Adapter', function () {
30
30
  $$PREBID_GLOBAL$$.bidderSettings = {};
31
31
  })
32
32
 
33
- const commonBidRequest = {
33
+ const displayBidRequestParams = {
34
+ sizes: [[300, 250], [300, 600]]
35
+ }
36
+
37
+ const createBidRequest = () => ({
34
38
  bidder: 'taboola',
35
39
  params: {
36
40
  publisherId: 'publisherId',
37
41
  tagId: 'placement name'
38
42
  },
39
- bidId: 'aa43860a-4644-442a-b5e0-93f268cs4d19',
40
- auctionId: '65746dca-26f3-4186-be13-dfa63469b1b7',
41
- }
42
-
43
- const displayBidRequestParams = {
44
- sizes: [[300, 250], [300, 600]]
45
- }
43
+ bidId: utils.generateUUID(),
44
+ auctionId: utils.generateUUID(),
45
+ });
46
46
 
47
47
  describe('isBidRequestValid', function () {
48
48
  it('should fail when bid is invalid - tagId isn`t defined', function () {
@@ -132,7 +132,7 @@ describe('Taboola Adapter', function () {
132
132
 
133
133
  describe('buildRequests', function () {
134
134
  const defaultBidRequest = {
135
- ...commonBidRequest,
135
+ ...createBidRequest(),
136
136
  ...displayBidRequestParams,
137
137
  }
138
138
 
@@ -441,6 +441,105 @@ describe('Taboola Adapter', function () {
441
441
  overriddenServerResponse.body.seatbid[0].bid = bid;
442
442
  });
443
443
 
444
+ it('should interpret multi impression request', function () {
445
+ const multiRequest = {
446
+ bids: [
447
+ {
448
+ ...createBidRequest(),
449
+ ...displayBidRequestParams
450
+ },
451
+ {
452
+ ...createBidRequest(),
453
+ ...displayBidRequestParams
454
+ }
455
+ ]
456
+ }
457
+
458
+ const multiServerResponse = {
459
+ body: {
460
+ 'id': '49ffg4d58ef9a163a69fhgfghd4fad03621b9e036f24f7_15',
461
+ 'seatbid': [
462
+ {
463
+ 'bid': [
464
+ {
465
+ 'id': '0b3dd94348-134b-435f-8db5-6bf5afgfc39e86c',
466
+ 'impid': '2',
467
+ 'price': 0.342068,
468
+ 'adid': '2785119545551083381',
469
+ 'adm': 'ADM2',
470
+ 'adomain': [
471
+ 'example.xyz'
472
+ ],
473
+ 'cid': '15744349',
474
+ 'crid': '278195503434041083381',
475
+ 'w': 300,
476
+ 'h': 250,
477
+ 'exp': 60,
478
+ 'lurl': 'http://us-trc.taboola.com/sample'
479
+ },
480
+ {
481
+ 'id': '0b3dd94348-134b-435f-8db5-6bf5afgfc39e86c',
482
+ 'impid': '1',
483
+ 'price': 0.342068,
484
+ 'adid': '2785119545551083381',
485
+ 'adm': 'ADM1',
486
+ 'adomain': [
487
+ 'example.xyz'
488
+ ],
489
+ 'cid': '15744349',
490
+ 'crid': '278195503434041083381',
491
+ 'w': 300,
492
+ 'h': 250,
493
+ 'exp': 60,
494
+ 'lurl': 'http://us-trc.taboola.com/sample'
495
+ }
496
+ ],
497
+ 'seat': '14204545260'
498
+ }
499
+ ],
500
+ 'bidid': 'da43860a-4644-442a-b5e0-93f268cf8d19',
501
+ 'cur': 'USD'
502
+ }
503
+ };
504
+
505
+ const [bid] = multiServerResponse.body.seatbid[0].bid;
506
+ const expectedRes = [
507
+ {
508
+ requestId: multiRequest.bids[1].bidId,
509
+ cpm: bid.price,
510
+ creativeId: bid.crid,
511
+ ttl: 60,
512
+ netRevenue: true,
513
+ currency: multiServerResponse.body.cur,
514
+ mediaType: 'banner',
515
+ ad: multiServerResponse.body.seatbid[0].bid[0].adm,
516
+ width: bid.w,
517
+ height: bid.h,
518
+ meta: {
519
+ 'advertiserDomains': bid.adomain
520
+ },
521
+ },
522
+ {
523
+ requestId: multiRequest.bids[0].bidId,
524
+ cpm: bid.price,
525
+ creativeId: bid.crid,
526
+ ttl: 60,
527
+ netRevenue: true,
528
+ currency: multiServerResponse.body.cur,
529
+ mediaType: 'banner',
530
+ ad: multiServerResponse.body.seatbid[0].bid[1].adm,
531
+ width: bid.w,
532
+ height: bid.h,
533
+ meta: {
534
+ 'advertiserDomains': bid.adomain
535
+ },
536
+ }
537
+ ]
538
+
539
+ const res = spec.interpretResponse(multiServerResponse, multiRequest)
540
+ expect(res).to.deep.equal(expectedRes)
541
+ });
542
+
444
543
  it('should interpret display response', function () {
445
544
  const [bid] = serverResponse.body.seatbid[0].bid;
446
545
  const expectedRes = [
@@ -0,0 +1,271 @@
1
+ import {
2
+ teadsIdSubmodule,
3
+ storage,
4
+ buildAnalyticsTagUrl,
5
+ getGdprStatus,
6
+ gdprStatus,
7
+ getPublisherId,
8
+ getGdprConsentString,
9
+ getCookieExpirationDate, getTimestampFromDays, getCcpaConsentString
10
+ } from 'modules/teadsIdSystem.js';
11
+ import {server} from 'test/mocks/xhr.js';
12
+ import * as utils from '../../../src/utils.js';
13
+
14
+ const FP_TEADS_ID_COOKIE_NAME = '_tfpvi';
15
+ const teadsCookieIdSent = 'teadsCookieIdSent';
16
+ const EXPIRED_COOKIE_DATE = 'Thu, 01 Jan 1970 00:00:01 GMT';
17
+
18
+ describe('TeadsIdSystem', function () {
19
+ describe('buildAnalyticsTagUrl', function () {
20
+ it('return complete URL of server request', function () {
21
+ const submoduleConfig = {
22
+ params: {
23
+ pubId: 1234
24
+ }
25
+ };
26
+
27
+ const consentData = {
28
+ gdprApplies: true,
29
+ consentString: 'abc123=='
30
+ }
31
+
32
+ const result = buildAnalyticsTagUrl(submoduleConfig, consentData);
33
+ const expected = 'https://at.teads.tv/fpc?analytics_tag_id=PUB_1234&tfpvi=&gdpr_consent=abc123%3D%3D&gdpr_status=12&gdpr_reason=120&ccpa_consent=&sv=prebid-v1'
34
+ expect(result).to.be.equal(expected);
35
+ })
36
+ });
37
+
38
+ describe('getPublisherId', function () {
39
+ it('return empty string if params.pubId param is missing', function () {
40
+ const submoduleConfig = {};
41
+ const result = getPublisherId(submoduleConfig);
42
+ const expected = '';
43
+ expect(result).to.be.equal(expected);
44
+ });
45
+ it('return empty string if params.pubId param has a wrong value', function () {
46
+ const pubIdDifferentValues = [null, undefined, false, true, {}, [], 'abc123'];
47
+
48
+ pubIdDifferentValues.forEach((value) => {
49
+ const submoduleConfig = {
50
+ params: {
51
+ pubId: value
52
+ }
53
+ };
54
+ const result = getPublisherId(submoduleConfig);
55
+ const expected = '';
56
+ expect(result).to.be.equal(expected);
57
+ });
58
+ });
59
+ it('return a publisherId prefixed by PUB_ string if params.pubId has a good value', function () {
60
+ const pubIdDifferentValues = [1234, '1234'];
61
+
62
+ pubIdDifferentValues.forEach((value) => {
63
+ const submoduleConfig = {
64
+ params: {
65
+ pubId: value
66
+ }
67
+ };
68
+ const result = getPublisherId(submoduleConfig);
69
+ const expected = 'PUB_1234';
70
+ expect(result).to.be.equal(expected);
71
+ });
72
+ });
73
+ });
74
+
75
+ describe('getGdprConsentString', function () {
76
+ it('return empty consentString if no consentData given', function () {
77
+ const consentDataDifferentValues = [{}, undefined, null];
78
+
79
+ consentDataDifferentValues.forEach((value) => {
80
+ const result = getGdprConsentString(value);
81
+ const expected = '';
82
+ expect(result).to.be.equal(expected);
83
+ });
84
+ });
85
+ it('return empty consentString if consentString has a wrong format', function () {
86
+ const consentStringDifferentValues = [1, 0, undefined, null, {}];
87
+
88
+ consentStringDifferentValues.forEach((value) => {
89
+ const consentData = {
90
+ consentString: value
91
+ };
92
+ const result = getGdprConsentString(consentData);
93
+ const expected = '';
94
+ expect(result).to.be.equal(expected);
95
+ });
96
+ });
97
+ it('return a good consentString if present and a correct format', function () {
98
+ const consentData = {
99
+ consentString: 'consent-string-teads-O1'
100
+ };
101
+ const result = getGdprConsentString(consentData);
102
+ const expected = 'consent-string-teads-O1';
103
+ expect(result).to.be.equal(expected);
104
+ });
105
+ });
106
+
107
+ describe('getCcpaConsentString', function () {
108
+ it('return empty CCPA consentString if no CCPA data is available or a wrong format', function () {
109
+ const consentDataDifferentValues = [{}, undefined, null, 123];
110
+
111
+ consentDataDifferentValues.forEach((value) => {
112
+ const result = getCcpaConsentString(value);
113
+ const expected = '';
114
+ expect(result).to.be.equal(expected);
115
+ });
116
+ });
117
+ it('return CCPA consentString if CCPA data is available and a good format', function () {
118
+ const consentData = '1NYN';
119
+ const result = getCcpaConsentString(consentData);
120
+ const expected = '1NYN';
121
+ expect(result).to.be.equal(expected);
122
+ });
123
+ });
124
+
125
+ describe('getGdprStatus', function () {
126
+ it('return CMP_NOT_FOUND_OR_ERROR if no given consentData', function () {
127
+ const consentDataDifferentValues = [{}, undefined, null];
128
+
129
+ consentDataDifferentValues.forEach((value) => {
130
+ const result = getGdprStatus(value);
131
+ const expected = gdprStatus.CMP_NOT_FOUND_OR_ERROR;
132
+ expect(result).to.be.equal(expected);
133
+ });
134
+ });
135
+ it('return CMP_NOT_FOUND_OR_ERROR if gdprApplies param has a wrong format', function () {
136
+ const gdprAppliesDifferentValues = ['yes', 'true', 1, 0, undefined, null, {}];
137
+
138
+ gdprAppliesDifferentValues.forEach((value) => {
139
+ const consentData = {
140
+ gdprApplies: value
141
+ };
142
+ const result = getGdprStatus(consentData);
143
+ const expected = gdprStatus.CMP_NOT_FOUND_OR_ERROR;
144
+ expect(result).to.be.equal(expected);
145
+ });
146
+ });
147
+ it('return GDPR_DOESNT_APPLY if gdprApplies are false', function () {
148
+ const consentData = {
149
+ gdprApplies: false
150
+ };
151
+ const result = getGdprStatus(consentData);
152
+ const expected = gdprStatus.GDPR_DOESNT_APPLY;
153
+ expect(result).to.be.equal(expected);
154
+ });
155
+ it('return GDPR_APPLIES_PUBLISHER if gdprApplies are true', function () {
156
+ const consentData = {
157
+ gdprApplies: true
158
+ };
159
+ const result = getGdprStatus(consentData);
160
+ const expected = gdprStatus.GDPR_APPLIES_PUBLISHER;
161
+ expect(result).to.be.equal(expected);
162
+ })
163
+ });
164
+
165
+ describe('getExpirationDate', function () {
166
+ it('return Date Formatted if no given consentData', function () {
167
+ let timeStampStub;
168
+ timeStampStub = sinon.stub(utils, 'timestamp').returns(Date.UTC(2022, 8, 19, 14, 30, 50, 0));
169
+ const cookiesMaxAge = getTimestampFromDays(365);
170
+
171
+ const result = getCookieExpirationDate(cookiesMaxAge);
172
+ const expected = 'Tue, 19 Sep 2023 14:30:50 GMT';
173
+ expect(result).to.be.equal(expected);
174
+ timeStampStub.restore();
175
+ });
176
+ });
177
+
178
+ describe('getId', function () {
179
+ let setCookieStub, setLocalStorageStub, removeFromLocalStorageStub, logErrorStub, logInfoStub, timeStampStub;
180
+ const teadsUrl = 'https://at.teads.tv/fpc';
181
+ const timestampNow = new Date().getTime();
182
+
183
+ beforeEach(function () {
184
+ setCookieStub = sinon.stub(storage, 'setCookie');
185
+ timeStampStub = sinon.stub(utils, 'timestamp').returns(timestampNow);
186
+ logErrorStub = sinon.stub(utils, 'logError');
187
+ logInfoStub = sinon.stub(utils, 'logInfo');
188
+ });
189
+
190
+ afterEach(function () {
191
+ setCookieStub.restore();
192
+ timeStampStub.restore();
193
+ logErrorStub.restore();
194
+ logInfoStub.restore();
195
+ });
196
+
197
+ it('should log an error and continue to callback if request errors', function () {
198
+ const config = {
199
+ params: {}
200
+ };
201
+
202
+ const callbackSpy = sinon.spy();
203
+ const callback = teadsIdSubmodule.getId(config).callback;
204
+ callback(callbackSpy);
205
+ const request = server.requests[0];
206
+ expect(request.url).to.include(teadsUrl);
207
+ request.respond(503, null, 'Unavailable');
208
+ expect(logErrorStub.calledOnce).to.be.true;
209
+ });
210
+
211
+ it('should log an info and continue to callback if status 204 is sent', function () {
212
+ const config = {
213
+ params: {}
214
+ };
215
+
216
+ const callbackSpy = sinon.spy();
217
+ const callback = teadsIdSubmodule.getId(config).callback;
218
+ callback(callbackSpy);
219
+ const request = server.requests[0];
220
+ expect(request.url).to.include(teadsUrl);
221
+ request.respond(204, null, 'Unavailable');
222
+ expect(logInfoStub.calledOnce).to.be.true;
223
+ });
224
+
225
+ it('should call the callback with the response body if status 200 is sent', function () {
226
+ const config = {
227
+ params: {}
228
+ };
229
+
230
+ const callbackSpy = sinon.spy();
231
+ const callback = teadsIdSubmodule.getId(config).callback;
232
+ callback(callbackSpy);
233
+ const request = server.requests[0];
234
+ expect(request.url).to.include(teadsUrl);
235
+ request.respond(200, {'Content-Type': 'application/json'}, teadsCookieIdSent);
236
+ expect(callbackSpy.lastCall.lastArg).to.deep.equal(teadsCookieIdSent);
237
+ });
238
+
239
+ it('should save teadsId in cookie and local storage if it was returned by API', function () {
240
+ const config = {
241
+ params: {}
242
+ };
243
+ const result = teadsIdSubmodule.getId(config, {});
244
+ result.callback((id) => {
245
+ expect(id).to.be.deep.equal(teadsCookieIdSent);
246
+ });
247
+
248
+ let request = server.requests[0];
249
+ request.respond(200, {'Content-Type': 'application/json'}, teadsCookieIdSent);
250
+
251
+ const cookiesMaxAge = getTimestampFromDays(365); // 1 year
252
+ const expirationCookieDate = getCookieExpirationDate(cookiesMaxAge);
253
+ expect(setCookieStub.calledWith(FP_TEADS_ID_COOKIE_NAME, teadsCookieIdSent, expirationCookieDate)).to.be.true;
254
+ });
255
+
256
+ it('should delete teadsId in cookie and local storage if it was not returned by API', function () {
257
+ const config = {
258
+ params: {}
259
+ };
260
+ const result = teadsIdSubmodule.getId(config, {});
261
+ result.callback((id) => {
262
+ expect(id).to.be.undefined
263
+ });
264
+
265
+ let request = server.requests[0];
266
+ request.respond(200, {'Content-Type': 'application/json'}, '');
267
+
268
+ expect(setCookieStub.calledWith(FP_TEADS_ID_COOKIE_NAME, '', EXPIRED_COOKIE_DATE)).to.be.true;
269
+ });
270
+ });
271
+ });
@@ -405,6 +405,9 @@ describe('User ID', function () {
405
405
  init(config);
406
406
  setSubmoduleRegistry([amxIdSubmodule, sharedIdSystemSubmodule, identityLinkSubmodule, imuIdSubmodule]);
407
407
 
408
+ // before ppid should not be set
409
+ expect(window.googletag._ppid).to.equal(undefined);
410
+
408
411
  config.setConfig({
409
412
  userSync: {
410
413
  ppid: 'pubcid.org',
@@ -416,19 +419,52 @@ describe('User ID', function () {
416
419
  ]
417
420
  }
418
421
  });
419
- // before ppid should not be set
420
- expect(window.googletag._ppid).to.equal(undefined);
421
422
  return expectImmediateBidHook(() => {}, {adUnits}).then(() => {
422
423
  // ppid should have been set without dashes and stuff
423
424
  expect(window.googletag._ppid).to.equal('pubCommonidvaluepubCommonidvalue');
424
425
  });
425
426
  });
426
427
 
428
+ it('should set PPID when the source needs to call out to the network', () => {
429
+ let adUnits = [getAdUnitMock()];
430
+ init(config);
431
+ const callback = sinon.stub();
432
+ setSubmoduleRegistry([{
433
+ name: 'sharedId',
434
+ getId: function () {
435
+ return {callback}
436
+ },
437
+ decode(d) {
438
+ return d
439
+ }
440
+ }]);
441
+ config.setConfig({
442
+ userSync: {
443
+ ppid: 'pubcid.org',
444
+ auctionDelay: 10,
445
+ userIds: [
446
+ {
447
+ name: 'sharedId',
448
+ }
449
+ ]
450
+ }
451
+ });
452
+ return expectImmediateBidHook(() => {}, {adUnits}).then(() => {
453
+ expect(window.googletag._ppid).to.be.undefined;
454
+ const uid = 'thismustbelongerthan32characters'
455
+ callback.yield({pubcid: uid});
456
+ expect(window.googletag._ppid).to.equal(uid);
457
+ });
458
+ });
459
+
427
460
  it('should set googletag ppid correctly for imuIdSubmodule', function () {
428
461
  let adUnits = [getAdUnitMock()];
429
462
  init(config);
430
463
  setSubmoduleRegistry([imuIdSubmodule]);
431
464
 
465
+ // before ppid should not be set
466
+ expect(window.googletag._ppid).to.equal(undefined);
467
+
432
468
  config.setConfig({
433
469
  userSync: {
434
470
  ppid: 'ppid.intimatemerger.com',
@@ -437,8 +473,7 @@ describe('User ID', function () {
437
473
  ]
438
474
  }
439
475
  });
440
- // before ppid should not be set
441
- expect(window.googletag._ppid).to.equal(undefined);
476
+
442
477
  return expectImmediateBidHook(() => {}, {adUnits}).then(() => {
443
478
  // ppid should have been set without dashes and stuff
444
479
  expect(window.googletag._ppid).to.equal('imppidvalueimppidvalueimppidvalue');