prebid.js 5.20.2 → 5.20.3
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/.circleci/config.yml +4 -5
- package/modules/pubmaticBidAdapter.js +1 -1
- package/package.json +1 -1
- package/src/prebid.js +20 -4
- package/src/targeting.js +8 -0
- package/test/fixtures/fixtures.js +2 -1
- package/test/spec/modules/pubmaticBidAdapter_spec.js +40 -0
- package/test/spec/unit/core/targeting_spec.js +93 -0
- package/test/spec/unit/pbjs_api_spec.js +3 -1
package/.circleci/config.yml
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
# Check https://circleci.com/docs/2.0/language-javascript/ for more details
|
|
4
4
|
#
|
|
5
5
|
|
|
6
|
-
aliases:
|
|
6
|
+
aliases:
|
|
7
7
|
- &environment
|
|
8
8
|
docker:
|
|
9
9
|
# specify the version you desire here
|
|
@@ -17,9 +17,8 @@ aliases:
|
|
|
17
17
|
|
|
18
18
|
- &restore_dep_cache
|
|
19
19
|
keys:
|
|
20
|
-
-
|
|
21
|
-
|
|
22
|
-
- v1-dependencies-
|
|
20
|
+
- v5.20.x-legacy-dependencies-{{ checksum "package.json" }}
|
|
21
|
+
- v5.20.x-legacy-dependencies-
|
|
23
22
|
|
|
24
23
|
- &save_dep_cache
|
|
25
24
|
paths:
|
|
@@ -72,7 +71,7 @@ jobs:
|
|
|
72
71
|
build:
|
|
73
72
|
<<: *environment
|
|
74
73
|
steps: *unit_test_steps
|
|
75
|
-
|
|
74
|
+
|
|
76
75
|
e2etest:
|
|
77
76
|
<<: *environment
|
|
78
77
|
steps: *endtoend_test_steps
|
|
@@ -1078,7 +1078,7 @@ export const spec = {
|
|
|
1078
1078
|
bid = deepClone(originalBid);
|
|
1079
1079
|
bid.params.adSlot = bid.params.adSlot || '';
|
|
1080
1080
|
_parseAdSlot(bid);
|
|
1081
|
-
if (bid.params.hasOwnProperty('video')) {
|
|
1081
|
+
if ((bid.mediaTypes && bid.mediaTypes.hasOwnProperty('video')) || bid.params.hasOwnProperty('video')) {
|
|
1082
1082
|
// Nothing to do
|
|
1083
1083
|
} else {
|
|
1084
1084
|
// If we have a native mediaType configured alongside banner, its ok if the banner size is not set in width and height
|
package/package.json
CHANGED
package/src/prebid.js
CHANGED
|
@@ -403,10 +403,23 @@ function emitAdRenderSucceeded({ doc, bid, id }) {
|
|
|
403
403
|
events.emit(AD_RENDER_SUCCEEDED, data);
|
|
404
404
|
}
|
|
405
405
|
|
|
406
|
+
/**
|
|
407
|
+
* This function will check for presence of given node in given parent. If not present - will inject it.
|
|
408
|
+
* @param {Node} node node, whose existance is in question
|
|
409
|
+
* @param {Document} doc document element do look in
|
|
410
|
+
* @param {string} tagName tag name to look in
|
|
411
|
+
*/
|
|
412
|
+
function reinjectNodeIfRemoved(node, doc, tagName) {
|
|
413
|
+
const injectionNode = doc.querySelector(tagName);
|
|
414
|
+
if (!node.parentNode || node.parentNode !== injectionNode) {
|
|
415
|
+
insertElement(node, doc, tagName);
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
|
|
406
419
|
/**
|
|
407
420
|
* This function will render the ad (based on params) in the given iframe document passed through.
|
|
408
421
|
* Note that doc SHOULD NOT be the parent document page as we can't doc.write() asynchronously
|
|
409
|
-
* @param {
|
|
422
|
+
* @param {Document} doc document
|
|
410
423
|
* @param {string} id bid id to locate the ad
|
|
411
424
|
* @alias module:pbjs.renderAd
|
|
412
425
|
*/
|
|
@@ -450,10 +463,13 @@ $$PREBID_GLOBAL$$.renderAd = hook('async', function (doc, id, options) {
|
|
|
450
463
|
const {height, width, ad, mediaType, adUrl, renderer} = bid;
|
|
451
464
|
|
|
452
465
|
const creativeComment = document.createComment(`Creative ${bid.creativeId} served by ${bid.bidder} Prebid.js Header Bidding`);
|
|
466
|
+
// It is important that the comment with metadata is injected before the ad is actually rendered,
|
|
467
|
+
// so the creativeId can be used by e.g. ad quality scanners to check against blocking rules
|
|
468
|
+
insertElement(creativeComment, doc, 'html');
|
|
453
469
|
|
|
454
470
|
if (isRendererRequired(renderer)) {
|
|
455
471
|
executeRenderer(renderer, bid);
|
|
456
|
-
|
|
472
|
+
reinjectNodeIfRemoved(creativeComment, doc, 'html');
|
|
457
473
|
emitAdRenderSucceeded({ doc, bid, id });
|
|
458
474
|
} else if ((doc === document && !inIframe()) || mediaType === 'video') {
|
|
459
475
|
const message = `Error trying to write ad. Ad render call ad id ${id} was prevented from writing to the main document.`;
|
|
@@ -472,7 +488,7 @@ $$PREBID_GLOBAL$$.renderAd = hook('async', function (doc, id, options) {
|
|
|
472
488
|
doc.write(ad);
|
|
473
489
|
doc.close();
|
|
474
490
|
setRenderSize(doc, width, height);
|
|
475
|
-
|
|
491
|
+
reinjectNodeIfRemoved(creativeComment, doc, 'html');
|
|
476
492
|
callBurl(bid);
|
|
477
493
|
emitAdRenderSucceeded({ doc, bid, id });
|
|
478
494
|
} else if (adUrl) {
|
|
@@ -485,7 +501,7 @@ $$PREBID_GLOBAL$$.renderAd = hook('async', function (doc, id, options) {
|
|
|
485
501
|
|
|
486
502
|
insertElement(iframe, doc, 'body');
|
|
487
503
|
setRenderSize(doc, width, height);
|
|
488
|
-
|
|
504
|
+
reinjectNodeIfRemoved(creativeComment, doc, 'html');
|
|
489
505
|
callBurl(bid);
|
|
490
506
|
emitAdRenderSucceeded({ doc, bid, id });
|
|
491
507
|
} else {
|
package/src/targeting.js
CHANGED
|
@@ -416,7 +416,15 @@ export function newTargeting(auctionManager) {
|
|
|
416
416
|
let bidsReceived = auctionManager.getBidsReceived();
|
|
417
417
|
|
|
418
418
|
if (!config.getConfig('useBidCache')) {
|
|
419
|
+
// don't use bid cache (i.e. filter out bids not in the latest auction)
|
|
419
420
|
bidsReceived = bidsReceived.filter(bid => latestAuctionForAdUnit[bid.adUnitCode] === bid.auctionId)
|
|
421
|
+
} else {
|
|
422
|
+
// if custom bid cache filter function exists, run for each bid from
|
|
423
|
+
// previous auctions. If it returns true, include bid in bid pool
|
|
424
|
+
const filterFunction = config.getConfig('bidCacheFilterFunction');
|
|
425
|
+
if (typeof filterFunction === 'function') {
|
|
426
|
+
bidsReceived = bidsReceived.filter(bid => latestAuctionForAdUnit[bid.adUnitCode] === bid.auctionId || !!filterFunction(bid))
|
|
427
|
+
}
|
|
420
428
|
}
|
|
421
429
|
|
|
422
430
|
bidsReceived = bidsReceived
|
|
@@ -1231,7 +1231,7 @@ export function getCurrencyRates() {
|
|
|
1231
1231
|
};
|
|
1232
1232
|
}
|
|
1233
1233
|
|
|
1234
|
-
export function createBidReceived({bidder, cpm, auctionId, responseTimestamp, adUnitCode, adId, status, ttl, requestId}) {
|
|
1234
|
+
export function createBidReceived({bidder, cpm, auctionId, responseTimestamp, adUnitCode, adId, status, ttl, requestId, mediaType}) {
|
|
1235
1235
|
let bid = {
|
|
1236
1236
|
'bidderCode': bidder,
|
|
1237
1237
|
'width': '300',
|
|
@@ -1259,6 +1259,7 @@ export function createBidReceived({bidder, cpm, auctionId, responseTimestamp, ad
|
|
|
1259
1259
|
'hb_pb': cpm,
|
|
1260
1260
|
'foobar': '300x250'
|
|
1261
1261
|
}),
|
|
1262
|
+
'mediaType': mediaType,
|
|
1262
1263
|
'netRevenue': true,
|
|
1263
1264
|
'currency': 'USD',
|
|
1264
1265
|
'ttl': (!ttl) ? 300 : ttl
|
|
@@ -3861,4 +3861,44 @@ describe('PubMatic adapter', function () {
|
|
|
3861
3861
|
})
|
|
3862
3862
|
});
|
|
3863
3863
|
});
|
|
3864
|
+
|
|
3865
|
+
describe('Video request params', function() {
|
|
3866
|
+
let sandbox, utilsMock, newVideoRequest;
|
|
3867
|
+
beforeEach(() => {
|
|
3868
|
+
utilsMock = sinon.mock(utils);
|
|
3869
|
+
sandbox = sinon.sandbox.create();
|
|
3870
|
+
sandbox.spy(utils, 'logWarn');
|
|
3871
|
+
newVideoRequest = utils.deepClone(videoBidRequests)
|
|
3872
|
+
});
|
|
3873
|
+
|
|
3874
|
+
afterEach(() => {
|
|
3875
|
+
utilsMock.restore();
|
|
3876
|
+
sandbox.restore();
|
|
3877
|
+
})
|
|
3878
|
+
|
|
3879
|
+
it('Should log warning if video params from mediaTypes and params obj of bid are not present', function () {
|
|
3880
|
+
delete newVideoRequest[0].mediaTypes.video;
|
|
3881
|
+
delete newVideoRequest[0].params.video;
|
|
3882
|
+
|
|
3883
|
+
let request = spec.buildRequests(newVideoRequest, {
|
|
3884
|
+
auctionId: 'new-auction-id'
|
|
3885
|
+
});
|
|
3886
|
+
|
|
3887
|
+
sinon.assert.calledOnce(utils.logWarn);
|
|
3888
|
+
expect(request).to.equal(undefined);
|
|
3889
|
+
});
|
|
3890
|
+
|
|
3891
|
+
it('Should consider video params from mediaType object of bid', function () {
|
|
3892
|
+
delete newVideoRequest[0].params.video;
|
|
3893
|
+
|
|
3894
|
+
let request = spec.buildRequests(newVideoRequest, {
|
|
3895
|
+
auctionId: 'new-auction-id'
|
|
3896
|
+
});
|
|
3897
|
+
let data = JSON.parse(request.data);
|
|
3898
|
+
expect(data.imp[0].video).to.exist;
|
|
3899
|
+
expect(data.imp[0]['video']['w']).to.equal(videoBidRequests[0].mediaTypes.video.playerSize[0]);
|
|
3900
|
+
expect(data.imp[0]['video']['h']).to.equal(videoBidRequests[0].mediaTypes.video.playerSize[1]);
|
|
3901
|
+
expect(data.imp[0]['video']['battr']).to.equal(undefined);
|
|
3902
|
+
});
|
|
3903
|
+
});
|
|
3864
3904
|
});
|
|
@@ -227,6 +227,8 @@ describe('targeting tests', function () {
|
|
|
227
227
|
let sandbox;
|
|
228
228
|
let enableSendAllBids = false;
|
|
229
229
|
let useBidCache;
|
|
230
|
+
let bidCacheFilterFunction;
|
|
231
|
+
let undef;
|
|
230
232
|
|
|
231
233
|
beforeEach(function() {
|
|
232
234
|
sandbox = sinon.sandbox.create();
|
|
@@ -241,12 +243,16 @@ describe('targeting tests', function () {
|
|
|
241
243
|
if (key === 'useBidCache') {
|
|
242
244
|
return useBidCache;
|
|
243
245
|
}
|
|
246
|
+
if (key === 'bidCacheFilterFunction') {
|
|
247
|
+
return bidCacheFilterFunction;
|
|
248
|
+
}
|
|
244
249
|
return origGetConfig.apply(config, arguments);
|
|
245
250
|
});
|
|
246
251
|
});
|
|
247
252
|
|
|
248
253
|
afterEach(function () {
|
|
249
254
|
sandbox.restore();
|
|
255
|
+
bidCacheFilterFunction = undef;
|
|
250
256
|
});
|
|
251
257
|
|
|
252
258
|
describe('getAllTargeting', function () {
|
|
@@ -785,6 +791,93 @@ describe('targeting tests', function () {
|
|
|
785
791
|
expect(bids[0].adId).to.equal('adid-2');
|
|
786
792
|
});
|
|
787
793
|
|
|
794
|
+
it('should use bidCacheFilterFunction', function() {
|
|
795
|
+
auctionManagerStub.returns([
|
|
796
|
+
createBidReceived({bidder: 'appnexus', cpm: 7, auctionId: 1, responseTimestamp: 100, adUnitCode: 'code-0', adId: 'adid-1', mediaType: 'banner'}),
|
|
797
|
+
createBidReceived({bidder: 'appnexus', cpm: 5, auctionId: 2, responseTimestamp: 102, adUnitCode: 'code-0', adId: 'adid-2', mediaType: 'banner'}),
|
|
798
|
+
createBidReceived({bidder: 'appnexus', cpm: 6, auctionId: 1, responseTimestamp: 101, adUnitCode: 'code-1', adId: 'adid-3', mediaType: 'banner'}),
|
|
799
|
+
createBidReceived({bidder: 'appnexus', cpm: 8, auctionId: 2, responseTimestamp: 103, adUnitCode: 'code-1', adId: 'adid-4', mediaType: 'banner'}),
|
|
800
|
+
createBidReceived({bidder: 'appnexus', cpm: 27, auctionId: 1, responseTimestamp: 100, adUnitCode: 'code-2', adId: 'adid-5', mediaType: 'video'}),
|
|
801
|
+
createBidReceived({bidder: 'appnexus', cpm: 25, auctionId: 2, responseTimestamp: 102, adUnitCode: 'code-2', adId: 'adid-6', mediaType: 'video'}),
|
|
802
|
+
createBidReceived({bidder: 'appnexus', cpm: 26, auctionId: 1, responseTimestamp: 101, adUnitCode: 'code-3', adId: 'adid-7', mediaType: 'video'}),
|
|
803
|
+
createBidReceived({bidder: 'appnexus', cpm: 28, auctionId: 2, responseTimestamp: 103, adUnitCode: 'code-3', adId: 'adid-8', mediaType: 'video'}),
|
|
804
|
+
]);
|
|
805
|
+
|
|
806
|
+
let adUnitCodes = ['code-0', 'code-1', 'code-2', 'code-3'];
|
|
807
|
+
targetingInstance.setLatestAuctionForAdUnit('code-0', 2);
|
|
808
|
+
targetingInstance.setLatestAuctionForAdUnit('code-1', 2);
|
|
809
|
+
targetingInstance.setLatestAuctionForAdUnit('code-2', 2);
|
|
810
|
+
targetingInstance.setLatestAuctionForAdUnit('code-3', 2);
|
|
811
|
+
|
|
812
|
+
// Bid Caching On, No Filter Function
|
|
813
|
+
useBidCache = true;
|
|
814
|
+
bidCacheFilterFunction = undef;
|
|
815
|
+
let bids = targetingInstance.getWinningBids(adUnitCodes);
|
|
816
|
+
|
|
817
|
+
expect(bids.length).to.equal(4);
|
|
818
|
+
expect(bids[0].adId).to.equal('adid-1');
|
|
819
|
+
expect(bids[1].adId).to.equal('adid-4');
|
|
820
|
+
expect(bids[2].adId).to.equal('adid-5');
|
|
821
|
+
expect(bids[3].adId).to.equal('adid-8');
|
|
822
|
+
|
|
823
|
+
// Bid Caching Off, No Filter Function
|
|
824
|
+
useBidCache = false;
|
|
825
|
+
bidCacheFilterFunction = undef;
|
|
826
|
+
bids = targetingInstance.getWinningBids(adUnitCodes);
|
|
827
|
+
|
|
828
|
+
expect(bids.length).to.equal(4);
|
|
829
|
+
expect(bids[0].adId).to.equal('adid-2');
|
|
830
|
+
expect(bids[1].adId).to.equal('adid-4');
|
|
831
|
+
expect(bids[2].adId).to.equal('adid-6');
|
|
832
|
+
expect(bids[3].adId).to.equal('adid-8');
|
|
833
|
+
|
|
834
|
+
// Bid Caching On AGAIN, No Filter Function (should be same as first time)
|
|
835
|
+
useBidCache = true;
|
|
836
|
+
bidCacheFilterFunction = undef;
|
|
837
|
+
bids = targetingInstance.getWinningBids(adUnitCodes);
|
|
838
|
+
|
|
839
|
+
expect(bids.length).to.equal(4);
|
|
840
|
+
expect(bids[0].adId).to.equal('adid-1');
|
|
841
|
+
expect(bids[1].adId).to.equal('adid-4');
|
|
842
|
+
expect(bids[2].adId).to.equal('adid-5');
|
|
843
|
+
expect(bids[3].adId).to.equal('adid-8');
|
|
844
|
+
|
|
845
|
+
// Bid Caching On, with Filter Function to Exclude video
|
|
846
|
+
useBidCache = true;
|
|
847
|
+
let bcffCalled = 0;
|
|
848
|
+
bidCacheFilterFunction = bid => {
|
|
849
|
+
bcffCalled++;
|
|
850
|
+
return bid.mediaType !== 'video';
|
|
851
|
+
}
|
|
852
|
+
bids = targetingInstance.getWinningBids(adUnitCodes);
|
|
853
|
+
|
|
854
|
+
expect(bids.length).to.equal(4);
|
|
855
|
+
expect(bids[0].adId).to.equal('adid-1');
|
|
856
|
+
expect(bids[1].adId).to.equal('adid-4');
|
|
857
|
+
expect(bids[2].adId).to.equal('adid-6');
|
|
858
|
+
expect(bids[3].adId).to.equal('adid-8');
|
|
859
|
+
// filter function should have been called for each cached bid (4 times)
|
|
860
|
+
expect(bcffCalled).to.equal(4);
|
|
861
|
+
|
|
862
|
+
// Bid Caching Off, with Filter Function to Exclude video
|
|
863
|
+
// - should not use cached bids or call the filter function
|
|
864
|
+
useBidCache = false;
|
|
865
|
+
bcffCalled = 0;
|
|
866
|
+
bidCacheFilterFunction = bid => {
|
|
867
|
+
bcffCalled++;
|
|
868
|
+
return bid.mediaType !== 'video';
|
|
869
|
+
}
|
|
870
|
+
bids = targetingInstance.getWinningBids(adUnitCodes);
|
|
871
|
+
|
|
872
|
+
expect(bids.length).to.equal(4);
|
|
873
|
+
expect(bids[0].adId).to.equal('adid-2');
|
|
874
|
+
expect(bids[1].adId).to.equal('adid-4');
|
|
875
|
+
expect(bids[2].adId).to.equal('adid-6');
|
|
876
|
+
expect(bids[3].adId).to.equal('adid-8');
|
|
877
|
+
// filter function should not have been called
|
|
878
|
+
expect(bcffCalled).to.equal(0);
|
|
879
|
+
});
|
|
880
|
+
|
|
788
881
|
it('should not use rendered bid to get winning bid', function () {
|
|
789
882
|
let bidsReceived = [
|
|
790
883
|
createBidReceived({bidder: 'appnexus', cpm: 8, auctionId: 1, responseTimestamp: 100, adUnitCode: 'code-0', adId: 'adid-1', status: 'rendered'}),
|
|
@@ -1135,13 +1135,15 @@ describe('Unit: Prebid Module', function () {
|
|
|
1135
1135
|
height: 0
|
|
1136
1136
|
}
|
|
1137
1137
|
},
|
|
1138
|
-
getElementsByTagName: sinon.stub()
|
|
1138
|
+
getElementsByTagName: sinon.stub(),
|
|
1139
|
+
querySelector: sinon.stub()
|
|
1139
1140
|
};
|
|
1140
1141
|
|
|
1141
1142
|
elStub = {
|
|
1142
1143
|
insertBefore: sinon.stub()
|
|
1143
1144
|
};
|
|
1144
1145
|
doc.getElementsByTagName.returns([elStub]);
|
|
1146
|
+
doc.querySelector.returns(elStub);
|
|
1145
1147
|
|
|
1146
1148
|
spyLogError = sinon.spy(utils, 'logError');
|
|
1147
1149
|
spyLogMessage = sinon.spy(utils, 'logMessage');
|