From 667bbda82a49fcf83e81cfb8c22e07fa6b9c4cc0 Mon Sep 17 00:00:00 2001 From: Michele Nasti Date: Tue, 16 May 2023 17:13:58 +0200 Subject: [PATCH] RubiconBidAdapter: sync parseSize algorithm for isBidRequestValid and ortb conversion (#9957) * sync parseSize algorithm for isBidRequestValid and ortb conversion * use same sizes of parseSizes in video outstream * general test refactor to be less flacky --------- Co-authored-by: Michele Nasti --- modules/rubiconBidAdapter.js | 6 +- test/spec/modules/rubiconBidAdapter_spec.js | 142 +++++++++++--------- 2 files changed, 79 insertions(+), 69 deletions(-) diff --git a/modules/rubiconBidAdapter.js b/modules/rubiconBidAdapter.js index 62ec61b3dcf..5c30b413780 100644 --- a/modules/rubiconBidAdapter.js +++ b/modules/rubiconBidAdapter.js @@ -208,8 +208,10 @@ export const converter = ortbConverter({ bidResponse.meta.mediaType = deepAccess(bid, 'ext.prebid.type'); const {bidRequest} = context; - bidResponse.width = bid.w || deepAccess(bidRequest, 'mediaTypes.video.w') || deepAccess(bidRequest, 'params.video.playerWidth') || bidResponse.playerWidth; - bidResponse.height = bid.h || deepAccess(bidRequest, 'mediaTypes.video.h') || deepAccess(bidRequest, 'params.video.playerHeight') || bidResponse.playerHeight; + let [parseSizeWidth, parseSizeHeight] = bidRequest.mediaTypes.video?.context === 'outstream' ? parseSizes(bidRequest, VIDEO) : [undefined, undefined]; + + bidResponse.width = bid.w || parseSizeWidth || bidResponse.playerWidth; + bidResponse.height = bid.h || parseSizeHeight || bidResponse.playerHeight; if (bidResponse.mediaType === VIDEO && bidRequest.mediaTypes.video.context === 'outstream') { bidResponse.renderer = outstreamRenderer(bidResponse); diff --git a/test/spec/modules/rubiconBidAdapter_spec.js b/test/spec/modules/rubiconBidAdapter_spec.js index 4f1c0dd606a..0c8477a0fcb 100644 --- a/test/spec/modules/rubiconBidAdapter_spec.js +++ b/test/spec/modules/rubiconBidAdapter_spec.js @@ -192,6 +192,7 @@ describe('the rubicon adapter', function () { * @param {boolean} [gdprApplies] */ function createGdprBidderRequest(gdprApplies) { + const bidderRequest = getBidderRequest(); if (typeof gdprApplies === 'boolean') { bidderRequest.gdprConsent = { 'consentString': 'BOJ/P2HOJ/P2HABABMAAAAAZ+A==', @@ -202,15 +203,16 @@ describe('the rubicon adapter', function () { 'consentString': 'BOJ/P2HOJ/P2HABABMAAAAAZ+A==' }; } + return bidderRequest; } - function createUspBidderRequest() { + function addUspToBidderRequest(bidderRequest) { bidderRequest.uspConsent = '1NYN'; } function createVideoBidderRequest() { - createGdprBidderRequest(true); - createUspBidderRequest(); + const bidderRequest = createGdprBidderRequest(true); + addUspToBidderRequest(bidderRequest); let bid = bidderRequest.bids[0]; bid.mediaTypes = { @@ -260,9 +262,10 @@ describe('the rubicon adapter', function () { criteoId: '1111', }; bid.userIdAsEids = createEidsArray(bid.userId); + return bidderRequest; } - function createVideoBidderRequestNoVideo() { + function removeVideoParamFromBidderRequest(bidderRequest) { let bid = bidderRequest.bids[0]; bid.mediaTypes = { video: { @@ -273,7 +276,9 @@ describe('the rubicon adapter', function () { } function createVideoBidderRequestOutstream() { + const bidderRequest = createGdprBidderRequest(false); let bid = bidderRequest.bids[0]; + delete bid.sizes; bid.mediaTypes = { video: { context: 'outstream', @@ -291,17 +296,20 @@ describe('the rubicon adapter', function () { protocols: [1, 2, 3, 4, 5, 6] }, }; - bid.params.accountId = 14062; - bid.params.siteId = 70608; - bid.params.zoneId = 335918; - bid.params.video = { - 'language': 'en', - 'skip': 1, - 'skipafter': 15, - 'playerHeight': 320, - 'playerWidth': 640, - 'size_id': 203 - }; + bid.params = { + accountId: 14062, + siteId: 70608, + zoneId: 335918, + video: { + 'language': 'en', + 'skip': 1, + 'skipafter': 15, + 'playerHeight': 320, + 'playerWidth': 640, + 'size_id': 203 + } + } + return bidderRequest; } beforeEach(function () { @@ -744,7 +752,7 @@ describe('the rubicon adapter', function () { describe('GDPR consent config', function () { it('should send "gdpr" and "gdpr_consent", when gdprConsent defines consentString and gdprApplies', function () { - createGdprBidderRequest(true); + const bidderRequest = createGdprBidderRequest(true); let [request] = spec.buildRequests(bidderRequest.bids, bidderRequest); let data = parseQuery(request.data); @@ -753,7 +761,7 @@ describe('the rubicon adapter', function () { }); it('should send only "gdpr_consent", when gdprConsent defines only consentString', function () { - createGdprBidderRequest(); + const bidderRequest = createGdprBidderRequest(); let [request] = spec.buildRequests(bidderRequest.bids, bidderRequest); let data = parseQuery(request.data); @@ -770,12 +778,12 @@ describe('the rubicon adapter', function () { }); it('should set "gdpr" value as 1 or 0, using "gdprApplies" value of either true/false', function () { - createGdprBidderRequest(true); + let bidderRequest = createGdprBidderRequest(true); let [request] = spec.buildRequests(bidderRequest.bids, bidderRequest); let data = parseQuery(request.data); expect(data['gdpr']).to.equal('1'); - createGdprBidderRequest(false); + bidderRequest = createGdprBidderRequest(false); [request] = spec.buildRequests(bidderRequest.bids, bidderRequest); data = parseQuery(request.data); expect(data['gdpr']).to.equal('0'); @@ -784,7 +792,7 @@ describe('the rubicon adapter', function () { describe('USP Consent', function () { it('should send us_privacy if bidderRequest has a value for uspConsent', function () { - createUspBidderRequest(); + addUspToBidderRequest(bidderRequest); let [request] = spec.buildRequests(bidderRequest.bids, bidderRequest); let data = parseQuery(request.data); @@ -1542,7 +1550,7 @@ describe('the rubicon adapter', function () { if (FEATURES.VIDEO) { describe('for video requests', function () { it('should make a well-formed video request', function () { - createVideoBidderRequest(); + const bidderRequest = createVideoBidderRequest(); sandbox.stub(Date, 'now').callsFake(() => bidderRequest.auctionStart + 100 @@ -1628,7 +1636,7 @@ describe('the rubicon adapter', function () { }); it('should add ortb values to video requests', function () { - createVideoBidderRequest(); + const bidderRequest = createVideoBidderRequest(); sandbox.stub(Date, 'now').callsFake(() => bidderRequest.auctionStart + 100 @@ -1661,7 +1669,7 @@ describe('the rubicon adapter', function () { }); it('should correctly set bidfloor on imp when getfloor in scope', function () { - createVideoBidderRequest(); + const bidderRequest = createVideoBidderRequest(); // default getFloor response is empty object so should not break and not send hard_floor bidderRequest.bids[0].getFloor = () => getFloorResponse; sinon.spy(bidderRequest.bids[0], 'getFloor'); @@ -1706,7 +1714,7 @@ describe('the rubicon adapter', function () { }); it('should continue with auction if getFloor throws error', function () { - createVideoBidderRequest(); + const bidderRequest = createVideoBidderRequest(); // default getFloor response is empty object so should not break and not send hard_floor bidderRequest.bids[0].getFloor = () => { throw new Error('An exception!'); @@ -1727,7 +1735,7 @@ describe('the rubicon adapter', function () { }); it('should add alias name to PBS Request', function () { - createVideoBidderRequest(); + const bidderRequest = createVideoBidderRequest(); adapterManager.aliasRegistry['superRubicon'] = 'rubicon'; bidderRequest.bidderCode = 'superRubicon'; bidderRequest.bids[0].bidder = 'superRubicon'; @@ -1743,7 +1751,7 @@ describe('the rubicon adapter', function () { }); it('should add floors flag correctly to PBS Request', function () { - createVideoBidderRequest(); + const bidderRequest = createVideoBidderRequest(); let [request] = spec.buildRequests(bidderRequest.bids, bidderRequest); // should not pass if undefined @@ -1759,7 +1767,7 @@ describe('the rubicon adapter', function () { }); it('should add multibid configuration to PBS Request', function () { - createVideoBidderRequest(); + const bidderRequest = createVideoBidderRequest(); const multibid = [{ bidder: 'bidderA', @@ -1786,7 +1794,7 @@ describe('the rubicon adapter', function () { }); it('should pass client analytics to PBS endpoint if all modules included', function () { - createVideoBidderRequest(); + const bidderRequest = createVideoBidderRequest(); $$PREBID_GLOBAL$$.installedModules = []; let [request] = spec.buildRequests(bidderRequest.bids, bidderRequest); let payload = request.data; @@ -1796,7 +1804,7 @@ describe('the rubicon adapter', function () { }); it('should pass client analytics to PBS endpoint if rubicon analytics adapter is included', function () { - createVideoBidderRequest(); + const bidderRequest = createVideoBidderRequest(); $$PREBID_GLOBAL$$.installedModules = ['rubiconBidAdapter', 'rubiconAnalyticsAdapter']; let [request] = spec.buildRequests(bidderRequest.bids, bidderRequest); let payload = request.data; @@ -1806,7 +1814,7 @@ describe('the rubicon adapter', function () { }); it('should not pass client analytics to PBS endpoint if rubicon analytics adapter is not included', function () { - createVideoBidderRequest(); + const bidderRequest = createVideoBidderRequest(); $$PREBID_GLOBAL$$.installedModules = ['rubiconBidAdapter']; let [request] = spec.buildRequests(bidderRequest.bids, bidderRequest); let payload = request.data; @@ -1815,7 +1823,7 @@ describe('the rubicon adapter', function () { }); it('should send video exp param correctly when set', function () { - createVideoBidderRequest(); + const bidderRequest = createVideoBidderRequest(); config.setConfig({s2sConfig: {defaultTtl: 600}}); let [request] = spec.buildRequests(bidderRequest.bids, bidderRequest); let post = request.data; @@ -1826,7 +1834,7 @@ describe('the rubicon adapter', function () { }); it('should not send video exp at all if not set in s2sConfig config', function () { - createVideoBidderRequest(); + const bidderRequest = createVideoBidderRequest(); let [request] = spec.buildRequests(bidderRequest.bids, bidderRequest); let post = request.data; @@ -1837,7 +1845,7 @@ describe('the rubicon adapter', function () { }); it('should send tmax as the bidderRequest timeout value', function () { - createVideoBidderRequest(); + const bidderRequest = createVideoBidderRequest(); bidderRequest.timeout = 3333; let [request] = spec.buildRequests(bidderRequest.bids, bidderRequest); let post = request.data; @@ -1845,7 +1853,7 @@ describe('the rubicon adapter', function () { }); it('should send correct bidfloor to PBS', function () { - createVideoBidderRequest(); + const bidderRequest = createVideoBidderRequest(); bidderRequest.bids[0].params.floor = 0.1; let [request] = spec.buildRequests(bidderRequest.bids, bidderRequest); @@ -1873,7 +1881,7 @@ describe('the rubicon adapter', function () { }); it('should send request with proper ad position', function () { - createVideoBidderRequest(); + const bidderRequest = createVideoBidderRequest(); let positionBidderRequest = utils.deepClone(bidderRequest); positionBidderRequest.bids[0].mediaTypes.video.pos = 1; let [request] = spec.buildRequests(positionBidderRequest.bids, positionBidderRequest); @@ -1943,7 +1951,7 @@ describe('the rubicon adapter', function () { }); it('should enforce the new required mediaTypes.video params', function () { - createVideoBidderRequest(); + let bidderRequest = createVideoBidderRequest(); sandbox.stub(Date, 'now').callsFake(() => bidderRequest.auctionStart + 100 @@ -1952,48 +1960,48 @@ describe('the rubicon adapter', function () { expect(spec.isBidRequestValid(bidderRequest.bids[0])).to.equal(true); // change mimes to a non array, no good - createVideoBidderRequest(); + bidderRequest = createVideoBidderRequest(); bidderRequest.bids[0].mediaTypes.video.mimes = 'video/mp4'; expect(spec.isBidRequestValid(bidderRequest.bids[0])).to.equal(false); // delete mimes, no good - createVideoBidderRequest(); + bidderRequest = createVideoBidderRequest(); delete bidderRequest.bids[0].mediaTypes.video.mimes; expect(spec.isBidRequestValid(bidderRequest.bids[0])).to.equal(false); // change protocols to an int not array of ints, no good - createVideoBidderRequest(); + bidderRequest = createVideoBidderRequest(); bidderRequest.bids[0].mediaTypes.video.protocols = 1; expect(spec.isBidRequestValid(bidderRequest.bids[0])).to.equal(false); // delete protocols, no good - createVideoBidderRequest(); + bidderRequest = createVideoBidderRequest(); delete bidderRequest.bids[0].mediaTypes.video.protocols; expect(spec.isBidRequestValid(bidderRequest.bids[0])).to.equal(false); // change linearity to an string, no good - createVideoBidderRequest(); + bidderRequest = createVideoBidderRequest(); bidderRequest.bids[0].mediaTypes.video.linearity = 'string'; expect(spec.isBidRequestValid(bidderRequest.bids[0])).to.equal(false); // delete linearity, no good - createVideoBidderRequest(); + bidderRequest = createVideoBidderRequest(); delete bidderRequest.bids[0].mediaTypes.video.linearity; expect(spec.isBidRequestValid(bidderRequest.bids[0])).to.equal(false); // change api to an string, no good - createVideoBidderRequest(); + bidderRequest = createVideoBidderRequest(); bidderRequest.bids[0].mediaTypes.video.api = 'string'; expect(spec.isBidRequestValid(bidderRequest.bids[0])).to.equal(false); // delete api, no good - createVideoBidderRequest(); + bidderRequest = createVideoBidderRequest(); delete bidderRequest.bids[0].mediaTypes.video.api; expect(spec.isBidRequestValid(bidderRequest.bids[0])).to.equal(false); }); it('bid request is valid when video context is outstream', function () { - createVideoBidderRequestOutstream(); + const bidderRequest = createVideoBidderRequestOutstream(); sandbox.stub(Date, 'now').callsFake(() => bidderRequest.auctionStart + 100 ); @@ -2035,7 +2043,7 @@ describe('the rubicon adapter', function () { }); it('should send request as banner when invalid video bid in multiple mediaType bidRequest', function () { - createVideoBidderRequestNoVideo(); + removeVideoParamFromBidderRequest(bidderRequest); let bid = bidderRequest.bids[0]; bid.mediaTypes.banner = { @@ -2054,7 +2062,7 @@ describe('the rubicon adapter', function () { }); it('should include coppa flag in video bid request', () => { - createVideoBidderRequest(); + const bidderRequest = createVideoBidderRequest(); sandbox.stub(Date, 'now').callsFake(() => bidderRequest.auctionStart + 100 @@ -2071,7 +2079,7 @@ describe('the rubicon adapter', function () { }); it('should include first party data', () => { - createVideoBidderRequest(); + const bidderRequest = createVideoBidderRequest(); const site = { ext: { @@ -2123,7 +2131,7 @@ describe('the rubicon adapter', function () { }); it('should include pbadslot in bid request', function () { - createVideoBidderRequest(); + const bidderRequest = createVideoBidderRequest(); bidderRequest.bids[0].ortb2Imp = { ext: { data: { @@ -2141,7 +2149,7 @@ describe('the rubicon adapter', function () { }); it('should NOT include storedrequests in pbs payload', function () { - createVideoBidderRequest(); + const bidderRequest = createVideoBidderRequest(); bidderRequest.bids[0].ortb2 = { ext: { prebid: { @@ -2168,7 +2176,7 @@ describe('the rubicon adapter', function () { }); it('should include GAM ad unit in bid request', function () { - createVideoBidderRequest(); + const bidderRequest = createVideoBidderRequest(); bidderRequest.bids[0].ortb2Imp = { ext: { data: { @@ -2190,7 +2198,7 @@ describe('the rubicon adapter', function () { }); it('should use the integration type provided in the config instead of the default', () => { - createVideoBidderRequest(); + const bidderRequest = createVideoBidderRequest(); config.setConfig({rubicon: {int_type: 'testType'}}); const [request] = spec.buildRequests(bidderRequest.bids, bidderRequest); expect(request.data.ext.prebid.bidders.rubicon.integration).to.equal('testType'); @@ -2198,7 +2206,7 @@ describe('the rubicon adapter', function () { it('should pass the user.id provided in the config', function () { config.setConfig({user: {id: '123'}}); - createVideoBidderRequest(); + const bidderRequest = createVideoBidderRequest(); sandbox.stub(Date, 'now').callsFake(() => bidderRequest.auctionStart + 100 @@ -2321,13 +2329,13 @@ describe('the rubicon adapter', function () { describe('classifiedAsVideo', function () { it('should return true if mediaTypes is video', function () { - createVideoBidderRequest(); + const bidderRequest = createVideoBidderRequest(); const bidClassifiedAsVideo = classifiedAsVideo(bidderRequest.bids[0]); expect(bidClassifiedAsVideo).is.equal(true); }); it('should return false if trying to use legacy mediaType with video', function () { - createVideoBidderRequest(); + const bidderRequest = createVideoBidderRequest(); delete bidderRequest.bids[0].mediaTypes; bidderRequest.bids[0].mediaType = 'video'; const legacyVideoTypeBidRequest = classifiedAsVideo(bidderRequest.bids[0]); @@ -2345,13 +2353,13 @@ describe('the rubicon adapter', function () { }); it('Should return false if both banner and video mediaTypes are set and params.video is not an object', function () { - createVideoBidderRequestNoVideo(); + removeVideoParamFromBidderRequest(bidderRequest); let bid = bidderRequest.bids[0]; bid.mediaTypes.banner = {flag: true}; expect(classifiedAsVideo(bid)).to.equal(false); }); it('Should return true if both banner and video mediaTypes are set and params.video is an object', function () { - createVideoBidderRequestNoVideo(); + removeVideoParamFromBidderRequest(bidderRequest); let bid = bidderRequest.bids[0]; bid.mediaTypes.banner = {flag: true}; bid.params.video = {}; @@ -2359,7 +2367,7 @@ describe('the rubicon adapter', function () { }); it('Should return true and create a params.video object if one is not already present', function () { - createVideoBidderRequestNoVideo(); + removeVideoParamFromBidderRequest(bidderRequest); let bid = bidderRequest.bids[0] expect(classifiedAsVideo(bid)).to.equal(true); expect(bid.params.video).to.not.be.undefined; @@ -3213,11 +3221,8 @@ describe('the rubicon adapter', function () { if (FEATURES.VIDEO) { describe('for video', function () { - beforeEach(function () { - createVideoBidderRequest(); - }); - it('should register a successful bid', function () { + const bidderRequest = createVideoBidderRequest(); let response = { cur: 'USD', seatbid: [{ @@ -3288,7 +3293,6 @@ describe('the rubicon adapter', function () { describe('for outstream video', function () { const sandbox = sinon.createSandbox(); beforeEach(function () { - createVideoBidderRequestOutstream(); config.setConfig({rubicon: { rendererConfig: { align: 'left', @@ -3309,6 +3313,7 @@ describe('the rubicon adapter', function () { }); it('should register a successful bid', function () { + const bidderRequest = createVideoBidderRequestOutstream(); let response = { cur: 'USD', seatbid: [{ @@ -3369,6 +3374,7 @@ describe('the rubicon adapter', function () { }); it('should render ad with Magnite renderer', function () { + const bidderRequest = createVideoBidderRequestOutstream(); let response = { cur: 'USD', seatbid: [{ @@ -3432,6 +3438,7 @@ describe('the rubicon adapter', function () { }); it('should render ad with Magnite renderer without video object', function () { + const bidderRequest = createVideoBidderRequestOutstream(); delete bidderRequest.bids[0].params.video; bidderRequest.bids[0].params.bidonmultiformat = true; bidderRequest.bids[0].mediaTypes.video.placement = 3; @@ -3749,7 +3756,7 @@ describe('the rubicon adapter', function () { }); it('should copy the schain JSON to to bid.source.ext.schain', () => { - createVideoBidderRequest(); + const bidderRequest = createVideoBidderRequest(); const schain = getSupplyChainConfig(); bidderRequest.bids[0].schain = schain; const request = spec.buildRequests(bidderRequest.bids, bidderRequest); @@ -3785,12 +3792,13 @@ describe('the rubicon adapter', function () { }); // banner - let [bannerRequest] = spec.buildRequests(bidderRequest.bids, bidderRequest); + const bannerBidderRequest = createGdprBidderRequest(false); + let [bannerRequest] = spec.buildRequests(bannerBidderRequest.bids, bannerBidderRequest); expect(bannerRequest.url).to.equal('https://fastlane-qa.rubiconproject.com/a/api/fastlane.json'); // video and returnVast - createVideoBidderRequest(); - let [videoRequest] = spec.buildRequests(bidderRequest.bids, bidderRequest); + const videoBidderRequest = createVideoBidderRequest(); + let [videoRequest] = spec.buildRequests(videoBidderRequest.bids, videoBidderRequest); let post = videoRequest.data; expect(videoRequest.url).to.equal('https://prebid-server-qa.rubiconproject.com/openrtb2/auction'); expect(post.ext.prebid.cache.vastxml).to.have.property('returnCreative').that.is.an('boolean');