From 8344d13f76175dacdd64537317122223720b59b1 Mon Sep 17 00:00:00 2001 From: Rupesh Lakhani <35333377+AskRupert-DM@users.noreply.github.com> Date: Tue, 11 Jun 2024 11:05:38 +0100 Subject: [PATCH] Update ozoneBidAdapter_spec.js updated spec test following updates to adapter based of prebid feedback --- test/spec/modules/ozoneBidAdapter_spec.js | 218 +++++++++++++++++++++- 1 file changed, 214 insertions(+), 4 deletions(-) diff --git a/test/spec/modules/ozoneBidAdapter_spec.js b/test/spec/modules/ozoneBidAdapter_spec.js index 1e7f71332f2..809c82d576b 100644 --- a/test/spec/modules/ozoneBidAdapter_spec.js +++ b/test/spec/modules/ozoneBidAdapter_spec.js @@ -6,6 +6,7 @@ import {getGranularityKeyName, getGranularityObject} from '../../../modules/ozon import * as utils from '../../../src/utils.js'; const OZONEURI = 'https://elb.the-ozone-project.com/openrtb2/auction'; const BIDDER_CODE = 'ozone'; + var validBidRequests = [ { adUnitCode: 'div-gpt-ad-1460505748561-0', @@ -62,6 +63,8 @@ var validBidRequestsMulti = [ transactionId: '2e63c0ed-b10c-4008-aed5-84582cecfe87' } ]; +// use 'pubcid', 'tdid', 'id5id', 'parrableId', 'idl_env', 'criteoId' +// see http://prebid.org/dev-docs/modules/userId.html var validBidRequestsWithUserIdData = [ { adUnitCode: 'div-gpt-ad-1460505748561-0', @@ -140,6 +143,7 @@ var validBidRequestsWithUserIdData = [ }] } ] + } ]; var validBidRequestsMinimal = [ @@ -168,6 +172,7 @@ var validBidRequestsNoSizes = [ transactionId: '2e63c0ed-b10c-4008-aed5-84582cecfe87' } ]; + var validBidRequestsWithBannerMediaType = [ { adUnitCode: 'div-gpt-ad-1460505748561-0', @@ -196,6 +201,7 @@ var validBidRequestsWithNonBannerMediaTypesAndValidOutstreamVideo = [ transactionId: '2e63c0ed-b10c-4008-aed5-84582cecfe87' } ]; + var validBidRequests1OutstreamVideo2020 = [ { 'bidder': 'ozone', @@ -278,6 +284,8 @@ var validBidRequests1OutstreamVideo2020 = [ 'bidderWinsCount': 0 } ]; + +// WHEN sent as bidderRequest to buildRequests you should send the child: .bidderRequest var validBidderRequest1OutstreamVideo2020 = { bidderRequest: { auctionId: '27dcb421-95c6-4024-a624-3c03816c5f99', @@ -380,6 +388,7 @@ var validBidderRequest1OutstreamVideo2020 = { timeout: 3000 } }; + var validBidderRequest = { auctionId: '27dcb421-95c6-4024-a624-3c03816c5f99', auctionStart: 1536838908986, @@ -401,6 +410,12 @@ var validBidderRequest = { start: 1536838908987, timeout: 3000 }; + +// bidder request with GDPR - change the values for testing: +// gdprConsent.gdprApplies (true/false) +// gdprConsent.vendorData.purposeConsents (make empty, make null, remove it) +// gdprConsent.vendorData.vendorConsents (remove 524, remove all, make the element null, remove it) +// WHEN sent as bidderRequest to buildRequests you should send the child: .bidderRequest var bidderRequestWithFullGdpr = { auctionId: '27dcb421-95c6-4024-a624-3c03816c5f99', auctionStart: 1536838908986, @@ -454,6 +469,7 @@ var bidderRequestWithFullGdpr = { 'gdprApplies': true } }; + var gdpr1 = { 'consentString': 'BOh7mtYOh7mtYAcABBENCU-AAAAncgPIXJiiAoao0PxBFkgCAC8ACIAAQAQQAAIAAAIAAAhBGAAAQAQAEQgAAAAAAABAAAAAAAAAAAAAAACAAAAAAAACgAAAAABAAAAQAAAAAAA', 'vendorData': { @@ -486,6 +502,8 @@ var gdpr1 = { }, 'gdprApplies': true }; + +// simulating the Mirror var bidderRequestWithPartialGdpr = { bidderRequest: { auctionId: '27dcb421-95c6-4024-a624-3c03816c5f99', @@ -530,6 +548,8 @@ var bidderRequestWithPartialGdpr = { } } }; + +// make sure the impid matches the request bidId var validResponse = { 'body': { 'id': 'd6198807-7a53-4141-b2db-d2cb754d68ba', @@ -586,6 +606,7 @@ var validResponse = { }, 'headers': {} }; + var validResponse2Bids = { 'body': { 'id': 'd6198807-7a53-4141-b2db-d2cb754d68ba', @@ -672,6 +693,9 @@ var validResponse2Bids = { }, 'headers': {} }; +/* +A bidder returns a bid for both sizes in an adunit + */ var validResponse2BidsSameAdunit = { 'body': { 'id': 'd6198807-7a53-4141-b2db-d2cb754d68ba', @@ -758,6 +782,14 @@ var validResponse2BidsSameAdunit = { }, 'headers': {} }; +/* + +SPECIAL CONSIDERATION FOR VIDEO TESTS: + +DO NOT USE _validVideoResponse directly - the interpretResponse function will modify it (adding a renderer!!!) so all +subsequent calls will already have a renderer attached!!! + +*/ function getCleanValidVideoResponse() { return JSON.parse(JSON.stringify(_validVideoResponse)); } @@ -843,6 +875,7 @@ var _validVideoResponse = { }, 'headers': {} }; + var validBidResponse1adWith2Bidders = { 'body': { 'id': '91221f96-b931-4acc-8f05-c2a1186fa5ac', @@ -933,6 +966,11 @@ var validBidResponse1adWith2Bidders = { }, 'headers': {} }; + +/* +testing 2 ads, 2 bidders, one bidder bids for both slots in one adunit + */ + var multiRequest1 = [ { 'bidder': 'ozone', @@ -1065,6 +1103,7 @@ var multiRequest1 = [ 'bidderWinsCount': 0 } ]; + var multiBidderRequest1 = { 'bidderCode': 'ozone', 'auctionId': '592ee33b-fb2e-4c00-b2d5-383e99cac57f', @@ -1237,6 +1276,7 @@ var multiBidderRequest1 = { }, 'start': 1592918645578 }; + var multiResponse1 = { 'body': { 'id': '592ee33b-fb2e-4c00-b2d5-383e99cac57f', @@ -1448,8 +1488,14 @@ var multiResponse1 = { }, 'headers': {} }; + +/* +--------------------end of 2 slots, 2 ---------------------------- + */ + describe('ozone Adapter', function () { describe('isBidRequestValid', function () { + // A test ad unit that will consistently return test creatives let validBidReq = { bidder: BIDDER_CODE, params: { @@ -1458,10 +1504,13 @@ describe('ozone Adapter', function () { siteId: '1234567890' } }; + it('should return true when required params found', function () { expect(spec.isBidRequestValid(validBidReq)).to.equal(true); }); + var validBidReq2 = { + bidder: BIDDER_CODE, params: { placementId: '1310000099', @@ -1471,9 +1520,11 @@ describe('ozone Adapter', function () { }, siteId: 1234567890 } + it('should return true when required params found and all optional params are valid', function () { expect(spec.isBidRequestValid(validBidReq2)).to.equal(true); }); + var xEmptyPlacement = { bidder: BIDDER_CODE, params: { @@ -1482,9 +1533,11 @@ describe('ozone Adapter', function () { siteId: '1234567890' } }; + it('should not validate empty placementId', function () { expect(spec.isBidRequestValid(xEmptyPlacement)).to.equal(false); }); + var xMissingPlacement = { bidder: BIDDER_CODE, params: { @@ -1492,9 +1545,11 @@ describe('ozone Adapter', function () { siteId: '1234567890' } }; + it('should not validate missing placementId', function () { expect(spec.isBidRequestValid(xMissingPlacement)).to.equal(false); }); + var xBadPlacement = { bidder: BIDDER_CODE, params: { @@ -1503,9 +1558,11 @@ describe('ozone Adapter', function () { siteId: '1234567890' } }; + it('should not validate placementId with a non-numeric value', function () { expect(spec.isBidRequestValid(xBadPlacement)).to.equal(false); }); + var xBadPlacementTooShort = { bidder: BIDDER_CODE, params: { @@ -1514,9 +1571,11 @@ describe('ozone Adapter', function () { siteId: '1234567890' } }; + it('should not validate placementId with a numeric value of wrong length', function () { expect(spec.isBidRequestValid(xBadPlacementTooShort)).to.equal(false); }); + var xBadPlacementTooLong = { bidder: BIDDER_CODE, params: { @@ -1525,9 +1584,11 @@ describe('ozone Adapter', function () { siteId: '1234567890' } }; + it('should not validate placementId with a numeric value of wrong length', function () { expect(spec.isBidRequestValid(xBadPlacementTooLong)).to.equal(false); }); + var xMissingPublisher = { bidder: BIDDER_CODE, params: { @@ -1535,9 +1596,11 @@ describe('ozone Adapter', function () { siteId: '1234567890' } }; + it('should not validate missing publisherId', function () { expect(spec.isBidRequestValid(xMissingPublisher)).to.equal(false); }); + var xMissingSiteId = { bidder: BIDDER_CODE, params: { @@ -1545,9 +1608,11 @@ describe('ozone Adapter', function () { placementId: '1234567890', } }; + it('should not validate missing sitetId', function () { expect(spec.isBidRequestValid(xMissingSiteId)).to.equal(false); }); + var xBadPublisherTooShort = { bidder: BIDDER_CODE, params: { @@ -1556,9 +1621,11 @@ describe('ozone Adapter', function () { siteId: '1234567890' } }; + it('should not validate publisherId being too short', function () { expect(spec.isBidRequestValid(xBadPublisherTooShort)).to.equal(false); }); + var xBadPublisherTooLong = { bidder: BIDDER_CODE, params: { @@ -1567,9 +1634,11 @@ describe('ozone Adapter', function () { siteId: '1234567890' } }; + it('should not validate publisherId being too long', function () { expect(spec.isBidRequestValid(xBadPublisherTooLong)).to.equal(false); }); + var publisherNumericOk = { bidder: BIDDER_CODE, params: { @@ -1578,9 +1647,11 @@ describe('ozone Adapter', function () { siteId: '1234567890' } }; + it('should validate publisherId being 12 digits', function () { expect(spec.isBidRequestValid(publisherNumericOk)).to.equal(true); }); + var xEmptyPublisher = { bidder: BIDDER_CODE, params: { @@ -1589,9 +1660,11 @@ describe('ozone Adapter', function () { siteId: '1234567890' } }; + it('should not validate empty publisherId', function () { expect(spec.isBidRequestValid(xEmptyPublisher)).to.equal(false); }); + var xBadSite = { bidder: BIDDER_CODE, params: { @@ -1600,15 +1673,19 @@ describe('ozone Adapter', function () { siteId: '12345Z' } }; + it('should not validate bad siteId', function () { expect(spec.isBidRequestValid(xBadSite)).to.equal(false); }); + it('should not validate siteId too long', function () { expect(spec.isBidRequestValid(xBadSite)).to.equal(false); }); + it('should not validate siteId too short', function () { expect(spec.isBidRequestValid(xBadSite)).to.equal(false); }); + var allNonStrings = { bidder: BIDDER_CODE, params: { @@ -1617,9 +1694,11 @@ describe('ozone Adapter', function () { siteId: 1234567890 } }; + it('should validate all numeric values being sent as non-string numbers', function () { expect(spec.isBidRequestValid(allNonStrings)).to.equal(true); }); + var emptySiteId = { bidder: BIDDER_CODE, params: { @@ -1628,9 +1707,11 @@ describe('ozone Adapter', function () { siteId: '' } }; + it('should not validate siteId being empty string (it is required now)', function () { expect(spec.isBidRequestValid(emptySiteId)).to.equal(false); }); + var xBadCustomData = { bidder: BIDDER_CODE, params: { @@ -1640,9 +1721,11 @@ describe('ozone Adapter', function () { 'customData': 'this aint gonna work' } }; + it('should not validate customData not being an array', function () { expect(spec.isBidRequestValid(xBadCustomData)).to.equal(false); }); + var xBadCustomDataOldCustomdataValue = { bidder: BIDDER_CODE, params: { @@ -1652,9 +1735,11 @@ describe('ozone Adapter', function () { 'customData': {'gender': 'bart', 'age': 'low'} } }; + it('should not validate customData being an object, not an array', function () { expect(spec.isBidRequestValid(xBadCustomDataOldCustomdataValue)).to.equal(false); }); + var xBadCustomDataZerocd = { bidder: BIDDER_CODE, params: { @@ -1664,9 +1749,11 @@ describe('ozone Adapter', function () { 'customData': [] } }; + it('should not validate customData array having no elements', function () { expect(spec.isBidRequestValid(xBadCustomDataZerocd)).to.equal(false); }); + var xBadCustomDataNotargeting = { bidder: BIDDER_CODE, params: { @@ -1679,6 +1766,7 @@ describe('ozone Adapter', function () { it('should not validate customData[] having no "targeting"', function () { expect(spec.isBidRequestValid(xBadCustomDataNotargeting)).to.equal(false); }); + var xBadCustomDataTgtNotObj = { bidder: BIDDER_CODE, params: { @@ -1691,6 +1779,7 @@ describe('ozone Adapter', function () { it('should not validate customData[0].targeting not being an object', function () { expect(spec.isBidRequestValid(xBadCustomDataTgtNotObj)).to.equal(false); }); + var xBadCustomParams = { bidder: BIDDER_CODE, params: { @@ -1715,9 +1804,11 @@ describe('ozone Adapter', function () { mimes: ['video/mp4']} } }; + it('should not validate video without context attribute', function () { expect(spec.isBidRequestValid(xBadVideoContext2)).to.equal(false); }); + let validVideoBidReq = { bidder: BIDDER_CODE, params: { @@ -1731,6 +1822,7 @@ describe('ozone Adapter', function () { 'context': 'outstream'}, } }; + it('should validate video outstream being sent', function () { expect(spec.isBidRequestValid(validVideoBidReq)).to.equal(true); }); @@ -1740,23 +1832,28 @@ describe('ozone Adapter', function () { expect(spec.isBidRequestValid(instreamVid)).to.equal(true); }); }); + describe('buildRequests', function () { beforeEach(function () { config.resetConfig() }); + it('sends bid request to OZONEURI via POST', function () { const request = spec.buildRequests(validBidRequests, validBidderRequest); expect(request.url).to.equal(OZONEURI); expect(request.method).to.equal('POST'); }); + it('sends data as a string', function () { const request = spec.buildRequests(validBidRequests, validBidderRequest); expect(request.data).to.be.a('string'); }); + it('sends all bid parameters', function () { const request = spec.buildRequests(validBidRequests, validBidderRequest); expect(request).to.have.all.keys(['bidderRequest', 'data', 'method', 'url']); }); + it('adds all parameters inside the ext object only', function () { const request = spec.buildRequests(validBidRequests, validBidderRequest); expect(request.data).to.be.a('string'); @@ -1765,6 +1862,7 @@ describe('ozone Adapter', function () { expect(request).not.to.have.key('lotameData'); expect(request).not.to.have.key('customData'); }); + it('adds all parameters inside the ext object only - lightning', function () { let localBidReq = JSON.parse(JSON.stringify(validBidRequests)); const request = spec.buildRequests(localBidReq, validBidderRequest); @@ -1774,6 +1872,7 @@ describe('ozone Adapter', function () { expect(request).not.to.have.key('lotameData'); expect(request).not.to.have.key('customData'); }); + it('ignores ozoneData in & after version 2.1.1', function () { let validBidRequestsWithOzoneData = JSON.parse(JSON.stringify(validBidRequests)); validBidRequestsWithOzoneData[0].params.ozoneData = {'networkID': '3048', 'dfpSiteID': 'd.thesun', 'sectionID': 'homepage', 'path': '/', 'sec_id': 'null', 'sec': 'sec', 'topics': 'null', 'kw': 'null', 'aid': 'null', 'search': 'null', 'article_type': 'null', 'hide_ads': '', 'article_slug': 'null'}; @@ -1785,36 +1884,44 @@ describe('ozone Adapter', function () { expect(request).not.to.have.key('lotameData'); expect(request).not.to.have.key('customData'); }); + it('has correct bidder', function () { const request = spec.buildRequests(validBidRequests, validBidderRequest); expect(request.bidderRequest.bids[0].bidder).to.equal(BIDDER_CODE); }); + it('handles mediaTypes element correctly', function () { const request = spec.buildRequests(validBidRequestsWithBannerMediaType, validBidderRequest); expect(request).to.have.all.keys(['bidderRequest', 'data', 'method', 'url']); }); + it('handles no ozone or custom data', function () { const request = spec.buildRequests(validBidRequestsMinimal, validBidderRequest); expect(request).to.have.all.keys(['bidderRequest', 'data', 'method', 'url']); }); + it('handles video mediaType element correctly, with outstream video', function () { const request = spec.buildRequests(validBidRequests1OutstreamVideo2020, validBidderRequest); expect(request).to.have.all.keys(['bidderRequest', 'data', 'method', 'url']); }); + it('should not crash when there is no sizes element at all', function () { const request = spec.buildRequests(validBidRequestsNoSizes, validBidderRequest); expect(request).to.have.all.keys(['bidderRequest', 'data', 'method', 'url']); }); + it('should be able to handle non-single requests', function () { config.setConfig({'ozone': {'singleRequest': false}}); const request = spec.buildRequests(validBidRequestsNoSizes, validBidderRequest); expect(request).to.be.a('array'); expect(request[0]).to.have.all.keys(['bidderRequest', 'data', 'method', 'url']); + // need to reset the singleRequest config flag: config.setConfig({'ozone': {'singleRequest': true}}); }); + it('should add gdpr consent information to the request when ozone is true', function () { let consentString = 'BOcocyaOcocyaAfEYDENCD-AAAAjx7_______9______9uz_Ov_v_f__33e8__9v_l_7_-___u_-33d4-_1vf99yfm1-7ftr3tp_87ues2_Xur__59__3z3_NphLgA=='; - let bidderRequest = validBidderRequest; + let bidderRequest = JSON.parse(JSON.stringify(validBidderRequest)); bidderRequest.gdprConsent = { consentString: consentString, gdprApplies: true, @@ -1825,14 +1932,17 @@ describe('ozone Adapter', function () { purposeConsents: {1: true, 2: true, 3: true, 4: true, 5: true} } } + const request = spec.buildRequests(validBidRequestsNoSizes, bidderRequest); const payload = JSON.parse(request.data); expect(payload.regs.ext.gdpr).to.equal(1); expect(payload.user.ext.consent).to.equal(consentString); }); + + // mirror it('should add gdpr consent information to the request when vendorData is missing vendorConsents (Mirror)', function () { let consentString = 'BOcocyaOcocyaAfEYDENCD-AAAAjx7_______9______9uz_Ov_v_f__33e8__9v_l_7_-___u_-33d4-_1vf99yfm1-7ftr3tp_87ues2_Xur__59__3z3_NphLgA=='; - let bidderRequest = validBidderRequest; + let bidderRequest = JSON.parse(JSON.stringify(validBidderRequest)); bidderRequest.gdprConsent = { consentString: consentString, gdprApplies: true, @@ -1840,15 +1950,18 @@ describe('ozone Adapter', function () { metadata: consentString, gdprApplies: true } + } + const request = spec.buildRequests(validBidRequestsNoSizes, bidderRequest); const payload = JSON.parse(request.data); expect(payload.regs.ext.gdpr).to.equal(1); expect(payload.user.ext.consent).to.equal(consentString); }); + it('should set regs.ext.gdpr flag to 0 when gdprApplies is false', function () { let consentString = 'BOcocyaOcocyaAfEYDENCD-AAAAjx7_______9______9uz_Ov_v_f__33e8__9v_l_7_-___u_-33d4-_1vf99yfm1-7ftr3tp_87ues2_Xur__59__3z3_NphLgA=='; - let bidderRequest = validBidderRequest; + let bidderRequest = JSON.parse(JSON.stringify(validBidderRequest)); bidderRequest.gdprConsent = { consentString: consentString, gdprApplies: false, @@ -1859,13 +1972,32 @@ describe('ozone Adapter', function () { purposeConsents: {1: true, 2: true, 3: true, 4: true, 5: true} } }; + const request = spec.buildRequests(validBidRequestsNoSizes, bidderRequest); const payload = JSON.parse(request.data); expect(payload.regs.ext.gdpr).to.equal(0); }); + + // see https://docs.prebid.org/dev-docs/modules/consentManagementGpp.html + it('should set gpp and gpp_sid when available', function() { + let gppString = 'gppConsentString'; + let gppSections = [7, 8, 9]; + let bidderRequest = JSON.parse(JSON.stringify(validBidderRequest)); + bidderRequest.ortb2 = {regs: {gpp: gppString, gpp_sid: gppSections}}; + const request = spec.buildRequests(validBidRequestsNoSizes, bidderRequest); + const payload = JSON.parse(request.data); + expect(payload.regs.ext.gpp).to.equal(gppString); + expect(payload.regs.ext.gpp_sid).to.have.same.members(gppSections); + }); + it('should not set gpp and gpp_sid keys when not available', function() { + const request = spec.buildRequests(validBidRequestsNoSizes, validBidderRequest); + const payload = JSON.parse(request.data); + expect(payload).to.not.contain.keys(['gpp', 'gpp_sid', 'ext', 'regs']); + }); + it('should not have imp[N].ext.ozone.userId', function () { let consentString = 'BOcocyaOcocyaAfEYDENCD-AAAAjx7_______9______9uz_Ov_v_f__33e8__9v_l_7_-___u_-33d4-_1vf99yfm1-7ftr3tp_87ues2_Xur__59__3z3_NphLgA=='; - let bidderRequest = validBidderRequest; + let bidderRequest = JSON.parse(JSON.stringify(validBidderRequest)); bidderRequest.gdprConsent = { consentString: consentString, gdprApplies: false, @@ -1876,7 +2008,9 @@ describe('ozone Adapter', function () { purposeConsents: {1: true, 2: true, 3: true, 4: true, 5: true} } }; + let bidRequests = validBidRequests; + // values from http://prebid.org/dev-docs/modules/userId.html#pubcommon-id bidRequests[0]['userId'] = { 'digitrustid': {data: {id: 'DTID', keyv: 4, privacy: {optout: false}, producer: 'ABC', version: 2}}, 'id5id': { uid: '1111', ext: { linkType: 2, abTestingControlGroup: false } }, @@ -1893,13 +2027,16 @@ describe('ozone Adapter', function () { expect(firstBid).to.not.have.property('userId'); delete validBidRequests[0].userId; // tidy up now, else it will screw with other tests }); + it('should pick up the value of pubcid when built using the pubCommonId module (not userId)', function () { let bidRequests = validBidRequests; + // values from http://prebid.org/dev-docs/modules/userId.html#pubcommon-id bidRequests[0]['userId'] = { 'digitrustid': {data: {id: 'DTID', keyv: 4, privacy: {optout: false}, producer: 'ABC', version: 2}}, 'id5id': { uid: '1111', ext: { linkType: 2, abTestingControlGroup: false } }, 'idl_env': '3333', 'parrableid': 'eidVersion.encryptionKeyReference.encryptedValue', + // 'pubcid': '5555', // remove pubcid from here to emulate the OLD module & cause the failover code to kick in 'tdid': '6666', 'sharedid': {'id': '01EAJWWNEPN3CYMM5N8M5VXY22', 'third': '01EAJWWNEPN3CYMM5N8M5VXY22'} }; @@ -1909,8 +2046,18 @@ describe('ozone Adapter', function () { expect(payload.ext.ozone.pubcid).to.equal(bidRequests[0]['crumbs']['pubcid']); delete validBidRequests[0].userId; // tidy up now, else it will screw with other tests }); + it('should add a user.ext.eids object to contain user ID data in the new location (Nov 2019) Updated Aug 2020', function() { const request = spec.buildRequests(validBidRequestsWithUserIdData, validBidderRequest); + /* + 'pubcid': '12345678', + 'tdid': '1111tdid', + 'id5id': { uid: '1111', ext: { linkType: 2, abTestingControlGroup: false } }, + 'criteoId': '1111criteoId', + 'idl_env': 'liverampId', + 'parrableId': {'eid': '01.5678.parrableid'} + */ + const payload = JSON.parse(request.data); expect(payload.user).to.exist; expect(payload.user.ext).to.exist; @@ -1930,6 +2077,7 @@ describe('ozone Adapter', function () { expect(payload.user.ext.eids[6]['source']).to.equal('parrableId'); expect(payload.user.ext.eids[6]['uids'][0]['id']['eid']).to.equal('01.5678.parrableid'); }); + it('replaces the auction url for a config override', function () { spec.propertyBag.whitelabel = null; let fakeOrigin = 'http://sometestendpoint'; @@ -1942,6 +2090,7 @@ describe('ozone Adapter', function () { config.setConfig({'ozone': {'kvpPrefix': null, 'endpointOverride': null}}); spec.propertyBag.whitelabel = null; }); + it('replaces the FULL auction url for a config override', function () { spec.propertyBag.whitelabel = null; let fakeurl = 'http://sometestendpoint/myfullurl'; @@ -1954,6 +2103,7 @@ describe('ozone Adapter', function () { config.setConfig({'ozone': {'kvpPrefix': null, 'endpointOverride': null}}); spec.propertyBag.whitelabel = null; }); + it('replaces the renderer url for a config override', function () { spec.propertyBag.whitelabel = null; let fakeUrl = 'http://renderer.com'; @@ -1984,6 +2134,7 @@ describe('ozone Adapter', function () { expect(result[0]).to.have.own.property('meta'); expect(result[0].meta.advertiserDomains[0]).to.equal('http://prebid.org'); }); + it('replaces the kvp prefix ', function () { spec.propertyBag.whitelabel = null; config.setConfig({'ozone': {'kvpPrefix': 'test'}}); @@ -1993,6 +2144,7 @@ describe('ozone Adapter', function () { config.setConfig({'ozone': {'kvpPrefix': null}}); spec.propertyBag.whitelabel = null; }); + it('handles an alias ', function () { spec.propertyBag.whitelabel = null; config.setConfig({'lmc': {'kvpPrefix': 'test'}}); @@ -2006,6 +2158,7 @@ describe('ozone Adapter', function () { }); it('should use oztestmode GET value if set', function() { var specMock = utils.deepClone(spec); + // mock the getGetParametersAsObject function to simulate GET parameters for oztestmode: specMock.getGetParametersAsObject = function() { return {'oztestmode': 'mytestvalue_123'}; }; @@ -2016,6 +2169,7 @@ describe('ozone Adapter', function () { }); it('should pass through GET params if present: ozf, ozpf, ozrp, ozip', function() { var specMock = utils.deepClone(spec); + // mock the getGetParametersAsObject function to simulate GET parameters : specMock.getGetParametersAsObject = function() { return {ozf: '1', ozpf: '0', ozrp: '2', ozip: '123'}; }; @@ -2028,6 +2182,7 @@ describe('ozone Adapter', function () { }); it('should pass through GET params if present: ozf, ozpf, ozrp, ozip with alternative values', function() { var specMock = utils.deepClone(spec); + // mock the getGetParametersAsObject function to simulate GET parameters : specMock.getGetParametersAsObject = function() { return {ozf: 'false', ozpf: 'true', ozrp: 'xyz', ozip: 'hello'}; }; @@ -2040,6 +2195,7 @@ describe('ozone Adapter', function () { }); it('should use oztestmode GET value if set, even if there is no customdata in config', function() { var specMock = utils.deepClone(spec); + // mock the getGetParametersAsObject function to simulate GET parameters for oztestmode: specMock.getGetParametersAsObject = function() { return {'oztestmode': 'mytestvalue_123'}; }; @@ -2109,6 +2265,7 @@ describe('ozone Adapter', function () { config.resetConfig(); }); it('should use GET values for batchRequests if found', function() { + // mock the getGetParametersAsObject function to simulate GET parameters for oztestmode: var specMock = utils.deepClone(spec); specMock.getGetParametersAsObject = function() { return {'batchRequests': '5'}; @@ -2121,24 +2278,28 @@ describe('ozone Adapter', function () { } let request = specMock.buildRequests(arrReq, validBidderRequest); expect(request.length).to.equal(5); // 5 x 5 = 25 + // test GET 10 specMock = utils.deepClone(spec); specMock.getGetParametersAsObject = function() { return {'batchRequests': '10'}; // the built in function will return '10' (string) }; request = specMock.buildRequests(arrReq, validBidderRequest); expect(request.length).to.equal(3); // 10, 10, 5 + // test GET true specMock = utils.deepClone(spec); specMock.getGetParametersAsObject = function() { return {'batchRequests': true}; }; request = specMock.buildRequests(arrReq, validBidderRequest); expect(request.method).to.equal('POST'); // no batching - GET param must be numeric + // test GET 'true' specMock = utils.deepClone(spec); specMock.getGetParametersAsObject = function() { return {'batchRequests': 'true'}; }; request = specMock.buildRequests(arrReq, validBidderRequest); expect(request.method).to.equal('POST'); // no batching - GET param must be numeric + // test GET -5 specMock = utils.deepClone(spec); specMock.getGetParametersAsObject = function() { return {'batchRequests': -5}; @@ -2146,7 +2307,9 @@ describe('ozone Adapter', function () { request = specMock.buildRequests(arrReq, validBidderRequest); expect(request.method).to.equal('POST'); // no batching }); + it('should use GET values auction=dev & cookiesync=dev if set', function() { + // mock the getGetParametersAsObject function to simulate GET parameters for oztestmode: var specMock = utils.deepClone(spec); specMock.getGetParametersAsObject = function() { return {}; @@ -2156,6 +2319,9 @@ describe('ozone Adapter', function () { expect(url).to.equal('https://elb.the-ozone-project.com/openrtb2/auction'); let cookieUrl = specMock.getCookieSyncUrl(); expect(cookieUrl).to.equal('https://elb.the-ozone-project.com/static/load-cookie.html'); + + // now mock the response from getGetParametersAsObject & do the request again + specMock = utils.deepClone(spec); specMock.getGetParametersAsObject = function() { return {'auction': 'dev', 'cookiesync': 'dev'}; @@ -2167,6 +2333,7 @@ describe('ozone Adapter', function () { expect(cookieUrl).to.equal('https://test.ozpr.net/static/load-cookie.html'); }); it('should use a valid ozstoredrequest GET value if set to override the placementId values, and set oz_rw if we find it', function() { + // mock the getGetParametersAsObject function to simulate GET parameters for ozstoredrequest: var specMock = utils.deepClone(spec); specMock.getGetParametersAsObject = function() { return {'ozstoredrequest': '1122334455'}; // 10 digits are valid @@ -2177,6 +2344,7 @@ describe('ozone Adapter', function () { expect(data.imp[0].ext.prebid.storedrequest.id).to.equal('1122334455'); }); it('should NOT use an invalid ozstoredrequest GET value if set to override the placementId values, and set oz_rw to 0', function() { + // mock the getGetParametersAsObject function to simulate GET parameters for ozstoredrequest: var specMock = utils.deepClone(spec); specMock.getGetParametersAsObject = function() { return {'ozstoredrequest': 'BADVAL'}; // 10 digits are valid @@ -2186,6 +2354,7 @@ describe('ozone Adapter', function () { expect(data.ext.ozone.oz_rw).to.equal(0); expect(data.imp[0].ext.prebid.storedrequest.id).to.equal('1310000099'); }); + it('should pick up the config value of coppa & set it in the request', function () { config.setConfig({'coppa': true}); const request = spec.buildRequests(validBidRequestsNoSizes, validBidderRequest); @@ -2237,8 +2406,10 @@ describe('ozone Adapter', function () { const payload = JSON.parse(request.data); expect(payload.ext.ozone.oz_kvp_rw).to.equal(0); }); + // start of FPD it('should handle ortb2 site data', function () { let bidderRequest = JSON.parse(JSON.stringify(validBidderRequest)); + // this is the new correct way of doing it (at a site-wide level) bidderRequest.ortb2 = { 'site': { 'name': 'example_ortb2_name', @@ -2259,6 +2430,7 @@ describe('ozone Adapter', function () { }); it('should add ortb2 site data when there is no customData already created', function () { let bidderRequest = JSON.parse(JSON.stringify(validBidderRequest)); + // this is the new correct way of doing it (at a site-wide level) bidderRequest.ortb2 = { 'site': { 'name': 'example_ortb2_name', @@ -2279,6 +2451,7 @@ describe('ozone Adapter', function () { }); it('should add ortb2 user data to the user object', function () { let bidderRequest = JSON.parse(JSON.stringify(validBidderRequest)); + // this is the new correct way of doing it (at a site-wide level) bidderRequest.ortb2 = { 'user': { 'gender': 'I identify as a box of rocks' @@ -2290,6 +2463,7 @@ describe('ozone Adapter', function () { }); it('should not override the user.ext.consent string even if this is set in config ortb2', function () { let bidderRequest = JSON.parse(JSON.stringify(bidderRequestWithFullGdpr)); + // this is the new correct way of doing it (at a site-wide level) bidderRequest.ortb2 = { 'user': { 'ext': { @@ -2303,6 +2477,7 @@ describe('ozone Adapter', function () { expect(payload.user.ext.consent2).to.equal('this should be set'); expect(payload.user.ext.consent).to.equal('BOh7mtYOh7mtYAcABBENCU-AAAAncgPIXJiiAoao0PxBFkgCAC8ACIAAQAQQAAIAAAIAAAhBGAAAQAQAEQgAAAAAAABAAAAAAAAAAAAAAACAAAAAAAACgAAAAABAAAAQAAAAAAA'); }); + // end of FPD... it('should have openrtb video params', function() { let allowed = ['mimes', 'minduration', 'maxduration', 'protocols', 'w', 'h', 'startdelay', 'placement', 'linearity', 'skip', 'skipmin', 'skipafter', 'sequence', 'battr', 'maxextended', 'minbitrate', 'maxbitrate', 'boxingallowed', 'playbackmethod', 'playbackend', 'delivery', 'pos', 'companionad', 'api', 'companiontype', 'ext']; const request = spec.buildRequests(validBidRequests1OutstreamVideo2020, validBidderRequest); @@ -2340,8 +2515,10 @@ describe('ozone Adapter', function () { expect(utils.deepAccess(payload, 'imp.0.floor.banner.currency')).to.equal('USD'); expect(utils.deepAccess(payload, 'imp.0.floor.banner.floor')).to.equal(0.8); }); + it('handles schain object in each bidrequest (will be the same in each br)', function () { let br = JSON.parse(JSON.stringify(validBidRequests)); + // I only need to inject this into one of the bidrequests - it will get picked up in the br loop let schainConfigObject = { 'ver': '1.0', 'complete': 1, @@ -2360,15 +2537,18 @@ describe('ozone Adapter', function () { expect(data.source.ext.schain).to.deep.equal(schainConfigObject); // .deep.equal() : Target object deeply (but not strictly) equals `{a: 1}` }); }); + describe('interpretResponse', function () { beforeEach(function () { config.resetConfig() }) + it('should build bid array', function () { const request = spec.buildRequests(validBidRequests, validBidderRequest); const result = spec.interpretResponse(validResponse, request); expect(result.length).to.equal(1); }); + it('should have all relevant fields', function () { const request = spec.buildRequests(validBidRequests, validBidderRequest); const result = spec.interpretResponse(validResponse, request); @@ -2377,6 +2557,7 @@ describe('ozone Adapter', function () { expect(bid.width).to.equal(validResponse.body.seatbid[0].bid[0].width); expect(bid.height).to.equal(validResponse.body.seatbid[0].bid[0].height); }); + it('should build bid array with gdpr', function () { let validBR = JSON.parse(JSON.stringify(bidderRequestWithFullGdpr)); validBR.gdprConsent = {'gdprApplies': 1, 'consentString': 'This is the gdpr consent string'}; @@ -2392,6 +2573,7 @@ describe('ozone Adapter', function () { expect(payload.user.ext.uspConsent).not.to.exist; expect(payload.regs.ext.us_privacy).to.equal('1YNY'); }); + it('should build bid array with only partial gdpr', function () { var validBidderRequestWithGdpr = bidderRequestWithPartialGdpr.bidderRequest; validBidderRequestWithGdpr.gdprConsent = {'gdprApplies': 1, 'consentString': 'This is the gdpr consent string'}; @@ -2399,22 +2581,26 @@ describe('ozone Adapter', function () { const payload = JSON.parse(request.data); expect(payload.user.ext.consent).to.be.a('string'); }); + it('should fail ok if no seatbid in server response', function () { const result = spec.interpretResponse({}, {}); expect(result).to.be.an('array'); expect(result).to.be.empty; }); + it('should fail ok if seatbid is not an array', function () { const result = spec.interpretResponse({'body': {'seatbid': 'nothing_here'}}, {}); expect(result).to.be.an('array'); expect(result).to.be.empty; }); + it('should have video renderer for outstream video', function () { const request = spec.buildRequests(validBidRequests1OutstreamVideo2020, validBidderRequest1OutstreamVideo2020.bidderRequest); const result = spec.interpretResponse(getCleanValidVideoResponse(), validBidderRequest1OutstreamVideo2020); const bid = result[0]; expect(bid.renderer).to.be.an.instanceOf(Renderer); }); + it('should have NO video renderer for instream video', function () { let instreamRequestsObj = JSON.parse(JSON.stringify(validBidRequests1OutstreamVideo2020)); instreamRequestsObj[0].mediaTypes.video.context = 'instream'; @@ -2425,16 +2611,19 @@ describe('ozone Adapter', function () { const bid = result[0]; expect(bid.hasOwnProperty('renderer')).to.be.false; }); + it('should correctly parse response where there are more bidders than ad slots', function () { const request = spec.buildRequests(validBidRequests, validBidderRequest); const result = spec.interpretResponse(validBidResponse1adWith2Bidders, request); expect(result.length).to.equal(2); }); + it('should have a ttl of 600', function () { const request = spec.buildRequests(validBidRequests, validBidderRequest); const result = spec.interpretResponse(validResponse, request); expect(result[0].ttl).to.equal(300); }); + it('should handle oz_omp_floor_dollars correctly, inserting 1 as necessary', function () { config.setConfig({'ozone': {'oz_omp_floor': 0.01}}); const request = spec.buildRequests(validBidRequests, validBidderRequest); @@ -2549,6 +2738,7 @@ describe('ozone Adapter', function () { expect(result[1]['impid']).to.equal('3025f169863b7f8'); expect(result[1]['id']).to.equal('18552976939844999'); expect(result[1]['adserverTargeting']['oz_ozappnexus_adId']).to.equal('3025f169863b7f8-0-oz-2'); + // change the bid values so a different second bid for an impid by the same bidder gets dropped validres = JSON.parse(JSON.stringify(multiResponse1)); validres.body.seatbid[0].bid[1].price = 1.1; validres.body.seatbid[0].bid[1].cpm = 1.1; @@ -2574,6 +2764,7 @@ describe('ozone Adapter', function () { expect(bid.mediaType).to.equal('video'); }); }); + describe('userSyncs', function () { it('should fail gracefully if no server response', function () { const result = spec.getUserSyncs('bad', false, gdpr1); @@ -2584,6 +2775,7 @@ describe('ozone Adapter', function () { expect(result).to.be.empty; }); it('should append the various values if they exist', function() { + // get the cookie bag populated spec.buildRequests(validBidRequests, validBidderRequest); const result = spec.getUserSyncs({iframeEnabled: true}, 'good server response', gdpr1); expect(result).to.be.an('array'); @@ -2593,18 +2785,25 @@ describe('ozone Adapter', function () { expect(result[0].url).to.include('gdpr_consent=BOh7mtYOh7mtYAcABBENCU-AAAAncgPIXJiiAoao0PxBFkgCAC8ACIAAQAQQAAIAAAIAAAhBGAAAQAQAEQgAAAAAAABAAAAAAAAAAAAAAACAAAAAAAACgAAAAABAAAAQAAAAAAA'); }); it('should append ccpa (usp data)', function() { + // get the cookie bag populated spec.buildRequests(validBidRequests, validBidderRequest); const result = spec.getUserSyncs({iframeEnabled: true}, 'good server response', gdpr1, '1YYN'); expect(result).to.be.an('array'); expect(result[0].url).to.include('usp_consent=1YYN'); }); it('should use "" if no usp is sent to cookieSync', function() { + // get the cookie bag populated spec.buildRequests(validBidRequests, validBidderRequest); const result = spec.getUserSyncs({iframeEnabled: true}, 'good server response', gdpr1); expect(result).to.be.an('array'); expect(result[0].url).to.include('usp_consent=&'); }); + it('should add gpp if its present', function () { + const result = spec.getUserSyncs({iframeEnabled: true}, 'good server response', gdpr1, '1---', { gppString: 'gppStringHere', applicableSections: [7, 8, 9] }); + expect(result[0].url).to.include('gpp=gppStringHere&gpp_sid=7,8,9'); + }); }); + describe('video object utils', function () { it('should find width & height from video object', function () { let obj = {'playerSize': [640, 480], 'mimes': ['video/mp4'], 'context': 'outstream'}; @@ -2667,6 +2866,7 @@ describe('ozone Adapter', function () { expect(utils.deepAccess(result[1].adserverTargeting, 'oz_appnexus_dealid', '')).to.equal(''); }); }); + describe('default size', function () { it('should should return default sizes if no obj is sent', function () { let obj = ''; @@ -2675,6 +2875,7 @@ describe('ozone Adapter', function () { expect(result.defaultWidth).to.equal(300); }); }); + describe('getGranularityKeyName', function() { it('should return a string granularity as-is', function() { const result = getGranularityKeyName('', 'this is it', ''); @@ -2689,6 +2890,7 @@ describe('ozone Adapter', function () { expect(result).to.equal('string buckets'); }); }); + describe('getGranularityObject', function() { it('should return an object as-is', function() { const result = getGranularityObject('', {'name': 'mark'}, '', ''); @@ -2699,10 +2901,12 @@ describe('ozone Adapter', function () { expect(result.name).to.equal('rupert'); }); }); + describe('blockTheRequest', function() { beforeEach(function () { config.resetConfig() }) + it('should return true if oz_request is false', function() { config.setConfig({'ozone': {'oz_request': false}}); let result = spec.blockTheRequest(); @@ -2817,10 +3021,15 @@ describe('ozone Adapter', function () { expect(response[1].bid.length).to.equal(2); }); }); + /** + * spec.getWhitelabelConfigItem test - get a config value for a whitelabelled bidder, + * from a standard ozone.oz_xxxx_yyy string + */ describe('getWhitelabelConfigItem', function() { beforeEach(function () { config.resetConfig() }) + it('should fetch the whitelabelled equivalent config value correctly', function () { var specMock = utils.deepClone(spec); config.setConfig({'ozone': {'oz_omp_floor': 'ozone-floor-value'}}); @@ -2832,6 +3041,7 @@ describe('ozone Adapter', function () { specMock.propertyBag.whitelabel = {bidder: 'markbidder', keyPrefix: 'mb'}; let markbidder_config = specMock.getWhitelabelConfigItem(testKey); expect(markbidder_config).to.equal('markbidder-floor-value'); + // second test for non-ozone without an oz_ config.setConfig({'markbidder': {'singleRequest': 'markbidder-singlerequest-value'}}); let testKey2 = 'ozone.singleRequest'; let markbidder_config2 = specMock.getWhitelabelConfigItem(testKey2);