prebid.js 5.17.0 → 6.0.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 (145) hide show
  1. package/.babelrc.js +3 -6
  2. package/README.md +3 -1
  3. package/browsers.json +1 -8
  4. package/integrationExamples/gpt/akamaidap_segments_example.html +132 -0
  5. package/modules/.submodules.json +1 -0
  6. package/modules/adfBidAdapter.js +21 -16
  7. package/modules/adgenerationBidAdapter.js +28 -4
  8. package/modules/adkernelBidAdapter.js +2 -1
  9. package/modules/admixerBidAdapter.js +11 -0
  10. package/modules/adtelligentBidAdapter.js +2 -1
  11. package/modules/airgridRtdProvider.js +1 -1
  12. package/modules/akamaiDapRtdProvider.js +474 -0
  13. package/modules/akamaiDapRtdProvider.md +47 -0
  14. package/modules/aolBidAdapter.js +2 -1
  15. package/modules/appnexusBidAdapter.js +5 -3
  16. package/modules/atsAnalyticsAdapter.js +67 -46
  17. package/modules/atsAnalyticsAdapter.md +1 -0
  18. package/modules/betweenBidAdapter.js +20 -3
  19. package/modules/bliinkBidAdapter.js +58 -32
  20. package/modules/bliinkBidAdapter.md +29 -6
  21. package/modules/browsiRtdProvider.js +106 -18
  22. package/modules/cleanioRtdProvider.js +192 -0
  23. package/modules/cleanioRtdProvider.md +59 -0
  24. package/modules/codefuelBidAdapter.js +183 -0
  25. package/modules/codefuelBidAdapter.md +111 -0
  26. package/modules/connectIdSystem.js +104 -0
  27. package/modules/connectIdSystem.md +33 -0
  28. package/modules/cwireBidAdapter.js +272 -0
  29. package/modules/cwireBidAdapter.md +43 -0
  30. package/modules/deepintentBidAdapter.js +106 -9
  31. package/modules/deepintentBidAdapter.md +36 -1
  32. package/modules/deltaprojectsBidAdapter.js +252 -0
  33. package/modules/deltaprojectsBidAdapter.md +32 -0
  34. package/modules/dgkeywordRtdProvider.js +0 -1
  35. package/modules/engageyaBidAdapter.js +157 -0
  36. package/modules/gridBidAdapter.js +1 -0
  37. package/modules/gumgumBidAdapter.js +8 -0
  38. package/modules/inskinBidAdapter.js +7 -3
  39. package/modules/ixBidAdapter.js +8 -1
  40. package/modules/jixieBidAdapter.js +8 -2
  41. package/modules/justpremiumBidAdapter.js +6 -1
  42. package/modules/limelightDigitalBidAdapter.js +22 -2
  43. package/modules/livewrappedAnalyticsAdapter.js +53 -3
  44. package/modules/mediakeysBidAdapter.js +2 -1
  45. package/modules/multibid/index.js +3 -3
  46. package/modules/nativoBidAdapter.js +6 -2
  47. package/modules/nextMillenniumBidAdapter.js +12 -3
  48. package/modules/oguryBidAdapter.js +36 -7
  49. package/modules/openxBidAdapter.js +34 -22
  50. package/modules/operaadsBidAdapter.js +21 -1
  51. package/modules/otmBidAdapter.js +146 -0
  52. package/modules/otmBidAdapter.md +27 -26
  53. package/modules/outbrainBidAdapter.js +5 -0
  54. package/modules/pixfutureBidAdapter.js +24 -4
  55. package/modules/pixfutureBidAdapter.md +127 -0
  56. package/modules/playwireBidAdapter.md +61 -0
  57. package/modules/prebidServerBidAdapter/index.js +1 -1
  58. package/modules/proxistoreBidAdapter.js +4 -6
  59. package/modules/publinkIdSystem.js +11 -6
  60. package/modules/pubmaticBidAdapter.js +9 -0
  61. package/modules/pubmaticBidAdapter.md +1 -1
  62. package/modules/rtdModule/index.js +2 -2
  63. package/modules/sonobiBidAdapter.js +7 -0
  64. package/modules/sortableBidAdapter.js +1 -0
  65. package/modules/talkadsBidAdapter.js +129 -0
  66. package/modules/talkadsBidAdapter.md +60 -0
  67. package/modules/teadsBidAdapter.js +3 -0
  68. package/modules/tripleliftBidAdapter.js +22 -5
  69. package/modules/trustxBidAdapter.js +8 -6
  70. package/modules/undertoneBidAdapter.js +9 -5
  71. package/modules/undertoneBidAdapter.md +5 -1
  72. package/modules/unicornBidAdapter.js +3 -3
  73. package/modules/userId/eids.js +18 -0
  74. package/modules/userId/eids.md +7 -0
  75. package/modules/userId/userId.md +12 -0
  76. package/modules/ventesBidAdapter.js +370 -0
  77. package/modules/ventesBidAdapter.md +94 -0
  78. package/modules/videobyteBidAdapter.js +13 -6
  79. package/modules/videobyteBidAdapter.md +49 -0
  80. package/modules/visxBidAdapter.js +15 -22
  81. package/modules/yahoosspBidAdapter.js +637 -0
  82. package/modules/yahoosspBidAdapter.md +795 -0
  83. package/modules/yieldlabBidAdapter.js +48 -3
  84. package/modules/yieldlabBidAdapter.md +16 -1
  85. package/modules/yieldmoSyntheticInventoryModule.js +46 -0
  86. package/modules/yieldmoSyntheticInventoryModule.md +68 -0
  87. package/package.json +1 -1
  88. package/src/adapterManager.js +5 -0
  89. package/src/adapters/bidderFactory.js +4 -3
  90. package/src/auction.js +11 -11
  91. package/src/constants.json +1 -0
  92. package/src/secureCreatives.js +6 -7
  93. package/src/targeting.js +11 -9
  94. package/test/spec/modules/adfBidAdapter_spec.js +83 -29
  95. package/test/spec/modules/adgenerationBidAdapter_spec.js +121 -50
  96. package/test/spec/modules/adtelligentBidAdapter_spec.js +1 -0
  97. package/test/spec/modules/akamaiDapRtdProvider_spec.js +246 -0
  98. package/test/spec/modules/appnexusBidAdapter_spec.js +2 -1
  99. package/test/spec/modules/atsAnalyticsAdapter_spec.js +42 -9
  100. package/test/spec/modules/betweenBidAdapter_spec.js +41 -0
  101. package/test/spec/modules/bliinkBidAdapter_spec.js +87 -36
  102. package/test/spec/modules/browsiRtdProvider_spec.js +62 -7
  103. package/test/spec/modules/cleanioRtdProvider_spec.js +188 -0
  104. package/test/spec/modules/codefuelBidAdapter_spec.js +316 -0
  105. package/test/spec/modules/connectIdSystem_spec.js +189 -0
  106. package/test/spec/modules/cwireBidAdapter_spec.js +246 -0
  107. package/test/spec/modules/deepintentBidAdapter_spec.js +153 -3
  108. package/test/spec/modules/deltaprojectsBidAdapter_spec.js +399 -0
  109. package/test/spec/modules/engageyaBidAdapter_spec.js +286 -0
  110. package/test/spec/modules/gumgumBidAdapter_spec.js +5 -1
  111. package/test/spec/modules/ixBidAdapter_spec.js +13 -3
  112. package/test/spec/modules/jixieBidAdapter_spec.js +13 -11
  113. package/test/spec/modules/justpremiumBidAdapter_spec.js +9 -2
  114. package/test/spec/modules/limelightDigitalBidAdapter_spec.js +155 -1
  115. package/test/spec/modules/livewrappedAnalyticsAdapter_spec.js +67 -12
  116. package/test/spec/modules/multibid_spec.js +31 -31
  117. package/test/spec/modules/nextMillenniumBidAdapter_spec.js +13 -1
  118. package/test/spec/modules/oguryBidAdapter_spec.js +125 -37
  119. package/test/spec/modules/openxBidAdapter_spec.js +85 -13
  120. package/test/spec/modules/operaadsBidAdapter_spec.js +38 -6
  121. package/test/spec/modules/otmBidAdapter_spec.js +67 -0
  122. package/test/spec/modules/outbrainBidAdapter_spec.js +18 -0
  123. package/test/spec/modules/publinkIdSystem_spec.js +6 -6
  124. package/test/spec/modules/pubmaticBidAdapter_spec.js +39 -1
  125. package/test/spec/modules/sonobiBidAdapter_spec.js +34 -1
  126. package/test/spec/modules/sortableBidAdapter_spec.js +11 -0
  127. package/test/spec/modules/talkadsBidAdapter_spec.js +231 -0
  128. package/test/spec/modules/teadsBidAdapter_spec.js +132 -0
  129. package/test/spec/modules/tripleliftBidAdapter_spec.js +128 -0
  130. package/test/spec/modules/trustxBidAdapter_spec.js +3 -3
  131. package/test/spec/modules/undertoneBidAdapter_spec.js +52 -0
  132. package/test/spec/modules/unicornBidAdapter_spec.js +4 -4
  133. package/test/spec/modules/ventesBidAdapter_spec.js +845 -0
  134. package/test/spec/modules/videobyteBidAdapter_spec.js +2 -2
  135. package/test/spec/modules/visxBidAdapter_spec.js +48 -4
  136. package/test/spec/modules/yahoosspBidAdapter_spec.js +1332 -0
  137. package/test/spec/modules/yieldlabBidAdapter_spec.js +65 -1
  138. package/test/spec/modules/yieldmoSyntheticInventoryModule_spec.js +89 -0
  139. package/test/spec/unit/core/adapterManager_spec.js +32 -0
  140. package/test/spec/unit/core/bidderFactory_spec.js +61 -1
  141. package/test/spec/unit/pbjs_api_spec.js +37 -2
  142. package/test/spec/unit/secureCreatives_spec.js +54 -25
  143. package/wdio.conf.js +1 -1
  144. package/modules/turktelekomBidAdapter.md +0 -49
  145. package/yarn.lock +0 -13122
