prebid.js 6.4.0 → 6.8.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/integrationExamples/gpt/amp/creative.html +11 -33
- package/integrationExamples/gpt/x-domain/creative.html +53 -26
- package/modules/.submodules.json +2 -1
- package/modules/adagioBidAdapter.js +0 -8
- package/modules/adagioBidAdapter.md +1 -1
- package/modules/adbookpspBidAdapter.js +27 -10
- package/modules/adhashBidAdapter.js +3 -3
- package/modules/adkernelBidAdapter.js +2 -1
- package/modules/admanBidAdapter.js +10 -4
- package/modules/adomikAnalyticsAdapter.js +23 -11
- package/modules/adqueryIdSystem.js +103 -0
- package/modules/adqueryIdSystem.md +35 -0
- package/modules/adyoulikeBidAdapter.js +13 -9
- package/modules/appnexusBidAdapter.js +11 -0
- package/modules/bliinkBidAdapter.js +3 -2
- package/modules/brandmetricsRtdProvider.js +168 -0
- package/modules/brandmetricsRtdProvider.md +40 -0
- package/modules/colossussspBidAdapter.js +12 -8
- package/modules/colossussspBidAdapter.md +15 -1
- package/modules/compassBidAdapter.js +10 -3
- package/modules/consentManagement.js +7 -1
- package/modules/consumableBidAdapter.md +1 -1
- package/modules/criteoBidAdapter.js +10 -1
- package/modules/criteoIdSystem.js +29 -7
- package/modules/currency.js +26 -1
- package/modules/displayioBidAdapter.js +157 -0
- package/modules/displayioBidAdapter.md +148 -0
- package/modules/docereeBidAdapter.js +10 -1
- package/modules/docereeBidAdapter.md +2 -0
- package/modules/e_volutionBidAdapter.js +158 -0
- package/modules/glimpseBidAdapter.js +66 -44
- package/modules/gnetBidAdapter.js +3 -3
- package/modules/gnetBidAdapter.md +4 -4
- package/modules/gptPreAuction.js +55 -7
- package/modules/gumgumBidAdapter.js +56 -42
- package/modules/idImportLibrary.js +45 -8
- package/modules/idImportLibrary.md +4 -0
- package/modules/improvedigitalBidAdapter.js +24 -2
- package/modules/interactiveOffersBidAdapter.js +9 -6
- package/modules/ixBidAdapter.js +29 -12
- package/modules/jwplayerRtdProvider.js +71 -6
- package/modules/jwplayerRtdProvider.md +27 -11
- package/modules/kargoBidAdapter.js +2 -2
- package/modules/limelightDigitalBidAdapter.js +2 -1
- package/modules/livewrappedAnalyticsAdapter.js +3 -1
- package/modules/loglyliftBidAdapter.js +79 -0
- package/modules/loglyliftBidAdapter.md +55 -0
- package/modules/nextMillenniumBidAdapter.js +3 -1
- package/modules/oguryBidAdapter.js +9 -2
- package/modules/onetagBidAdapter.js +4 -2
- package/modules/optimeraRtdProvider.js +8 -1
- package/modules/ozoneBidAdapter.js +21 -64
- package/modules/pilotxBidAdapter.js +147 -0
- package/modules/pilotxBidAdapter.md +50 -0
- package/modules/proxistoreBidAdapter.js +0 -2
- package/modules/pubmaticAnalyticsAdapter.js +16 -0
- package/modules/richaudienceBidAdapter.js +3 -2
- package/modules/riseBidAdapter.js +1 -1
- package/modules/rtbhouseBidAdapter.js +14 -4
- package/modules/rtdModule/index.js +14 -15
- package/modules/rubiconAnalyticsAdapter.js +3 -2
- package/modules/seedingAllianceBidAdapter.js +3 -3
- package/modules/sharethroughBidAdapter.js +12 -17
- package/modules/showheroes-bsBidAdapter.js +13 -2
- package/modules/sovrnBidAdapter.js +93 -18
- package/modules/sovrnBidAdapter.md +80 -2
- package/modules/synacormediaBidAdapter.js +31 -10
- package/modules/tappxBidAdapter.js +8 -5
- package/modules/teadsBidAdapter.js +1 -2
- package/modules/undertoneBidAdapter.js +17 -1
- package/modules/userId/eids.js +7 -1
- package/modules/userId/userId.md +8 -0
- package/modules/viewability.js +177 -0
- package/modules/viewability.md +87 -0
- package/modules/welectBidAdapter.js +106 -0
- package/modules/yahoosspBidAdapter.js +2 -0
- package/modules/yieldmoBidAdapter.js +23 -5
- package/modules/zeta_global_sspAnalyticsAdapter.js +97 -0
- package/modules/zeta_global_sspAnalyticsAdapter.md +24 -0
- package/package.json +1 -1
- package/src/adRendering.js +38 -0
- package/src/auction.js +44 -9
- package/src/config.js +27 -3
- package/src/hook.js +5 -1
- package/src/prebid.js +21 -21
- package/src/secureCreatives.js +114 -44
- package/src/utils.js +25 -4
- package/test/helpers/syncPromise.js +71 -0
- package/test/spec/auctionmanager_spec.js +148 -16
- package/test/spec/config_spec.js +279 -0
- package/test/spec/modules/adagioBidAdapter_spec.js +0 -10
- package/test/spec/modules/adbookpspBidAdapter_spec.js +17 -3
- package/test/spec/modules/adhashBidAdapter_spec.js +2 -2
- package/test/spec/modules/admanBidAdapter_spec.js +2 -2
- package/test/spec/modules/adomikAnalyticsAdapter_spec.js +3 -1
- package/test/spec/modules/adqueryIdSystem_spec.js +74 -0
- package/test/spec/modules/adyoulikeBidAdapter_spec.js +49 -0
- package/test/spec/modules/appnexusBidAdapter_spec.js +27 -0
- package/test/spec/modules/bliinkBidAdapter_spec.js +2 -0
- package/test/spec/modules/brandmetricsRtdProvider_spec.js +191 -0
- package/test/spec/modules/colossussspBidAdapter_spec.js +5 -2
- package/test/spec/modules/compassBidAdapter_spec.js +1 -0
- package/test/spec/modules/consentManagement_spec.js +20 -0
- package/test/spec/modules/criteoBidAdapter_spec.js +21 -0
- package/test/spec/modules/criteoIdSystem_spec.js +6 -3
- package/test/spec/modules/currency_spec.js +21 -6
- package/test/spec/modules/displayioBidAdapter_spec.js +239 -0
- package/test/spec/modules/docereeBidAdapter_spec.js +9 -1
- package/test/spec/modules/e_volutionBidAdapter_spec.js +242 -0
- package/test/spec/modules/eids_spec.js +15 -0
- package/test/spec/modules/glimpseBidAdapter_spec.js +0 -18
- package/test/spec/modules/gnetBidAdapter_spec.js +6 -6
- package/test/spec/modules/gptPreAuction_spec.js +177 -2
- package/test/spec/modules/gumgumBidAdapter_spec.js +46 -0
- package/test/spec/modules/idImportLibrary_spec.js +197 -10
- package/test/spec/modules/improvedigitalBidAdapter_spec.js +42 -0
- package/test/spec/modules/ixBidAdapter_spec.js +104 -62
- package/test/spec/modules/jwplayerRtdProvider_spec.js +195 -2
- package/test/spec/modules/kargoBidAdapter_spec.js +1 -1
- package/test/spec/modules/limelightDigitalBidAdapter_spec.js +75 -17
- package/test/spec/modules/livewrappedAnalyticsAdapter_spec.js +22 -0
- package/test/spec/modules/loglyliftBidAdapter_spec.js +172 -0
- package/test/spec/modules/nextMillenniumBidAdapter_spec.js +1 -1
- package/test/spec/modules/oguryBidAdapter_spec.js +10 -2
- package/test/spec/modules/optimeraRtdProvider_spec.js +14 -1
- package/test/spec/modules/ozoneBidAdapter_spec.js +43 -31
- package/test/spec/modules/pilotxBidAdapter_spec.js +244 -0
- package/test/spec/modules/pubmaticAnalyticsAdapter_spec.js +13 -1
- package/test/spec/modules/realTimeDataModule_spec.js +67 -5
- package/test/spec/modules/richaudienceBidAdapter_spec.js +40 -0
- package/test/spec/modules/riseBidAdapter_spec.js +1 -1
- package/test/spec/modules/rtbhouseBidAdapter_spec.js +20 -0
- package/test/spec/modules/rubiconAnalyticsAdapter_spec.js +30 -0
- package/test/spec/modules/sharethroughBidAdapter_spec.js +91 -6
- package/test/spec/modules/showheroes-bsBidAdapter_spec.js +2 -0
- package/test/spec/modules/sovrnBidAdapter_spec.js +413 -333
- package/test/spec/modules/synacormediaBidAdapter_spec.js +70 -0
- package/test/spec/modules/tappxBidAdapter_spec.js +0 -19
- package/test/spec/modules/teadsBidAdapter_spec.js +14 -59
- package/test/spec/modules/undertoneBidAdapter_spec.js +55 -2
- package/test/spec/modules/userId_spec.js +68 -19
- package/test/spec/modules/viewability_spec.js +280 -0
- package/test/spec/modules/welectBidAdapter_spec.js +211 -0
- package/test/spec/modules/yahoosspBidAdapter_spec.js +10 -0
- package/test/spec/modules/zeta_global_sspAnalyticsAdapter_spec.js +427 -0
- package/test/spec/unit/pbjs_api_spec.js +20 -2
- package/test/spec/unit/secureCreatives_spec.js +85 -0
package/src/prebid.js
CHANGED
|
@@ -19,6 +19,7 @@ import { adunitCounter } from './adUnits.js';
|
|
|
19
19
|
import { executeRenderer, isRendererRequired } from './Renderer.js';
|
|
20
20
|
import { createBid } from './bidfactory.js';
|
|
21
21
|
import { storageCallbacks } from './storageManager.js';
|
|
22
|
+
import { emitAdRenderSucceeded, emitAdRenderFail } from './adRendering.js';
|
|
22
23
|
|
|
23
24
|
const $$PREBID_GLOBAL$$ = getGlobal();
|
|
24
25
|
const CONSTANTS = require('./constants.json');
|
|
@@ -27,7 +28,7 @@ const events = require('./events.js');
|
|
|
27
28
|
const { triggerUserSyncs } = userSync;
|
|
28
29
|
|
|
29
30
|
/* private variables */
|
|
30
|
-
const { ADD_AD_UNITS, BID_WON, REQUEST_BIDS, SET_TARGETING,
|
|
31
|
+
const { ADD_AD_UNITS, BID_WON, REQUEST_BIDS, SET_TARGETING, STALE_RENDER } = CONSTANTS.EVENTS;
|
|
31
32
|
const { PREVENT_WRITING_ON_MAIN_DOCUMENT, NO_AD, EXCEPTION, CANNOT_FIND_AD, MISSING_DOC_OR_ADID } = CONSTANTS.AD_RENDER_FAILED_REASON;
|
|
32
33
|
|
|
33
34
|
const eventValidators = {
|
|
@@ -146,7 +147,7 @@ function validateNativeMediaType(adUnit) {
|
|
|
146
147
|
function validateAdUnitPos(adUnit, mediaType) {
|
|
147
148
|
let pos = deepAccess(adUnit, `mediaTypes.${mediaType}.pos`);
|
|
148
149
|
|
|
149
|
-
if (!pos ||
|
|
150
|
+
if (!isNumber(pos) || isNaN(pos) || !isFinite(pos)) {
|
|
150
151
|
let warning = `Value of property 'pos' on ad unit ${adUnit.code} should be of type: Number`;
|
|
151
152
|
|
|
152
153
|
logWarn(warning);
|
|
@@ -385,27 +386,23 @@ $$PREBID_GLOBAL$$.setTargetingForAst = function (adUnitCodes) {
|
|
|
385
386
|
events.emit(SET_TARGETING, targeting.getAllTargeting());
|
|
386
387
|
};
|
|
387
388
|
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
if (bid) data.bid = bid;
|
|
400
|
-
if (id) data.adId = id;
|
|
401
|
-
|
|
402
|
-
events.emit(AD_RENDER_SUCCEEDED, data);
|
|
389
|
+
/**
|
|
390
|
+
* This function will check for presence of given node in given parent. If not present - will inject it.
|
|
391
|
+
* @param {Node} node node, whose existance is in question
|
|
392
|
+
* @param {Document} doc document element do look in
|
|
393
|
+
* @param {string} tagName tag name to look in
|
|
394
|
+
*/
|
|
395
|
+
function reinjectNodeIfRemoved(node, doc, tagName) {
|
|
396
|
+
const injectionNode = doc.querySelector(tagName);
|
|
397
|
+
if (!node.parentNode || node.parentNode !== injectionNode) {
|
|
398
|
+
insertElement(node, doc, tagName);
|
|
399
|
+
}
|
|
403
400
|
}
|
|
404
401
|
|
|
405
402
|
/**
|
|
406
403
|
* This function will render the ad (based on params) in the given iframe document passed through.
|
|
407
404
|
* Note that doc SHOULD NOT be the parent document page as we can't doc.write() asynchronously
|
|
408
|
-
* @param {
|
|
405
|
+
* @param {Document} doc document
|
|
409
406
|
* @param {string} id bid id to locate the ad
|
|
410
407
|
* @alias module:pbjs.renderAd
|
|
411
408
|
*/
|
|
@@ -449,10 +446,11 @@ $$PREBID_GLOBAL$$.renderAd = hook('async', function (doc, id, options) {
|
|
|
449
446
|
const {height, width, ad, mediaType, adUrl, renderer} = bid;
|
|
450
447
|
|
|
451
448
|
const creativeComment = document.createComment(`Creative ${bid.creativeId} served by ${bid.bidder} Prebid.js Header Bidding`);
|
|
449
|
+
insertElement(creativeComment, doc, 'html');
|
|
452
450
|
|
|
453
451
|
if (isRendererRequired(renderer)) {
|
|
454
452
|
executeRenderer(renderer, bid);
|
|
455
|
-
|
|
453
|
+
reinjectNodeIfRemoved(creativeComment, doc, 'html');
|
|
456
454
|
emitAdRenderSucceeded({ doc, bid, id });
|
|
457
455
|
} else if ((doc === document && !inIframe()) || mediaType === 'video') {
|
|
458
456
|
const message = `Error trying to write ad. Ad render call ad id ${id} was prevented from writing to the main document.`;
|
|
@@ -471,7 +469,7 @@ $$PREBID_GLOBAL$$.renderAd = hook('async', function (doc, id, options) {
|
|
|
471
469
|
doc.write(ad);
|
|
472
470
|
doc.close();
|
|
473
471
|
setRenderSize(doc, width, height);
|
|
474
|
-
|
|
472
|
+
reinjectNodeIfRemoved(creativeComment, doc, 'html');
|
|
475
473
|
callBurl(bid);
|
|
476
474
|
emitAdRenderSucceeded({ doc, bid, id });
|
|
477
475
|
} else if (adUrl) {
|
|
@@ -484,7 +482,7 @@ $$PREBID_GLOBAL$$.renderAd = hook('async', function (doc, id, options) {
|
|
|
484
482
|
|
|
485
483
|
insertElement(iframe, doc, 'body');
|
|
486
484
|
setRenderSize(doc, width, height);
|
|
487
|
-
|
|
485
|
+
reinjectNodeIfRemoved(creativeComment, doc, 'html');
|
|
488
486
|
callBurl(bid);
|
|
489
487
|
emitAdRenderSucceeded({ doc, bid, id });
|
|
490
488
|
} else {
|
|
@@ -901,6 +899,8 @@ $$PREBID_GLOBAL$$.markWinningBidAsUsed = function (markBidRequest) {
|
|
|
901
899
|
*/
|
|
902
900
|
$$PREBID_GLOBAL$$.getConfig = config.getConfig;
|
|
903
901
|
$$PREBID_GLOBAL$$.readConfig = config.readConfig;
|
|
902
|
+
$$PREBID_GLOBAL$$.mergeConfig = config.mergeConfig;
|
|
903
|
+
$$PREBID_GLOBAL$$.mergeBidderConfig = config.mergeBidderConfig;
|
|
904
904
|
|
|
905
905
|
/**
|
|
906
906
|
* Set Prebid config options.
|
package/src/secureCreatives.js
CHANGED
|
@@ -4,18 +4,25 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import events from './events.js';
|
|
7
|
-
import {
|
|
7
|
+
import {fireNativeTrackers, getAllAssetsMessage, getAssetMessage} from './native.js';
|
|
8
8
|
import constants from './constants.json';
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
9
|
+
import {deepAccess, isApnGetTagDefined, isGptPubadsDefined, logError, logWarn, replaceAuctionPrice} from './utils.js';
|
|
10
|
+
import {auctionManager} from './auctionManager.js';
|
|
11
11
|
import find from 'core-js-pure/features/array/find.js';
|
|
12
|
-
import { isRendererRequired
|
|
12
|
+
import {executeRenderer, isRendererRequired} from './Renderer.js';
|
|
13
13
|
import includes from 'core-js-pure/features/array/includes.js';
|
|
14
|
-
import {
|
|
14
|
+
import {config} from './config.js';
|
|
15
|
+
import {emitAdRenderFail, emitAdRenderSucceeded} from './adRendering.js';
|
|
15
16
|
|
|
16
17
|
const BID_WON = constants.EVENTS.BID_WON;
|
|
17
18
|
const STALE_RENDER = constants.EVENTS.STALE_RENDER;
|
|
18
19
|
|
|
20
|
+
const HANDLER_MAP = {
|
|
21
|
+
'Prebid Request': handleRenderRequest,
|
|
22
|
+
'Prebid Native': handleNativeRequest,
|
|
23
|
+
'Prebid Event': handleEventRequest,
|
|
24
|
+
}
|
|
25
|
+
|
|
19
26
|
export function listenMessagesFromCreative() {
|
|
20
27
|
window.addEventListener('message', receiveMessage, false);
|
|
21
28
|
}
|
|
@@ -29,52 +36,114 @@ export function receiveMessage(ev) {
|
|
|
29
36
|
return;
|
|
30
37
|
}
|
|
31
38
|
|
|
32
|
-
if (data && data.adId) {
|
|
39
|
+
if (data && data.adId && data.message) {
|
|
33
40
|
const adObject = find(auctionManager.getBidsReceived(), function (bid) {
|
|
34
41
|
return bid.adId === data.adId;
|
|
35
42
|
});
|
|
43
|
+
if (HANDLER_MAP.hasOwnProperty(data.message)) {
|
|
44
|
+
HANDLER_MAP[data.message](ev, data, adObject);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
36
48
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
49
|
+
function handleRenderRequest(ev, data, adObject) {
|
|
50
|
+
if (adObject == null) {
|
|
51
|
+
emitAdRenderFail({
|
|
52
|
+
reason: constants.AD_RENDER_FAILED_REASON.CANNOT_FIND_AD,
|
|
53
|
+
message: `Cannot find ad '${data.adId}' for cross-origin render request`,
|
|
54
|
+
id: data.adId
|
|
55
|
+
});
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
if (adObject.status === constants.BID_STATUS.RENDERED) {
|
|
59
|
+
logWarn(`Ad id ${adObject.adId} has been rendered before`);
|
|
60
|
+
events.emit(STALE_RENDER, adObject);
|
|
61
|
+
if (deepAccess(config.getConfig('auctionOptions'), 'suppressStaleRender')) {
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
45
65
|
|
|
46
|
-
|
|
66
|
+
try {
|
|
67
|
+
_sendAdToCreative(adObject, ev);
|
|
68
|
+
} catch (e) {
|
|
69
|
+
emitAdRenderFail({
|
|
70
|
+
reason: constants.AD_RENDER_FAILED_REASON.EXCEPTION,
|
|
71
|
+
message: e.message,
|
|
72
|
+
id: data.adId,
|
|
73
|
+
bid: adObject
|
|
74
|
+
});
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
47
77
|
|
|
48
|
-
|
|
49
|
-
|
|
78
|
+
// save winning bids
|
|
79
|
+
auctionManager.addWinningBid(adObject);
|
|
50
80
|
|
|
51
|
-
|
|
52
|
-
|
|
81
|
+
events.emit(BID_WON, adObject);
|
|
82
|
+
}
|
|
53
83
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
84
|
+
function handleNativeRequest(ev, data, adObject) {
|
|
85
|
+
// handle this script from native template in an ad server
|
|
86
|
+
// window.parent.postMessage(JSON.stringify({
|
|
87
|
+
// message: 'Prebid Native',
|
|
88
|
+
// adId: '%%PATTERN:hb_adid%%'
|
|
89
|
+
// }), '*');
|
|
90
|
+
if (adObject == null) {
|
|
91
|
+
logError(`Cannot find ad '${data.adId}' for x-origin event request`);
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
switch (data.action) {
|
|
95
|
+
case 'assetRequest':
|
|
96
|
+
reply(getAssetMessage(data, adObject));
|
|
97
|
+
break;
|
|
98
|
+
case 'allAssetRequest':
|
|
99
|
+
reply(getAllAssetsMessage(data, adObject));
|
|
100
|
+
break;
|
|
101
|
+
case 'resizeNativeHeight':
|
|
102
|
+
adObject.height = data.height;
|
|
103
|
+
adObject.width = data.width;
|
|
104
|
+
resizeRemoteCreative(adObject);
|
|
105
|
+
break;
|
|
106
|
+
default:
|
|
107
|
+
const trackerType = fireNativeTrackers(data, adObject);
|
|
108
|
+
if (trackerType === 'click') {
|
|
109
|
+
return;
|
|
76
110
|
}
|
|
77
|
-
|
|
111
|
+
auctionManager.addWinningBid(adObject);
|
|
112
|
+
events.emit(BID_WON, adObject);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function reply(message) {
|
|
116
|
+
ev.source.postMessage(JSON.stringify(message), ev.origin);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function handleEventRequest(ev, data, adObject) {
|
|
121
|
+
if (adObject == null) {
|
|
122
|
+
logError(`Cannot find ad '${data.adId}' for x-origin event request`);
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
if (adObject.status !== constants.BID_STATUS.RENDERED) {
|
|
126
|
+
logWarn(`Received x-origin event request without corresponding render request for ad '${data.adId}'`);
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
switch (data.event) {
|
|
130
|
+
case constants.EVENTS.AD_RENDER_FAILED:
|
|
131
|
+
emitAdRenderFail({
|
|
132
|
+
bid: adObject,
|
|
133
|
+
id: data.adId,
|
|
134
|
+
reason: data.info.reason,
|
|
135
|
+
message: data.info.message
|
|
136
|
+
});
|
|
137
|
+
break;
|
|
138
|
+
case constants.EVENTS.AD_RENDER_SUCCEEDED:
|
|
139
|
+
emitAdRenderSucceeded({
|
|
140
|
+
doc: null,
|
|
141
|
+
bid: adObject,
|
|
142
|
+
id: data.adId
|
|
143
|
+
});
|
|
144
|
+
break;
|
|
145
|
+
default:
|
|
146
|
+
logError(`Received x-origin event request for unsupported event: '${data.event}' (adId: '${data.adId}')`)
|
|
78
147
|
}
|
|
79
148
|
}
|
|
80
149
|
|
|
@@ -127,11 +196,12 @@ function resizeRemoteCreative({ adId, adUnitCode, width, height }) {
|
|
|
127
196
|
}
|
|
128
197
|
|
|
129
198
|
function getDfpElementId(adId) {
|
|
130
|
-
|
|
199
|
+
const slot = find(window.googletag.pubads().getSlots(), slot => {
|
|
131
200
|
return find(slot.getTargetingKeys(), key => {
|
|
132
201
|
return includes(slot.getTargeting(key), adId);
|
|
133
202
|
});
|
|
134
|
-
})
|
|
203
|
+
});
|
|
204
|
+
return slot ? slot.getSlotElementId() : null;
|
|
135
205
|
}
|
|
136
206
|
|
|
137
207
|
function getAstElementId(adUnitCode) {
|
package/src/utils.js
CHANGED
|
@@ -22,7 +22,17 @@ let consoleLogExists = Boolean(consoleExists && window.console.log);
|
|
|
22
22
|
let consoleInfoExists = Boolean(consoleExists && window.console.info);
|
|
23
23
|
let consoleWarnExists = Boolean(consoleExists && window.console.warn);
|
|
24
24
|
let consoleErrorExists = Boolean(consoleExists && window.console.error);
|
|
25
|
-
|
|
25
|
+
|
|
26
|
+
const emitEvent = (function () {
|
|
27
|
+
// lazy load events to avoid circular import
|
|
28
|
+
let ev;
|
|
29
|
+
return function() {
|
|
30
|
+
if (ev == null) {
|
|
31
|
+
ev = require('./events.js');
|
|
32
|
+
}
|
|
33
|
+
return ev.emit.apply(ev, arguments);
|
|
34
|
+
}
|
|
35
|
+
})();
|
|
26
36
|
|
|
27
37
|
// this allows stubbing of utility functions that are used internally by other utility functions
|
|
28
38
|
export const internal = {
|
|
@@ -265,14 +275,14 @@ export function logWarn() {
|
|
|
265
275
|
if (debugTurnedOn() && consoleWarnExists) {
|
|
266
276
|
console.warn.apply(console, decorateLog(arguments, 'WARNING:'));
|
|
267
277
|
}
|
|
268
|
-
|
|
278
|
+
emitEvent(CONSTANTS.EVENTS.AUCTION_DEBUG, {type: 'WARNING', arguments: arguments});
|
|
269
279
|
}
|
|
270
280
|
|
|
271
281
|
export function logError() {
|
|
272
282
|
if (debugTurnedOn() && consoleErrorExists) {
|
|
273
283
|
console.error.apply(console, decorateLog(arguments, 'ERROR:'));
|
|
274
284
|
}
|
|
275
|
-
|
|
285
|
+
emitEvent(CONSTANTS.EVENTS.AUCTION_DEBUG, {type: 'ERROR', arguments: arguments});
|
|
276
286
|
}
|
|
277
287
|
|
|
278
288
|
function decorateLog(args, prefix) {
|
|
@@ -1272,7 +1282,18 @@ export function mergeDeep(target, ...sources) {
|
|
|
1272
1282
|
if (!target[key]) {
|
|
1273
1283
|
Object.assign(target, { [key]: source[key] });
|
|
1274
1284
|
} else if (isArray(target[key])) {
|
|
1275
|
-
|
|
1285
|
+
source[key].forEach(obj => {
|
|
1286
|
+
let addItFlag = 1;
|
|
1287
|
+
for (let i = 0; i < target[key].length; i++) {
|
|
1288
|
+
if (deepEqual(target[key][i], obj)) {
|
|
1289
|
+
addItFlag = 0;
|
|
1290
|
+
break;
|
|
1291
|
+
}
|
|
1292
|
+
}
|
|
1293
|
+
if (addItFlag) {
|
|
1294
|
+
target[key].push(obj);
|
|
1295
|
+
}
|
|
1296
|
+
});
|
|
1276
1297
|
}
|
|
1277
1298
|
} else {
|
|
1278
1299
|
Object.assign(target, { [key]: source[key] });
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
const orig = {};
|
|
2
|
+
['resolve', 'reject', 'all', 'race', 'allSettled'].forEach((k) => orig[k] = Promise[k].bind(Promise))
|
|
3
|
+
|
|
4
|
+
// Callbacks attached through Promise.resolve(value).then(...) will usually
|
|
5
|
+
// not execute immediately even if `value` is immediately available. This
|
|
6
|
+
// breaks tests that were written before promises even though they are semantically still valid.
|
|
7
|
+
// They can be made to work by making promises quasi-synchronous.
|
|
8
|
+
|
|
9
|
+
export function SyncPromise(value, fail = false) {
|
|
10
|
+
if (value instanceof SyncPromise) {
|
|
11
|
+
return value;
|
|
12
|
+
} else if (typeof value === 'object' && typeof value.then === 'function') {
|
|
13
|
+
return orig.resolve(value);
|
|
14
|
+
} else {
|
|
15
|
+
Object.assign(this, {
|
|
16
|
+
then: function (cb, err) {
|
|
17
|
+
const handler = fail ? err : cb;
|
|
18
|
+
if (handler != null) {
|
|
19
|
+
return new SyncPromise(handler(value));
|
|
20
|
+
} else {
|
|
21
|
+
return this;
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
catch: function (cb) {
|
|
25
|
+
if (fail) {
|
|
26
|
+
return new SyncPromise(cb(value))
|
|
27
|
+
} else {
|
|
28
|
+
return this;
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
finally: function (cb) {
|
|
32
|
+
cb();
|
|
33
|
+
return this;
|
|
34
|
+
},
|
|
35
|
+
__value: fail ? {status: 'rejected', reason: value} : {status: 'fulfilled', value}
|
|
36
|
+
})
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
Object.assign(SyncPromise, {
|
|
41
|
+
resolve: (val) => new SyncPromise(val),
|
|
42
|
+
reject: (val) => new SyncPromise(val, true),
|
|
43
|
+
race: (promises) => promises.find((p) => p instanceof SyncPromise) || orig.race(promises),
|
|
44
|
+
allSettled: (promises) => {
|
|
45
|
+
if (promises.every((p) => p instanceof SyncPromise)) {
|
|
46
|
+
return new SyncPromise(promises.map((p) => p.__value))
|
|
47
|
+
} else {
|
|
48
|
+
return orig.allSettled(promises);
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
all: (promises) => {
|
|
52
|
+
if (promises.every((p) => p instanceof SyncPromise)) {
|
|
53
|
+
return SyncPromise.allSettled(promises).then((result) => {
|
|
54
|
+
const err = result.find((r) => r.status === 'rejected');
|
|
55
|
+
if (err != null) {
|
|
56
|
+
return new SyncPromise(err.reason, true);
|
|
57
|
+
} else {
|
|
58
|
+
return new SyncPromise(result.map((r) => r.value))
|
|
59
|
+
}
|
|
60
|
+
})
|
|
61
|
+
} else {
|
|
62
|
+
return orig.all(promises);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
})
|
|
66
|
+
|
|
67
|
+
export function synchronizePromise(sandbox) {
|
|
68
|
+
Object.keys(orig).forEach((k) => {
|
|
69
|
+
sandbox.stub(window.Promise, k).callsFake(SyncPromise[k]);
|
|
70
|
+
})
|
|
71
|
+
}
|
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
auctionCallbacks,
|
|
4
4
|
AUCTION_COMPLETED,
|
|
5
5
|
adjustBids,
|
|
6
|
-
getMediaTypeGranularity,
|
|
6
|
+
getMediaTypeGranularity, addBidResponse,
|
|
7
7
|
} from 'src/auction.js';
|
|
8
8
|
import CONSTANTS from 'src/constants.json';
|
|
9
9
|
import * as auctionModule from 'src/auction.js';
|
|
@@ -14,6 +14,10 @@ import * as store from 'src/videoCache.js';
|
|
|
14
14
|
import * as ajaxLib from 'src/ajax.js';
|
|
15
15
|
import find from 'core-js-pure/features/array/find.js';
|
|
16
16
|
import { server } from 'test/mocks/xhr.js';
|
|
17
|
+
import {expect} from 'chai';
|
|
18
|
+
import {hook} from '../../src/hook.js';
|
|
19
|
+
import 'src/debugging.js'
|
|
20
|
+
import {synchronizePromise} from '../helpers/syncPromise.js'; // some of these tests require debugging hooks to be loaded
|
|
17
21
|
|
|
18
22
|
var assert = require('assert');
|
|
19
23
|
|
|
@@ -124,6 +128,27 @@ function mockAjaxBuilder() {
|
|
|
124
128
|
}
|
|
125
129
|
|
|
126
130
|
describe('auctionmanager.js', function () {
|
|
131
|
+
let promiseSandbox;
|
|
132
|
+
|
|
133
|
+
before(() => {
|
|
134
|
+
// hooks are global and their side effects depend on what has been loaded... not ideal for unit tests
|
|
135
|
+
[
|
|
136
|
+
auctionModule.addBidResponse,
|
|
137
|
+
auctionModule.addBidderRequests,
|
|
138
|
+
auctionModule.bidsBackCallback
|
|
139
|
+
].forEach((h) => h.getHooks().remove())
|
|
140
|
+
hook.ready();
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
beforeEach(() => {
|
|
144
|
+
promiseSandbox = sinon.createSandbox();
|
|
145
|
+
synchronizePromise(promiseSandbox);
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
afterEach(() => {
|
|
149
|
+
promiseSandbox.restore();
|
|
150
|
+
})
|
|
151
|
+
|
|
127
152
|
describe('getKeyValueTargetingPairs', function () {
|
|
128
153
|
const DEFAULT_BID = {
|
|
129
154
|
cpm: 5.578,
|
|
@@ -1259,12 +1284,7 @@ describe('auctionmanager.js', function () {
|
|
|
1259
1284
|
let bids = TEST_BIDS;
|
|
1260
1285
|
let bidRequests;
|
|
1261
1286
|
let doneSpy;
|
|
1262
|
-
let auction
|
|
1263
|
-
getBidRequests: () => bidRequests,
|
|
1264
|
-
getAuctionId: () => '1',
|
|
1265
|
-
addBidReceived: () => true,
|
|
1266
|
-
getTimeout: () => 1000
|
|
1267
|
-
}
|
|
1287
|
+
let auction;
|
|
1268
1288
|
|
|
1269
1289
|
beforeEach(() => {
|
|
1270
1290
|
doneSpy = sinon.spy();
|
|
@@ -1272,12 +1292,21 @@ describe('auctionmanager.js', function () {
|
|
|
1272
1292
|
cache: {
|
|
1273
1293
|
url: 'https://prebid.adnxs.com/pbc/v1/cache'
|
|
1274
1294
|
}
|
|
1275
|
-
})
|
|
1295
|
+
});
|
|
1296
|
+
const start = Date.now();
|
|
1297
|
+
auction = {
|
|
1298
|
+
getBidRequests: () => bidRequests,
|
|
1299
|
+
getAuctionId: () => '1',
|
|
1300
|
+
addBidReceived: () => true,
|
|
1301
|
+
getTimeout: () => 1000,
|
|
1302
|
+
getAuctionStart: () => start,
|
|
1303
|
+
}
|
|
1276
1304
|
});
|
|
1277
1305
|
|
|
1278
1306
|
afterEach(() => {
|
|
1279
1307
|
doneSpy.resetHistory();
|
|
1280
1308
|
config.resetConfig();
|
|
1309
|
+
bidRequests = null;
|
|
1281
1310
|
});
|
|
1282
1311
|
|
|
1283
1312
|
it('should call auction done after bid is added to auction for mediaType banner', function () {
|
|
@@ -1328,19 +1357,114 @@ describe('auctionmanager.js', function () {
|
|
|
1328
1357
|
const responseBody = `{"responses":[{"uuid":"${uuid}"}]}`;
|
|
1329
1358
|
server.requests[0].respond(200, { 'Content-Type': 'application/json' }, responseBody);
|
|
1330
1359
|
assert.equal(doneSpy.callCount, 1);
|
|
1331
|
-
})
|
|
1360
|
+
});
|
|
1361
|
+
|
|
1362
|
+
describe('when addBidResponse hook returns promises', () => {
|
|
1363
|
+
let resolvers, callbacks, bids;
|
|
1364
|
+
|
|
1365
|
+
function hook(next, ...args) {
|
|
1366
|
+
next.bail(new Promise((resolve, reject) => {
|
|
1367
|
+
resolvers.resolve.push(resolve);
|
|
1368
|
+
resolvers.reject.push(reject);
|
|
1369
|
+
}).finally(() => next(...args)));
|
|
1370
|
+
}
|
|
1371
|
+
|
|
1372
|
+
function invokeCallbacks() {
|
|
1373
|
+
bids.forEach((bid, i) => callbacks.addBidResponse.call(bidRequests[i], ADUNIT_CODE, bid));
|
|
1374
|
+
bidRequests.forEach(bidRequest => callbacks.adapterDone.call(bidRequest));
|
|
1375
|
+
}
|
|
1376
|
+
|
|
1377
|
+
function delay(ms = 0) {
|
|
1378
|
+
return new Promise((resolve) => {
|
|
1379
|
+
setTimeout(resolve, ms)
|
|
1380
|
+
});
|
|
1381
|
+
}
|
|
1382
|
+
|
|
1383
|
+
beforeEach(() => {
|
|
1384
|
+
promiseSandbox.restore();
|
|
1385
|
+
bids = [
|
|
1386
|
+
mockBid({bidderCode: BIDDER_CODE1}),
|
|
1387
|
+
mockBid({bidderCode: BIDDER_CODE})
|
|
1388
|
+
]
|
|
1389
|
+
bidRequests = bids.map((b) => mockBidRequest(b));
|
|
1390
|
+
resolvers = {resolve: [], reject: []};
|
|
1391
|
+
addBidResponse.before(hook);
|
|
1392
|
+
callbacks = auctionCallbacks(doneSpy, auction);
|
|
1393
|
+
Object.assign(auction, {
|
|
1394
|
+
addNoBid: sinon.spy()
|
|
1395
|
+
});
|
|
1396
|
+
});
|
|
1397
|
+
|
|
1398
|
+
afterEach(() => {
|
|
1399
|
+
addBidResponse.getHooks({hook: hook}).remove();
|
|
1400
|
+
});
|
|
1401
|
+
|
|
1402
|
+
Object.entries({
|
|
1403
|
+
'all succeed': ['resolve', 'resolve'],
|
|
1404
|
+
'some fail': ['resolve', 'reject'],
|
|
1405
|
+
'all fail': ['reject', 'reject']
|
|
1406
|
+
}).forEach(([test, results]) => {
|
|
1407
|
+
describe(`(and ${test})`, () => {
|
|
1408
|
+
it('should wait for them to complete before calling auctionDone', () => {
|
|
1409
|
+
invokeCallbacks();
|
|
1410
|
+
return delay().then(() => {
|
|
1411
|
+
expect(doneSpy.called).to.be.false;
|
|
1412
|
+
expect(auction.addNoBid.called).to.be.false;
|
|
1413
|
+
resolvers[results[0]][0]();
|
|
1414
|
+
return delay();
|
|
1415
|
+
}).then(() => {
|
|
1416
|
+
expect(doneSpy.called).to.be.false;
|
|
1417
|
+
expect(auction.addNoBid.called).to.be.false;
|
|
1418
|
+
resolvers[results[1]][1]();
|
|
1419
|
+
return delay();
|
|
1420
|
+
}).then(() => {
|
|
1421
|
+
expect(doneSpy.called).to.be.true;
|
|
1422
|
+
});
|
|
1423
|
+
});
|
|
1424
|
+
});
|
|
1425
|
+
});
|
|
1426
|
+
|
|
1427
|
+
Object.entries({
|
|
1428
|
+
bidder: (timeout) => {
|
|
1429
|
+
bidRequests.forEach((r) => r.timeout = timeout);
|
|
1430
|
+
auction.getTimeout = () => timeout + 10000
|
|
1431
|
+
},
|
|
1432
|
+
auction: (timeout) => {
|
|
1433
|
+
auction.getTimeout = () => timeout;
|
|
1434
|
+
bidRequests.forEach((r) => r.timeout = timeout + 10000)
|
|
1435
|
+
}
|
|
1436
|
+
}).forEach(([test, setTimeout]) => {
|
|
1437
|
+
it(`should respect ${test} timeout if they never complete`, () => {
|
|
1438
|
+
const start = Date.now() - 2900;
|
|
1439
|
+
auction.getAuctionStart = () => start;
|
|
1440
|
+
setTimeout(3000);
|
|
1441
|
+
invokeCallbacks();
|
|
1442
|
+
return delay().then(() => {
|
|
1443
|
+
expect(doneSpy.called).to.be.false;
|
|
1444
|
+
return delay(100);
|
|
1445
|
+
}).then(() => {
|
|
1446
|
+
expect(doneSpy.called).to.be.true;
|
|
1447
|
+
});
|
|
1448
|
+
});
|
|
1449
|
+
|
|
1450
|
+
it(`should not wait if ${test} has already timed out`, () => {
|
|
1451
|
+
const start = Date.now() - 2000;
|
|
1452
|
+
auction.getAuctionStart = () => start;
|
|
1453
|
+
setTimeout(1000);
|
|
1454
|
+
invokeCallbacks();
|
|
1455
|
+
return delay().then(() => {
|
|
1456
|
+
expect(doneSpy.called).to.be.true;
|
|
1457
|
+
});
|
|
1458
|
+
});
|
|
1459
|
+
})
|
|
1460
|
+
});
|
|
1332
1461
|
});
|
|
1333
1462
|
|
|
1334
1463
|
describe('auctionOptions', function() {
|
|
1335
1464
|
let bidRequests;
|
|
1336
1465
|
let doneSpy;
|
|
1337
1466
|
let clock;
|
|
1338
|
-
let auction
|
|
1339
|
-
getBidRequests: () => bidRequests,
|
|
1340
|
-
getAuctionId: () => '1',
|
|
1341
|
-
addBidReceived: () => true,
|
|
1342
|
-
getTimeout: () => 1000
|
|
1343
|
-
}
|
|
1467
|
+
let auction;
|
|
1344
1468
|
let requiredBidder = BIDDER_CODE;
|
|
1345
1469
|
let requiredBidder1 = BIDDER_CODE1;
|
|
1346
1470
|
let secondaryBidder = 'doNotWaitForMe';
|
|
@@ -1352,7 +1476,15 @@ describe('auctionmanager.js', function () {
|
|
|
1352
1476
|
'auctionOptions': {
|
|
1353
1477
|
secondaryBidders: [ secondaryBidder ]
|
|
1354
1478
|
}
|
|
1355
|
-
})
|
|
1479
|
+
});
|
|
1480
|
+
const start = Date.now();
|
|
1481
|
+
auction = {
|
|
1482
|
+
getBidRequests: () => bidRequests,
|
|
1483
|
+
getAuctionId: () => '1',
|
|
1484
|
+
addBidReceived: () => true,
|
|
1485
|
+
getTimeout: () => 1000,
|
|
1486
|
+
getAuctionStart: () => start,
|
|
1487
|
+
}
|
|
1356
1488
|
});
|
|
1357
1489
|
|
|
1358
1490
|
afterEach(() => {
|