prebid.js 5.19.0 → 5.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.
- package/modules/airgridRtdProvider.js +1 -1
- package/modules/appnexusBidAdapter.js +5 -3
- package/modules/atsAnalyticsAdapter.js +67 -46
- package/modules/atsAnalyticsAdapter.md +1 -0
- package/modules/betweenBidAdapter.js +2 -1
- package/modules/browsiRtdProvider.js +106 -18
- package/modules/cleanioRtdProvider.js +192 -0
- package/modules/cleanioRtdProvider.md +59 -0
- package/modules/deltaprojectsBidAdapter.js +252 -0
- package/modules/deltaprojectsBidAdapter.md +32 -0
- package/modules/gridBidAdapter.js +1 -0
- package/modules/ixBidAdapter.js +7 -1
- package/modules/jixieBidAdapter.js +8 -2
- package/modules/justpremiumBidAdapter.js +6 -1
- package/modules/livewrappedAnalyticsAdapter.js +5 -0
- package/modules/multibid/index.js +3 -3
- package/modules/nativoBidAdapter.js +5 -1
- package/modules/openxBidAdapter.js +1 -1
- package/modules/operaadsBidAdapter.js +21 -1
- package/modules/otmBidAdapter.js +146 -0
- package/modules/otmBidAdapter.md +27 -26
- package/modules/outbrainBidAdapter.js +5 -0
- package/modules/playwireBidAdapter.md +61 -0
- package/modules/rtdModule/index.js +2 -2
- package/modules/sonobiBidAdapter.js +7 -0
- package/modules/sortableBidAdapter.js +1 -0
- package/modules/teadsBidAdapter.js +3 -0
- package/modules/trustxBidAdapter.js +8 -6
- package/modules/ventesBidAdapter.js +370 -0
- package/modules/ventesBidAdapter.md +94 -0
- package/modules/yahoosspBidAdapter.js +6 -6
- package/package.json +1 -1
- package/src/auction.js +11 -11
- package/test/spec/modules/appnexusBidAdapter_spec.js +2 -1
- package/test/spec/modules/atsAnalyticsAdapter_spec.js +42 -9
- package/test/spec/modules/browsiRtdProvider_spec.js +62 -7
- package/test/spec/modules/cleanioRtdProvider_spec.js +188 -0
- package/test/spec/modules/deltaprojectsBidAdapter_spec.js +399 -0
- package/test/spec/modules/ixBidAdapter_spec.js +3 -3
- package/test/spec/modules/jixieBidAdapter_spec.js +13 -11
- package/test/spec/modules/justpremiumBidAdapter_spec.js +9 -2
- package/test/spec/modules/livewrappedAnalyticsAdapter_spec.js +23 -4
- package/test/spec/modules/multibid_spec.js +31 -31
- package/test/spec/modules/openxBidAdapter_spec.js +0 -26
- package/test/spec/modules/operaadsBidAdapter_spec.js +38 -6
- package/test/spec/modules/otmBidAdapter_spec.js +67 -0
- package/test/spec/modules/outbrainBidAdapter_spec.js +18 -0
- package/test/spec/modules/sonobiBidAdapter_spec.js +34 -1
- package/test/spec/modules/sortableBidAdapter_spec.js +11 -0
- package/test/spec/modules/teadsBidAdapter_spec.js +132 -0
- package/test/spec/modules/trustxBidAdapter_spec.js +3 -3
- package/test/spec/modules/ventesBidAdapter_spec.js +845 -0
- package/test/spec/unit/core/adapterManager_spec.js +2 -1
|
@@ -144,9 +144,9 @@ function getAdapterMode() {
|
|
|
144
144
|
|
|
145
145
|
function getResponseFormat(bid) {
|
|
146
146
|
const adm = bid.adm;
|
|
147
|
-
if (adm.
|
|
147
|
+
if (adm.indexOf('o2playerSettings') !== -1 || adm.indexOf('YAHOO.VideoPlatform.VideoPlayer') !== -1 || adm.indexOf('AdPlacement') !== -1) {
|
|
148
148
|
return BANNER;
|
|
149
|
-
} else if (adm.
|
|
149
|
+
} else if (adm.indexOf('VAST') !== -1) {
|
|
150
150
|
return VIDEO;
|
|
151
151
|
}
|
|
152
152
|
};
|
|
@@ -188,23 +188,23 @@ function validateAppendObject(validationType, allowedKeys, inputObject, appendTo
|
|
|
188
188
|
for (const objectKey in inputObject) {
|
|
189
189
|
switch (validationType) {
|
|
190
190
|
case 'string':
|
|
191
|
-
if (allowedKeys.
|
|
191
|
+
if (allowedKeys.indexOf(objectKey) !== -1 && isStr(inputObject[objectKey])) {
|
|
192
192
|
outputObject[objectKey] = inputObject[objectKey];
|
|
193
193
|
};
|
|
194
194
|
break;
|
|
195
195
|
case 'number':
|
|
196
|
-
if (allowedKeys.
|
|
196
|
+
if (allowedKeys.indexOf(objectKey) !== -1 && isNumber(inputObject[objectKey])) {
|
|
197
197
|
outputObject[objectKey] = inputObject[objectKey];
|
|
198
198
|
};
|
|
199
199
|
break;
|
|
200
200
|
|
|
201
201
|
case 'array':
|
|
202
|
-
if (allowedKeys.
|
|
202
|
+
if (allowedKeys.indexOf(objectKey) !== -1 && isArray(inputObject[objectKey])) {
|
|
203
203
|
outputObject[objectKey] = inputObject[objectKey];
|
|
204
204
|
};
|
|
205
205
|
break;
|
|
206
206
|
case 'object':
|
|
207
|
-
if (allowedKeys.
|
|
207
|
+
if (allowedKeys.indexOf(objectKey) !== -1 && isPlainObject(inputObject[objectKey])) {
|
|
208
208
|
outputObject[objectKey] = inputObject[objectKey];
|
|
209
209
|
};
|
|
210
210
|
break;
|
package/package.json
CHANGED
package/src/auction.js
CHANGED
|
@@ -613,7 +613,8 @@ export const getPriceGranularity = (mediaType, bidReq) => {
|
|
|
613
613
|
* @returns {function}
|
|
614
614
|
*/
|
|
615
615
|
export const getPriceByGranularity = (granularity) => {
|
|
616
|
-
return (bid) => {
|
|
616
|
+
return (bid, bidReq) => {
|
|
617
|
+
granularity = granularity || getPriceGranularity(bid.mediaType, bidReq);
|
|
617
618
|
if (granularity === CONSTANTS.GRANULARITY_OPTIONS.AUTO) {
|
|
618
619
|
return bid.pbAg;
|
|
619
620
|
} else if (granularity === CONSTANTS.GRANULARITY_OPTIONS.DENSE) {
|
|
@@ -646,14 +647,14 @@ export const getAdvertiserDomain = () => {
|
|
|
646
647
|
* @param {BidRequest} bidReq
|
|
647
648
|
* @returns {*}
|
|
648
649
|
*/
|
|
649
|
-
export function getStandardBidderSettings(mediaType, bidderCode
|
|
650
|
+
export function getStandardBidderSettings(mediaType, bidderCode) {
|
|
650
651
|
// factory for key value objs
|
|
651
652
|
function createKeyVal(key, value) {
|
|
652
653
|
return {
|
|
653
654
|
key,
|
|
654
655
|
val: (typeof value === 'function')
|
|
655
|
-
? function (bidResponse) {
|
|
656
|
-
return value(bidResponse);
|
|
656
|
+
? function (bidResponse, bidReq) {
|
|
657
|
+
return value(bidResponse, bidReq);
|
|
657
658
|
}
|
|
658
659
|
: function (bidResponse) {
|
|
659
660
|
return getValue(bidResponse, value);
|
|
@@ -661,7 +662,6 @@ export function getStandardBidderSettings(mediaType, bidderCode, bidReq) {
|
|
|
661
662
|
};
|
|
662
663
|
}
|
|
663
664
|
const TARGETING_KEYS = CONSTANTS.TARGETING_KEYS;
|
|
664
|
-
const granularity = getPriceGranularity(mediaType, bidReq);
|
|
665
665
|
|
|
666
666
|
let bidderSettings = $$PREBID_GLOBAL$$.bidderSettings;
|
|
667
667
|
if (!bidderSettings[CONSTANTS.JSON_MAPPING.BD_SETTING_STANDARD]) {
|
|
@@ -671,7 +671,7 @@ export function getStandardBidderSettings(mediaType, bidderCode, bidReq) {
|
|
|
671
671
|
bidderSettings[CONSTANTS.JSON_MAPPING.BD_SETTING_STANDARD][CONSTANTS.JSON_MAPPING.ADSERVER_TARGETING] = [
|
|
672
672
|
createKeyVal(TARGETING_KEYS.BIDDER, 'bidderCode'),
|
|
673
673
|
createKeyVal(TARGETING_KEYS.AD_ID, 'adId'),
|
|
674
|
-
createKeyVal(TARGETING_KEYS.PRICE_BUCKET, getPriceByGranularity(
|
|
674
|
+
createKeyVal(TARGETING_KEYS.PRICE_BUCKET, getPriceByGranularity()),
|
|
675
675
|
createKeyVal(TARGETING_KEYS.SIZE, 'size'),
|
|
676
676
|
createKeyVal(TARGETING_KEYS.DEAL, 'dealId'),
|
|
677
677
|
createKeyVal(TARGETING_KEYS.SOURCE, 'source'),
|
|
@@ -716,12 +716,12 @@ export function getKeyValueTargetingPairs(bidderCode, custBidObj, bidReq) {
|
|
|
716
716
|
// 1) set the keys from "standard" setting or from prebid defaults
|
|
717
717
|
if (bidderSettings) {
|
|
718
718
|
// initialize default if not set
|
|
719
|
-
const standardSettings = getStandardBidderSettings(custBidObj.mediaType, bidderCode
|
|
720
|
-
setKeys(keyValues, standardSettings, custBidObj);
|
|
719
|
+
const standardSettings = getStandardBidderSettings(custBidObj.mediaType, bidderCode);
|
|
720
|
+
setKeys(keyValues, standardSettings, custBidObj, bidReq);
|
|
721
721
|
|
|
722
722
|
// 2) set keys from specific bidder setting override if they exist
|
|
723
723
|
if (bidderCode && bidderSettings[bidderCode] && bidderSettings[bidderCode][CONSTANTS.JSON_MAPPING.ADSERVER_TARGETING]) {
|
|
724
|
-
setKeys(keyValues, bidderSettings[bidderCode], custBidObj);
|
|
724
|
+
setKeys(keyValues, bidderSettings[bidderCode], custBidObj, bidReq);
|
|
725
725
|
custBidObj.sendStandardTargeting = bidderSettings[bidderCode].sendStandardTargeting;
|
|
726
726
|
}
|
|
727
727
|
}
|
|
@@ -734,7 +734,7 @@ export function getKeyValueTargetingPairs(bidderCode, custBidObj, bidReq) {
|
|
|
734
734
|
return keyValues;
|
|
735
735
|
}
|
|
736
736
|
|
|
737
|
-
function setKeys(keyValues, bidderSettings, custBidObj) {
|
|
737
|
+
function setKeys(keyValues, bidderSettings, custBidObj, bidReq) {
|
|
738
738
|
var targeting = bidderSettings[CONSTANTS.JSON_MAPPING.ADSERVER_TARGETING];
|
|
739
739
|
custBidObj.size = custBidObj.getSize();
|
|
740
740
|
|
|
@@ -748,7 +748,7 @@ function setKeys(keyValues, bidderSettings, custBidObj) {
|
|
|
748
748
|
|
|
749
749
|
if (isFn(value)) {
|
|
750
750
|
try {
|
|
751
|
-
value = value(custBidObj);
|
|
751
|
+
value = value(custBidObj, bidReq);
|
|
752
752
|
} catch (e) {
|
|
753
753
|
logError('bidmanager', 'ERROR', e);
|
|
754
754
|
}
|
|
@@ -1047,7 +1047,8 @@ describe('AppNexusAdapter', function () {
|
|
|
1047
1047
|
'trackers': [
|
|
1048
1048
|
{
|
|
1049
1049
|
'impression_urls': [
|
|
1050
|
-
'https://lax1-ib.adnxs.com/impression'
|
|
1050
|
+
'https://lax1-ib.adnxs.com/impression',
|
|
1051
|
+
'https://www.test.com/tracker'
|
|
1051
1052
|
],
|
|
1052
1053
|
'video_events': {}
|
|
1053
1054
|
}
|
|
@@ -12,11 +12,15 @@ let constants = require('src/constants.json');
|
|
|
12
12
|
|
|
13
13
|
export const storage = getStorageManager();
|
|
14
14
|
let sandbox;
|
|
15
|
+
let clock;
|
|
16
|
+
let now = new Date();
|
|
17
|
+
|
|
15
18
|
describe('ats analytics adapter', function () {
|
|
16
19
|
beforeEach(function () {
|
|
17
20
|
sinon.stub(events, 'getEvents').returns([]);
|
|
18
21
|
storage.setCookie('_lr_env_src_ats', 'true', 'Thu, 01 Jan 1970 00:00:01 GMT');
|
|
19
22
|
sandbox = sinon.sandbox.create();
|
|
23
|
+
clock = sandbox.useFakeTimers(now.getTime());
|
|
20
24
|
});
|
|
21
25
|
|
|
22
26
|
afterEach(function () {
|
|
@@ -25,18 +29,20 @@ describe('ats analytics adapter', function () {
|
|
|
25
29
|
atsAnalyticsAdapter.disableAnalytics();
|
|
26
30
|
Math.random.restore();
|
|
27
31
|
sandbox.restore();
|
|
32
|
+
clock.restore();
|
|
28
33
|
});
|
|
29
34
|
|
|
30
35
|
describe('track', function () {
|
|
31
36
|
it('builds and sends request and response data', function () {
|
|
32
37
|
sinon.stub(Math, 'random').returns(0.99);
|
|
33
|
-
sinon.stub(atsAnalyticsAdapter, 'shouldFireRequest').returns(true);
|
|
34
38
|
sinon.stub(atsAnalyticsAdapter, 'getUserAgent').returns('Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_5) AppleWebKit/536.25 (KHTML, like Gecko) Version/6.0 Safari/536.25');
|
|
35
|
-
|
|
39
|
+
|
|
36
40
|
now.setTime(now.getTime() + 3600000);
|
|
37
41
|
storage.setCookie('_lr_env_src_ats', 'true', now.toUTCString());
|
|
38
42
|
storage.setCookie('_lr_sampling_rate', '10', now.toUTCString());
|
|
39
43
|
|
|
44
|
+
this.timeout(2100);
|
|
45
|
+
|
|
40
46
|
let initOptions = {
|
|
41
47
|
pid: '10433394'
|
|
42
48
|
};
|
|
@@ -62,7 +68,7 @@ describe('ats analytics adapter', function () {
|
|
|
62
68
|
'refererInfo': {
|
|
63
69
|
'referer': 'https://example.com/dev'
|
|
64
70
|
},
|
|
65
|
-
'auctionId': 'a5b849e5-87d7-4205-8300-d063084fcfb7'
|
|
71
|
+
'auctionId': 'a5b849e5-87d7-4205-8300-d063084fcfb7'
|
|
66
72
|
};
|
|
67
73
|
// prepare general auction - response
|
|
68
74
|
let bidResponse = {
|
|
@@ -90,7 +96,7 @@ describe('ats analytics adapter', function () {
|
|
|
90
96
|
let expectedAfterBid = {
|
|
91
97
|
'Data': [{
|
|
92
98
|
'has_envelope': true,
|
|
93
|
-
'adapter_version':
|
|
99
|
+
'adapter_version': 3,
|
|
94
100
|
'bidder': 'appnexus',
|
|
95
101
|
'bid_id': '30c77d079cdf17',
|
|
96
102
|
'auction_id': 'a5b849e5-87d7-4205-8300-d063084fcfb7',
|
|
@@ -103,10 +109,30 @@ describe('ats analytics adapter', function () {
|
|
|
103
109
|
'response_time_stamp': '2020-02-03T14:23:11.978Z',
|
|
104
110
|
'currency': 'USD',
|
|
105
111
|
'cpm': 0.5,
|
|
106
|
-
'net_revenue': true
|
|
112
|
+
'net_revenue': true,
|
|
113
|
+
'bid_won': true
|
|
107
114
|
}]
|
|
108
115
|
};
|
|
109
116
|
|
|
117
|
+
let wonRequest = {
|
|
118
|
+
'adId': '2eddfdc0c791dc',
|
|
119
|
+
'mediaType': 'banner',
|
|
120
|
+
'requestId': '30c77d079cdf17',
|
|
121
|
+
'cpm': 0.5,
|
|
122
|
+
'creativeId': 29681110,
|
|
123
|
+
'currency': 'USD',
|
|
124
|
+
'netRevenue': true,
|
|
125
|
+
'ttl': 300,
|
|
126
|
+
'auctionId': 'a5b849e5-87d7-4205-8300-d063084fcfb7',
|
|
127
|
+
'statusMessage': 'Bid available',
|
|
128
|
+
'responseTimestamp': 1633525319061,
|
|
129
|
+
'requestTimestamp': 1633525319258,
|
|
130
|
+
'bidder': 'appnexus',
|
|
131
|
+
'adUnitCode': 'div-gpt-ad-1438287399331-0',
|
|
132
|
+
'size': '300x250',
|
|
133
|
+
'status': 'rendered'
|
|
134
|
+
};
|
|
135
|
+
|
|
110
136
|
// lets simulate that some bidders timeout
|
|
111
137
|
let bidTimeoutArgsV1 = [
|
|
112
138
|
{
|
|
@@ -148,6 +174,14 @@ describe('ats analytics adapter', function () {
|
|
|
148
174
|
|
|
149
175
|
// Step 5: Send auction end event
|
|
150
176
|
events.emit(constants.EVENTS.AUCTION_END, {});
|
|
177
|
+
// Step 6: Send bid won event
|
|
178
|
+
events.emit(constants.EVENTS.BID_WON, wonRequest);
|
|
179
|
+
|
|
180
|
+
sandbox.stub($$PREBID_GLOBAL$$, 'getAllWinningBids').callsFake((key) => {
|
|
181
|
+
return [wonRequest]
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
clock.tick(2000);
|
|
151
185
|
|
|
152
186
|
let requests = server.requests.filter(req => {
|
|
153
187
|
return req.url.indexOf(analyticsUrl) > -1;
|
|
@@ -156,13 +190,12 @@ describe('ats analytics adapter', function () {
|
|
|
156
190
|
expect(requests.length).to.equal(1);
|
|
157
191
|
|
|
158
192
|
let realAfterBid = JSON.parse(requests[0].requestBody);
|
|
159
|
-
|
|
193
|
+
|
|
194
|
+
// Step 7: assert real data after bid and expected data
|
|
160
195
|
expect(realAfterBid['Data']).to.deep.equal(expectedAfterBid['Data']);
|
|
161
196
|
|
|
162
197
|
// check that the publisher ID is configured via options
|
|
163
198
|
expect(atsAnalyticsAdapter.context.pid).to.equal(initOptions.pid);
|
|
164
|
-
|
|
165
|
-
atsAnalyticsAdapter.shouldFireRequest.restore();
|
|
166
199
|
})
|
|
167
200
|
it('check browser is safari', function () {
|
|
168
201
|
sinon.stub(atsAnalyticsAdapter, 'getUserAgent').returns('Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_5) AppleWebKit/536.25 (KHTML, like Gecko) Version/6.0 Safari/536.25');
|
|
@@ -204,7 +237,7 @@ describe('ats analytics adapter', function () {
|
|
|
204
237
|
sinon.stub(atsAnalyticsAdapter, 'getUserAgent').returns('Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_5) AppleWebKit/536.25 (KHTML, like Gecko) Version/6.0 Safari/536.25');
|
|
205
238
|
sinon.stub(Math, 'random').returns(0.99);
|
|
206
239
|
// publisher can try to pass anything they want but we will set sampling rate to 100, which means we will have 1% of requests
|
|
207
|
-
let result = atsAnalyticsAdapter.shouldFireRequest(
|
|
240
|
+
let result = atsAnalyticsAdapter.shouldFireRequest(8);
|
|
208
241
|
expect(result).to.equal(true);
|
|
209
242
|
})
|
|
210
243
|
it('should not fire analytics request if math random is something other then 0.99', function () {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as browsiRTD from '../../../modules/browsiRtdProvider.js';
|
|
2
2
|
import {makeSlot} from '../integration/faker/googletag.js';
|
|
3
|
+
import * as utils from '../../../src/utils'
|
|
3
4
|
|
|
4
5
|
describe('browsi Real time data sub module', function () {
|
|
5
6
|
const conf = {
|
|
@@ -29,11 +30,11 @@ describe('browsi Real time data sub module', function () {
|
|
|
29
30
|
});
|
|
30
31
|
|
|
31
32
|
it('should match placement with ad unit', function () {
|
|
32
|
-
const slot = makeSlot({code: '/
|
|
33
|
+
const slot = makeSlot({code: '/123/abc', divId: 'browsiAd_1'});
|
|
33
34
|
|
|
34
|
-
const test1 = browsiRTD.isIdMatchingAdUnit(slot, ['/
|
|
35
|
-
const test2 = browsiRTD.isIdMatchingAdUnit(slot, ['/
|
|
36
|
-
const test3 = browsiRTD.isIdMatchingAdUnit(slot, ['/
|
|
35
|
+
const test1 = browsiRTD.isIdMatchingAdUnit(slot, ['/123/abc']); // true
|
|
36
|
+
const test2 = browsiRTD.isIdMatchingAdUnit(slot, ['/123/abc', '/456/def']); // true
|
|
37
|
+
const test3 = browsiRTD.isIdMatchingAdUnit(slot, ['/123/def']); // false
|
|
37
38
|
const test4 = browsiRTD.isIdMatchingAdUnit(slot, []); // true
|
|
38
39
|
|
|
39
40
|
expect(test1).to.equal(true);
|
|
@@ -43,12 +44,12 @@ describe('browsi Real time data sub module', function () {
|
|
|
43
44
|
});
|
|
44
45
|
|
|
45
46
|
it('should return correct macro values', function () {
|
|
46
|
-
const slot = makeSlot({code: '/
|
|
47
|
+
const slot = makeSlot({code: '/123/abc', divId: 'browsiAd_1'});
|
|
47
48
|
|
|
48
49
|
slot.setTargeting('test', ['test', 'value']);
|
|
49
50
|
// slot getTargeting doesn't act like GPT so we can't expect real value
|
|
50
51
|
const macroResult = browsiRTD.getMacroId({p: '<AD_UNIT>/<KEY_test>'}, slot);
|
|
51
|
-
expect(macroResult).to.equal('/
|
|
52
|
+
expect(macroResult).to.equal('/123/abc/NA');
|
|
52
53
|
|
|
53
54
|
const macroResultB = browsiRTD.getMacroId({}, slot);
|
|
54
55
|
expect(macroResultB).to.equal('browsiAd_1');
|
|
@@ -72,7 +73,7 @@ describe('browsi Real time data sub module', function () {
|
|
|
72
73
|
it('should return prediction from server', function () {
|
|
73
74
|
makeSlot({code: 'hasPrediction', divId: 'hasPrediction'});
|
|
74
75
|
const data = {
|
|
75
|
-
p: {'hasPrediction': {
|
|
76
|
+
p: {'hasPrediction': {ps: {0: 0.234}}},
|
|
76
77
|
kn: 'bv',
|
|
77
78
|
pmd: undefined
|
|
78
79
|
};
|
|
@@ -80,4 +81,58 @@ describe('browsi Real time data sub module', function () {
|
|
|
80
81
|
expect(browsiRTD.browsiSubmodule.getTargetingData(['hasPrediction'])).to.eql({hasPrediction: {bv: '0.20'}});
|
|
81
82
|
})
|
|
82
83
|
})
|
|
84
|
+
|
|
85
|
+
describe('should return matching prediction', function () {
|
|
86
|
+
const predictions = {
|
|
87
|
+
0: 0.123,
|
|
88
|
+
1: 0.254,
|
|
89
|
+
3: 0,
|
|
90
|
+
4: 0.8
|
|
91
|
+
}
|
|
92
|
+
const singlePrediction = {
|
|
93
|
+
0: 0.123
|
|
94
|
+
}
|
|
95
|
+
it('should return raw value if valid', function () {
|
|
96
|
+
expect(browsiRTD.getCurrentData(predictions, 0)).to.equal(0.123);
|
|
97
|
+
expect(browsiRTD.getCurrentData(predictions, 1)).to.equal(0.254);
|
|
98
|
+
})
|
|
99
|
+
it('should return 0 for prediction = 0', function () {
|
|
100
|
+
expect(browsiRTD.getCurrentData(predictions, 3)).to.equal(0);
|
|
101
|
+
})
|
|
102
|
+
it('should return -1 for invalid params', function () {
|
|
103
|
+
expect(browsiRTD.getCurrentData(null, 3)).to.equal(-1);
|
|
104
|
+
expect(browsiRTD.getCurrentData(predictions, null)).to.equal(-1);
|
|
105
|
+
})
|
|
106
|
+
it('should return prediction according to object keys length ', function () {
|
|
107
|
+
expect(browsiRTD.getCurrentData(singlePrediction, 0)).to.equal(0.123);
|
|
108
|
+
expect(browsiRTD.getCurrentData(singlePrediction, 1)).to.equal(-1);
|
|
109
|
+
expect(browsiRTD.getCurrentData(singlePrediction, 2)).to.equal(-1);
|
|
110
|
+
expect(browsiRTD.getCurrentData(predictions, 4)).to.equal(0.8);
|
|
111
|
+
expect(browsiRTD.getCurrentData(predictions, 5)).to.equal(0.8);
|
|
112
|
+
expect(browsiRTD.getCurrentData(predictions, 8)).to.equal(0.8);
|
|
113
|
+
})
|
|
114
|
+
})
|
|
115
|
+
describe('should set bid request data', function () {
|
|
116
|
+
const data = {
|
|
117
|
+
p: {
|
|
118
|
+
'adUnit1': {ps: {0: 0.234}},
|
|
119
|
+
'adUnit2': {ps: {0: 0.134}}},
|
|
120
|
+
kn: 'bv',
|
|
121
|
+
pmd: undefined
|
|
122
|
+
};
|
|
123
|
+
browsiRTD.setData(data);
|
|
124
|
+
const fakeAdUnits = [
|
|
125
|
+
{
|
|
126
|
+
code: 'adUnit1'
|
|
127
|
+
},
|
|
128
|
+
{
|
|
129
|
+
code: 'adUnit2'
|
|
130
|
+
}
|
|
131
|
+
]
|
|
132
|
+
browsiRTD.browsiSubmodule.getBidRequestData({adUnits: fakeAdUnits}, () => {}, {}, null);
|
|
133
|
+
it('should set ad unit params with prediction values', function () {
|
|
134
|
+
expect(utils.deepAccess(fakeAdUnits[0], 'ortb2Imp.ext.data.browsi')).to.eql({bv: '0.20'});
|
|
135
|
+
expect(utils.deepAccess(fakeAdUnits[1], 'ortb2Imp.ext.data.browsi')).to.eql({bv: '0.10'});
|
|
136
|
+
})
|
|
137
|
+
})
|
|
83
138
|
});
|
|
@@ -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
|
+
});
|