@@ -0,0 +1,188 @@
1
+ import * as utils from '../../../src/utils.js';
2
+ import * as hook from '../../../src/hook.js'
3
+
4
+ import { __TEST__ } from '../../../modules/cleanioRtdProvider.js';
5
+
6
+ const {
7
+ readConfig,
8
+ ConfigError,
9
+ pageInitStepPreloadScript,
10
+ pageInitStepProtectPage,
11
+ bidWrapStepAugmentHtml,
12
+ bidWrapStepProtectByWrapping,
13
+ beforeInit,
14
+ } = __TEST__;
15
+
16
+ sinon.assert.expose(chai.assert, { prefix: 'sinon' });
17
+
18
+ const fakeScriptURL = 'https://example.com/script.js';
19
+
20
+ function makeFakeBidResponse() {
21
+ return {
22
+ ad: '<body>hello ad</body>',
23
+ bidderCode: 'BIDDER',
24
+ creativeId: 'CREATIVE',
25
+ cpm: 1.23,
26
+ };
27
+ }
28
+
29
+ describe('clean.io RTD module', function () {
30
+ describe('readConfig()', function() {
31
+ it('should throw ConfigError on invalid configurations', function() {
32
+ expect(() => readConfig({})).to.throw(ConfigError);
33
+ expect(() => readConfig({ params: {} })).to.throw(ConfigError);
34
+ expect(() => readConfig({ params: { protectionMode: 'bids' } })).to.throw(ConfigError);
35
+ expect(() => readConfig({ params: { cdnUrl: 'abc' } })).to.throw(ConfigError);
36
+ expect(() => readConfig({ params: { cdnUrl: 'abc', protectionMode: 'bids' } })).to.throw(ConfigError);
37
+ expect(() => readConfig({ params: { cdnUrl: 'https://abc1234567890.cloudfront.net/script.js', protectionMode: '123' } })).to.throw(ConfigError);
38
+ });
39
+
40
+ it('should accept valid configurations', function() {
41
+ expect(() => readConfig({ params: { cdnUrl: 'https://abc1234567890.cloudfront.net/script.js', protectionMode: 'full' } })).to.not.throw();
42
+ expect(() => readConfig({ params: { cdnUrl: 'https://abc1234567890.cloudfront.net/script.js', protectionMode: 'bids' } })).to.not.throw();
43
+ expect(() => readConfig({ params: { cdnUrl: 'https://abc1234567890.cloudfront.net/script.js', protectionMode: 'bids-nowait' } })).to.not.throw();
44
+ });
45
+ });
46
+
47
+ describe('Module initialization step', function() {
48
+ let insertElementStub;
49
+ beforeEach(function() {
50
+ insertElementStub = sinon.stub(utils, 'insertElement');
51
+ });
52
+ afterEach(function() {
53
+ utils.insertElement.restore();
54
+ });
55
+
56
+ it('pageInitStepPreloadScript() should insert link/preload element', function() {
57
+ pageInitStepPreloadScript(fakeScriptURL);
58
+
59
+ sinon.assert.calledOnce(insertElementStub);
60
+ sinon.assert.calledWith(insertElementStub, sinon.match(elem => elem.tagName === 'LINK'));
61
+ sinon.assert.calledWith(insertElementStub, sinon.match(elem => elem.rel === 'preload'));
62
+ sinon.assert.calledWith(insertElementStub, sinon.match(elem => elem.as === 'script'));
63
+ sinon.assert.calledWith(insertElementStub, sinon.match(elem => elem.href === fakeScriptURL));
64
+ });
65
+
66
+ it('pageInitStepProtectPage() should insert script element', function() {
67
+ pageInitStepProtectPage(fakeScriptURL);
68
+
69
+ sinon.assert.calledOnce(insertElementStub);
70
+ sinon.assert.calledWith(insertElementStub, sinon.match(elem => elem.tagName === 'SCRIPT'));
71
+ sinon.assert.calledWith(insertElementStub, sinon.match(elem => elem.type === 'text/javascript'));
72
+ sinon.assert.calledWith(insertElementStub, sinon.match(elem => elem.src === fakeScriptURL));
73
+ });
74
+ });
75
+
76
+ function ensurePrependToBidResponse(fakeBidResponse) {
77
+ expect(fakeBidResponse).to.have.own.property('ad').which.is.a('string');
78
+ expect(fakeBidResponse.ad).to.contain('<!-- pbad://creativeId=CREATIVE&bidderCode=BIDDER&cpm=1.23 -->');
79
+ }
80
+
81
+ function ensureWrapBidResponse(fakeBidResponse, scriptUrl) {
82
+ expect(fakeBidResponse).to.have.own.property('ad').which.is.a('string');
83
+ expect(fakeBidResponse.ad).to.contain(`src="${scriptUrl}"`);
84
+ expect(fakeBidResponse.ad).to.contain('agent.put(ad)');
85
+ }
86
+
87
+ describe('Bid processing step', function() {
88
+ it('bidWrapStepAugmentHtml() should prepend bid-specific information in a comment', function() {
89
+ const fakeBidResponse = makeFakeBidResponse();
90
+ bidWrapStepAugmentHtml(fakeBidResponse);
91
+ ensurePrependToBidResponse(fakeBidResponse);
92
+ });
93
+
94
+ it('bidWrapStepProtectByWrapping() should wrap payload into a script tag', function() {
95
+ const fakeBidResponse = makeFakeBidResponse();
96
+ bidWrapStepProtectByWrapping(fakeScriptURL, 0, fakeBidResponse);
97
+ ensureWrapBidResponse(fakeBidResponse, fakeScriptURL);
98
+ });
99
+ });
100
+
101
+ describe('Sumbodule execution', function() {
102
+ let submoduleStub;
103
+ let insertElementStub;
104
+ beforeEach(function () {
105
+ submoduleStub = sinon.stub(hook, 'submodule');
106
+ insertElementStub = sinon.stub(utils, 'insertElement');
107
+ });
108
+ afterEach(function () {
109
+ utils.insertElement.restore();
110
+ submoduleStub.restore();
111
+ });
112
+
113
+ function getModule() {
114
+ beforeInit();
115
+
116
+ expect(submoduleStub.calledOnceWith('realTimeData')).to.equal(true);
117
+
118
+ const registeredSubmoduleDefinition = submoduleStub.getCall(0).args[1];
119
+ expect(registeredSubmoduleDefinition).to.be.an('object');
120
+ expect(registeredSubmoduleDefinition).to.have.own.property('name', 'clean.io');
121
+ expect(registeredSubmoduleDefinition).to.have.own.property('init').that.is.a('function');
122
+ expect(registeredSubmoduleDefinition).to.have.own.property('onBidResponseEvent').that.is.a('function');
123
+
124
+ return registeredSubmoduleDefinition;
125
+ }
126
+
127
+ it('should register clean.io RTD submodule provider', function () {
128
+ getModule();
129
+ });
130
+
131
+ it('should refuse initialization with incorrect parameters', function () {
132
+ const { init } = getModule();
133
+ expect(init({ params: { cdnUrl: 'abc', protectionMode: 'full' } }, {})).to.equal(false); // too short distribution name
134
+ sinon.assert.notCalled(insertElementStub);
135
+ });
136
+
137
+ it('should iniitalize in full (page) protection mode', function () {
138
+ const { init, onBidResponseEvent } = getModule();
139
+ expect(init({ params: { cdnUrl: 'https://abc1234567890.cloudfront.net/script.js', protectionMode: 'full' } }, {})).to.equal(true);
140
+ sinon.assert.calledOnce(insertElementStub);
141
+ sinon.assert.calledWith(insertElementStub, sinon.match(elem => elem.tagName === 'SCRIPT'));
142
+
143
+ const fakeBidResponse = makeFakeBidResponse();
144
+ onBidResponseEvent(fakeBidResponse, {}, {});
145
+ ensurePrependToBidResponse(fakeBidResponse);
146
+ });
147
+
148
+ it('should iniitalize in bids (frame) protection mode', function () {
149
+ const { init, onBidResponseEvent } = getModule();
150
+ expect(init({ params: { cdnUrl: 'https://abc1234567890.cloudfront.net/script.js', protectionMode: 'bids' } }, {})).to.equal(true);
151
+ sinon.assert.calledOnce(insertElementStub);
152
+ sinon.assert.calledWith(insertElementStub, sinon.match(elem => elem.tagName === 'LINK'));
153
+
154
+ const fakeBidResponse = makeFakeBidResponse();
155
+ onBidResponseEvent(fakeBidResponse, {}, {});
156
+ ensureWrapBidResponse(fakeBidResponse, 'https://abc1234567890.cloudfront.net/script.js');
157
+ });
158
+
159
+ it('should respect preload status in bids-nowait protection mode', function () {
160
+ const { init, onBidResponseEvent } = getModule();
161
+ expect(init({ params: { cdnUrl: 'https://abc1234567890.cloudfront.net/script.js', protectionMode: 'bids-nowait' } }, {})).to.equal(true);
162
+ sinon.assert.calledOnce(insertElementStub);
163
+ sinon.assert.calledWith(insertElementStub, sinon.match(elem => elem.tagName === 'LINK'));
164
+ const preloadLink = insertElementStub.getCall(0).args[0];
165
+ expect(preloadLink).to.have.property('onload').which.is.a('function');
166
+ expect(preloadLink).to.have.property('onerror').which.is.a('function');
167
+
168
+ const fakeBidResponse1 = makeFakeBidResponse();
169
+ onBidResponseEvent(fakeBidResponse1, {}, {});
170
+ ensurePrependToBidResponse(fakeBidResponse1);
171
+
172
+ // Simulate successful preloading
173
+ preloadLink.onload();
174
+
175
+ const fakeBidResponse2 = makeFakeBidResponse();
176
+ onBidResponseEvent(fakeBidResponse2, {}, {});
177
+ ensureWrapBidResponse(fakeBidResponse2, 'https://abc1234567890.cloudfront.net/script.js');
178
+
179
+ // Simulate error
180
+ preloadLink.onerror();
181
+
182
+ // Now we should fallback to just prepending
183
+ const fakeBidResponse3 = makeFakeBidResponse();
184
+ onBidResponseEvent(fakeBidResponse3, {}, {});
185
+ ensurePrependToBidResponse(fakeBidResponse3);
186
+ });
187
+ });
188
+ });
@@ -0,0 +1,316 @@
1
+ import {expect} from 'chai';
2
+ import {spec} from 'modules/codefuelBidAdapter.js';
3
+ import {config} from 'src/config.js';
4
+ import {server} from 'test/mocks/xhr';
5
+
6
+ const USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/92.0.4515.159 Safari/537.36';
7
+ const DEFAULT_USER_AGENT = window.navigator.userAgent;
8
+ const setUADefault = () => { window.navigator.__defineGetter__('userAgent', function () { return DEFAULT_USER_AGENT }) };
9
+ const setUAMock = () => { window.navigator.__defineGetter__('userAgent', function () { return USER_AGENT }) };
10
+
11
+ describe('Codefuel Adapter', function () {
12
+ describe('Bid request and response', function () {
13
+ const commonBidRequest = {
14
+ bidder: 'codefuel',
15
+ params: {
16
+ publisher: {
17
+ id: 'publisher-id'
18
+ },
19
+ },
20
+ bidId: '2d6815a92ba1ba',
21
+ auctionId: '12043683-3254-4f74-8934-f941b085579e',
22
+ }
23
+ const nativeBidRequestParams = {
24
+ nativeParams: {
25
+ image: {
26
+ required: true,
27
+ sizes: [
28
+ 120,
29
+ 100
30
+ ],
31
+ sendId: true
32
+ },
33
+ title: {
34
+ required: true,
35
+ sendId: true
36
+ },
37
+ sponsoredBy: {
38
+ required: false
39
+ }
40
+ },
41
+ }
42
+
43
+ const displayBidRequestParams = {
44
+ sizes: [
45
+ [
46
+ 300,
47
+ 250
48
+ ]
49
+ ]
50
+ }
51
+
52
+ describe('isBidRequestValid', function () {
53
+ before(() => {
54
+ config.setConfig({
55
+ codefuel: {
56
+ bidderUrl: 'https://bidder-url.com',
57
+ }
58
+ }
59
+ )
60
+ })
61
+ after(() => {
62
+ config.resetConfig()
63
+ })
64
+
65
+ it('should fail when bid is invalid', function () {
66
+ const bid = {
67
+ bidder: 'codefuel',
68
+ params: {
69
+ publisher: {
70
+ id: 'publisher-id',
71
+ }
72
+ },
73
+ }
74
+ expect(spec.isBidRequestValid(bid)).to.equal(false)
75
+ })
76
+ it('should not succeed when bid contains native params', function () {
77
+ const bid = {
78
+ bidder: 'codefuel',
79
+ params: {
80
+ publisher: {
81
+ id: 'publisher-id',
82
+ }
83
+ },
84
+ ...nativeBidRequestParams,
85
+ }
86
+ expect(spec.isBidRequestValid(bid)).to.equal(false)
87
+ })
88
+ it('should not succeed when bid contains only sizes', function () {
89
+ const bid = {
90
+ bidder: 'codefuel',
91
+ params: {
92
+ publisher: {
93
+ id: 'publisher-id',
94
+ }
95
+ },
96
+ ...displayBidRequestParams,
97
+ }
98
+ expect(spec.isBidRequestValid(bid)).to.equal(false)
99
+ })
100
+ it('should fail if publisher id is not set', function () {
101
+ const bid = {
102
+ bidder: 'codefuel',
103
+ ...nativeBidRequestParams,
104
+ }
105
+ expect(spec.isBidRequestValid(bid)).to.equal(false)
106
+ })
107
+
108
+ it('should fail if bidder url is not set', function () {
109
+ const bid = {
110
+ bidder: 'codefuel',
111
+ params: {
112
+ publisher: {
113
+ id: 'publisher-id',
114
+ }
115
+ },
116
+ ...nativeBidRequestParams,
117
+ }
118
+ config.resetConfig()
119
+ expect(spec.isBidRequestValid(bid)).to.equal(false)
120
+ })
121
+ })
122
+
123
+ describe('buildRequests', function () {
124
+ before(() => {
125
+ setUAMock()
126
+ config.setConfig({
127
+ codefuel: {
128
+ bidderUrl: 'https://bidder-url.com',
129
+ }
130
+ }
131
+ )
132
+ })
133
+ after(() => {
134
+ config.resetConfig()
135
+ setUADefault()
136
+ })
137
+
138
+ const commonBidderRequest = {
139
+ timeout: 500,
140
+ auctionId: '12043683-3254-4f74-8934-f941b085579e',
141
+ refererInfo: {
142
+ referer: 'https://example.com/',
143
+ }
144
+ }
145
+
146
+ it('should build display request', function () {
147
+ const bidRequest = {
148
+ ...commonBidRequest,
149
+ ...displayBidRequestParams,
150
+ }
151
+ const expectedData = {
152
+ cur: [
153
+ 'USD'
154
+ ],
155
+ device: {
156
+ devicetype: 2,
157
+ ua: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/92.0.4515.159 Safari/537.36'
158
+ },
159
+ id: '12043683-3254-4f74-8934-f941b085579e',
160
+ imp: [
161
+ {
162
+ banner: {
163
+ format: [
164
+ {
165
+ h: 250,
166
+ w: 300
167
+ }
168
+ ]
169
+ },
170
+ id: '1'
171
+ }
172
+ ],
173
+ site: {
174
+ domain: 'example.com',
175
+ page: 'https://example.com/',
176
+ publisher: {
177
+ id: 'publisher-id'
178
+ }
179
+ },
180
+ source: {
181
+ fd: 1
182
+ },
183
+ tmax: 500
184
+ }
185
+ const res = spec.buildRequests([bidRequest], commonBidderRequest)
186
+ expect(res.url).to.equal('https://bidder-url.com')
187
+ expect(res.data).to.deep.equal(expectedData)
188
+ })
189
+
190
+ it('should pass bidder timeout', function () {
191
+ const bidRequest = {
192
+ ...commonBidRequest,
193
+ }
194
+ const bidderRequest = {
195
+ ...commonBidderRequest,
196
+ timeout: 500
197
+ }
198
+ const res = spec.buildRequests([bidRequest], bidderRequest)
199
+ const resData = res.data
200
+ expect(resData.tmax).to.equal(500)
201
+ });
202
+ })
203
+
204
+ describe('interpretResponse', function () {
205
+ it('should return empty array if no valid bids', function () {
206
+ const res = spec.interpretResponse({}, [])
207
+ expect(res).to.be.an('array').that.is.empty
208
+ });
209
+
210
+ it('should interpret display response', function () {
211
+ const serverResponse = {
212
+ body: {
213
+ id: '6b2eedc8-8ff5-46ef-adcf-e701b508943e',
214
+ seatbid: [
215
+ {
216
+ bid: [
217
+ {
218
+ id: 'd90fe7fa-28d7-11eb-8ce4-462a842a7cf9',
219
+ impid: '1',
220
+ price: 1.1,
221
+ nurl: 'http://example.com/win/${AUCTION_PRICE}',
222
+ adm: '<div>ad</div>',
223
+ adomain: [
224
+ 'example.com'
225
+ ],
226
+ cid: '3865084',
227
+ crid: '29998660',
228
+ cat: [
229
+ 'IAB10-2'
230
+ ],
231
+ w: 300,
232
+ h: 250
233
+ }
234
+ ],
235
+ seat: 'acc-6536'
236
+ }
237
+ ],
238
+ bidid: 'd90fe7fa-28d7-11eb-8ce4-13d94bfa26f9',
239
+ cur: 'USD'
240
+ }
241
+ }
242
+ const request = {
243
+ bids: [
244
+ {
245
+ ...commonBidRequest,
246
+ ...displayBidRequestParams
247
+ }
248
+ ]
249
+ }
250
+ const expectedRes = [
251
+ {
252
+ requestId: request.bids[0].bidId,
253
+ cpm: 1.1,
254
+ creativeId: '29998660',
255
+ ttl: 360,
256
+ netRevenue: true,
257
+ currency: 'USD',
258
+ mediaType: 'banner',
259
+ ad: '<div>ad</div>',
260
+ width: 300,
261
+ height: 250,
262
+ meta: {'advertiserDomains': []}
263
+ }
264
+ ]
265
+
266
+ const res = spec.interpretResponse(serverResponse, request)
267
+ expect(res).to.deep.equal(expectedRes)
268
+ });
269
+ })
270
+ })
271
+
272
+ describe('getUserSyncs', function () {
273
+ const usersyncUrl = 'https://usersync-url.com';
274
+ beforeEach(() => {
275
+ config.setConfig({
276
+ codefuel: {
277
+ usersyncUrl: usersyncUrl,
278
+ }
279
+ }
280
+ )
281
+ })
282
+ after(() => {
283
+ config.resetConfig()
284
+ })
285
+
286
+ it('should not return user sync if pixel enabled with codefuel config', function () {
287
+ const ret = spec.getUserSyncs({pixelEnabled: true})
288
+ expect(ret).to.be.an('array').that.is.empty
289
+ })
290
+
291
+ it('should not return user sync if pixel disabled', function () {
292
+ const ret = spec.getUserSyncs({pixelEnabled: false})
293
+ expect(ret).to.be.an('array').that.is.empty
294
+ })
295
+
296
+ it('should not return user sync if url is not set', function () {
297
+ config.resetConfig()
298
+ const ret = spec.getUserSyncs({pixelEnabled: true})
299
+ expect(ret).to.be.an('array').that.is.empty
300
+ })
301
+
302
+ it('should not pass GDPR consent', function() {
303
+ expect(spec.getUserSyncs({ pixelEnabled: true }, {}, {gdprApplies: true, consentString: 'foo'}, undefined)).to.to.be.an('array').that.is.empty
304
+ expect(spec.getUserSyncs({ pixelEnabled: true }, {}, {gdprApplies: false, consentString: 'foo'}, undefined)).to.be.an('array').that.is.empty
305
+ expect(spec.getUserSyncs({ pixelEnabled: true }, {}, {gdprApplies: true, consentString: undefined}, undefined)).to.be.an('array').that.is.empty
306
+ });
307
+
308
+ it('should not pass US consent', function() {
309
+ expect(spec.getUserSyncs({ pixelEnabled: true }, {}, undefined, '1NYN')).to.be.an('array').that.is.empty
310
+ });
311
+
312
+ it('should pass GDPR and US consent', function() {
313
+ expect(spec.getUserSyncs({ pixelEnabled: true }, {}, {gdprApplies: true, consentString: 'foo'}, '1NYN')).to.be.an('array').that.is.empty
314
+ });
315
+ })
316
+ })
@@ -0,0 +1,189 @@
1
+ import {expect} from 'chai';
2
+ import {parseQS} from 'src/utils.js';
3
+ import {connectIdSubmodule} from 'modules/connectIdSystem.js';
4
+
5
+ describe('Yahoo ConnectID Submodule', () => {
6
+ const HASHED_EMAIL = '6bda6f2fa268bf0438b5423a9861a2cedaa5dec163c03f743cfe05c08a8397b2';
7
+ const PIXEL_ID = '1234';
8
+ const PROD_ENDPOINT = `https://ups.analytics.yahoo.com/ups/${PIXEL_ID}/fed`;
9
+ const OVERRIDE_ENDPOINT = 'https://foo/bar';
10
+
11
+ it('should have the correct module name declared', () => {
12
+ expect(connectIdSubmodule.name).to.equal('connectId');
13
+ });
14
+
15
+ it('should have the correct TCFv2 Vendor ID declared', () => {
16
+ expect(connectIdSubmodule.gvlid).to.equal(25);
17
+ });
18
+
19
+ describe('getId()', () => {
20
+ let ajaxStub;
21
+ let getAjaxFnStub;
22
+ let consentData;
23
+ beforeEach(() => {
24
+ ajaxStub = sinon.stub();
25
+ getAjaxFnStub = sinon.stub(connectIdSubmodule, 'getAjaxFn');
26
+ getAjaxFnStub.returns(ajaxStub);
27
+
28
+ consentData = {
29
+ gdpr: {
30
+ gdprApplies: 1,
31
+ consentString: 'GDPR_CONSENT_STRING'
32
+ },
33
+ uspConsent: 'USP_CONSENT_STRING'
34
+ };
35
+ });
36
+
37
+ afterEach(() => {
38
+ getAjaxFnStub.restore();
39
+ });
40
+
41
+ function invokeGetIdAPI(configParams, consentData) {
42
+ let result = connectIdSubmodule.getId({
43
+ params: configParams
44
+ }, consentData);
45
+ if (typeof result === 'object') {
46
+ result.callback(sinon.stub());
47
+ }
48
+ return result;
49
+ }
50
+
51
+ it('returns undefined if he and pixelId params are not passed', () => {
52
+ expect(invokeGetIdAPI({}, consentData)).to.be.undefined;
53
+ expect(ajaxStub.callCount).to.equal(0);
54
+ });
55
+
56
+ it('returns undefined if the pixelId param is not passed', () => {
57
+ expect(invokeGetIdAPI({
58
+ he: HASHED_EMAIL
59
+ }, consentData)).to.be.undefined;
60
+ expect(ajaxStub.callCount).to.equal(0);
61
+ });
62
+
63
+ it('returns undefined if the he param is not passed', () => {
64
+ expect(invokeGetIdAPI({
65
+ pixelId: PIXEL_ID
66
+ }, consentData)).to.be.undefined;
67
+ expect(ajaxStub.callCount).to.equal(0);
68
+ });
69
+
70
+ it('returns an object with the callback function if the correct params are passed', () => {
71
+ let result = invokeGetIdAPI({
72
+ he: HASHED_EMAIL,
73
+ pixelId: PIXEL_ID
74
+ }, consentData);
75
+ expect(result).to.be.an('object').that.has.all.keys('callback');
76
+ expect(result.callback).to.be.a('function');
77
+ });
78
+
79
+ it('Makes an ajax GET request to the production API endpoint with query params', () => {
80
+ invokeGetIdAPI({
81
+ he: HASHED_EMAIL,
82
+ pixelId: PIXEL_ID
83
+ }, consentData);
84
+
85
+ const expectedParams = {
86
+ he: HASHED_EMAIL,
87
+ pixelId: PIXEL_ID,
88
+ '1p': '0',
89
+ gdpr: '1',
90
+ gdpr_consent: consentData.gdpr.consentString,
91
+ us_privacy: consentData.uspConsent
92
+ };
93
+ const requestQueryParams = parseQS(ajaxStub.firstCall.args[0].split('?')[1]);
94
+
95
+ expect(ajaxStub.firstCall.args[0].indexOf(`${PROD_ENDPOINT}?`)).to.equal(0);
96
+ expect(requestQueryParams).to.deep.equal(expectedParams);
97
+ expect(ajaxStub.firstCall.args[3]).to.deep.equal({method: 'GET', withCredentials: true});
98
+ });
99
+
100
+ it('Makes an ajax GET request to the specified override API endpoint with query params', () => {
101
+ invokeGetIdAPI({
102
+ he: HASHED_EMAIL,
103
+ endpoint: OVERRIDE_ENDPOINT
104
+ }, consentData);
105
+
106
+ const expectedParams = {
107
+ he: HASHED_EMAIL,
108
+ '1p': '0',
109
+ gdpr: '1',
110
+ gdpr_consent: consentData.gdpr.consentString,
111
+ us_privacy: consentData.uspConsent
112
+ };
113
+ const requestQueryParams = parseQS(ajaxStub.firstCall.args[0].split('?')[1]);
114
+
115
+ expect(ajaxStub.firstCall.args[0].indexOf(`${OVERRIDE_ENDPOINT}?`)).to.equal(0);
116
+ expect(requestQueryParams).to.deep.equal(expectedParams);
117
+ expect(ajaxStub.firstCall.args[3]).to.deep.equal({method: 'GET', withCredentials: true});
118
+ });
119
+
120
+ it('sets the callbacks param of the ajax function call correctly', () => {
121
+ invokeGetIdAPI({
122
+ he: HASHED_EMAIL,
123
+ pixelId: PIXEL_ID,
124
+ }, consentData);
125
+
126
+ expect(ajaxStub.firstCall.args[1]).to.be.an('object').that.has.all.keys(['success', 'error']);
127
+ });
128
+
129
+ it('sets GDPR consent data flag correctly when call is under GDPR jurisdiction.', () => {
130
+ invokeGetIdAPI({
131
+ he: HASHED_EMAIL,
132
+ pixelId: PIXEL_ID,
133
+ }, consentData);
134
+
135
+ const requestQueryParams = parseQS(ajaxStub.firstCall.args[0].split('?')[1]);
136
+ expect(requestQueryParams.gdpr).to.equal('1');
137
+ expect(requestQueryParams.gdpr_consent).to.equal(consentData.gdpr.consentString);
138
+ });
139
+
140
+ it('sets GDPR consent data flag correctly when call is NOT under GDPR jurisdiction.', () => {
141
+ consentData.gdpr.gdprApplies = false;
142
+
143
+ invokeGetIdAPI({
144
+ he: HASHED_EMAIL,
145
+ pixelId: PIXEL_ID,
146
+ }, consentData);
147
+
148
+ const requestQueryParams = parseQS(ajaxStub.firstCall.args[0].split('?')[1]);
149
+ expect(requestQueryParams.gdpr).to.equal('0');
150
+ expect(requestQueryParams.gdpr_consent).to.equal('');
151
+ });
152
+
153
+ [1, '1', true].forEach(firstPartyParamValue => {
154
+ it(`sets 1p payload property to '1' for a config value of ${firstPartyParamValue}`, () => {
155
+ invokeGetIdAPI({
156
+ '1p': firstPartyParamValue,
157
+ he: HASHED_EMAIL,
158
+ pixelId: PIXEL_ID,
159
+ }, consentData);
160
+
161
+ const requestQueryParams = parseQS(ajaxStub.firstCall.args[0].split('?')[1]);
162
+ expect(requestQueryParams['1p']).to.equal('1');
163
+ });
164
+ });
165
+ });
166
+
167
+ describe('decode()', () => {
168
+ const VALID_API_RESPONSES = [{
169
+ key: 'connectid',
170
+ expected: '4567',
171
+ payload: {
172
+ connectid: '4567'
173
+ }
174
+ }];
175
+ VALID_API_RESPONSES.forEach(responseData => {
176
+ it('should return a newly constructed object with the connect ID for a payload with ${responseData.key} key(s)', () => {
177
+ expect(connectIdSubmodule.decode(responseData.payload)).to.deep.equal(
178
+ {connectId: responseData.expected}
179
+ );
180
+ });
181
+ });
182
+
183
+ [{}, '', {foo: 'bar'}].forEach((response) => {
184
+ it(`should return undefined for an invalid response "${JSON.stringify(response)}"`, () => {
185
+ expect(connectIdSubmodule.decode(response)).to.be.undefined;
186
+ });
187
+ });
188
+ });
189
+ });