diff --git a/modules/lkqdBidAdapter.js b/modules/lkqdBidAdapter.js index a39abb320b2..8c10b5b0269 100644 --- a/modules/lkqdBidAdapter.js +++ b/modules/lkqdBidAdapter.js @@ -36,21 +36,30 @@ function buildRequests(validBidRequests, bidderRequest) { for (let i = 0; i < validBidRequests.length; i++) { let bidRequest = validBidRequests[i]; + let sizes = []; // if width/height not provided to the ad unit for some reason then attempt request with default 640x480 size - if (!bidRequest.sizes || !bidRequest.sizes.length) { + let bidRequestSizes = bidRequest.sizes; + let bidRequestDeepSizes = utils.deepAccess(bidRequest, 'mediaTypes.video.playerSize'); + if ((!bidRequestSizes || !bidRequestSizes.length) && (!bidRequestDeepSizes || !bidRequestDeepSizes.length)) { utils.logWarn('Warning: Could not find valid width/height parameters on the provided adUnit'); - bidRequest.sizes = [[640, 480]]; + sizes = [[640, 480]]; } // JWPlayer demo page uses sizes: [640,480] instead of sizes: [[640,480]] so need to handle single-layer array as well as nested arrays - if (bidRequest.sizes.length === 2 && typeof bidRequest.sizes[0] === 'number' && typeof bidRequest.sizes[1] === 'number') { - let adWidth = bidRequest.sizes[0]; - let adHeight = bidRequest.sizes[1]; - bidRequest.sizes = [[adWidth, adHeight]]; + if (bidRequestSizes && bidRequestSizes.length > 0) { + sizes = bidRequestSizes; + if (bidRequestSizes.length === 2 && typeof bidRequestSizes[0] === 'number' && typeof bidRequestSizes[1] === 'number') { + sizes = [bidRequestSizes]; + } + } else if (bidRequestDeepSizes && bidRequestDeepSizes.length > 0) { + sizes = bidRequestDeepSizes; + if (bidRequestDeepSizes.length === 2 && typeof bidRequestDeepSizes[0] === 'number' && typeof bidRequestDeepSizes[1] === 'number') { + sizes = [bidRequestDeepSizes]; + } } - for (let j = 0; j < bidRequest.sizes.length; j++) { - let size = bidRequest.sizes[j]; + for (let j = 0; j < sizes.length; j++) { + let size = sizes[j]; let playerWidth; let playerHeight; if (size && size.length == 2) { @@ -127,6 +136,9 @@ function buildRequests(validBidRequests, bidderRequest) { if (bidRequest.params.hasOwnProperty('flrmp') && bidRequest.params.flrmp != null) { sspData.flrmp = bidRequest.params.flrmp; } + if (bidRequest.params.hasOwnProperty('schain') && bidRequest.params.schain != null) { + sspData.schain = bidRequest.params.schain; + } if (bidRequest.params.hasOwnProperty('placement') && bidRequest.params.placement != null) { sspData.placement = bidRequest.params.placement; } @@ -139,7 +151,7 @@ function buildRequests(validBidRequests, bidderRequest) { if (bidRequest.params.hasOwnProperty('pageurl') && bidRequest.params.pageurl != null) { sspData.pageurl = bidRequest.params.pageurl; } else if (bidderRequest && bidderRequest.refererInfo) { - sspData.pageurl = encodeURIComponent(bidderRequest.refererInfo.referer); + sspData.pageurl = encodeURIComponent(encodeURIComponent(bidderRequest.refererInfo.referer)); } if (bidRequest.params.hasOwnProperty('contentId') && bidRequest.params.contentId != null) { sspData.contentid = bidRequest.params.contentId; @@ -153,6 +165,9 @@ function buildRequests(validBidRequests, bidderRequest) { if (bidRequest.params.hasOwnProperty('contentUrl') && bidRequest.params.contentUrl != null) { sspData.contenturl = bidRequest.params.contentUrl; } + if (bidRequest.params.hasOwnProperty('schain') && bidRequest.params.schain) { + sspData.schain = bidRequest.params.schain; + } // random number to prevent caching sspData.rnd = Math.floor(Math.random() * 999999999); @@ -165,7 +180,7 @@ function buildRequests(validBidRequests, bidderRequest) { bidRequests.push({ method: 'GET', url: sspUrl, - data: sspData + data: Object.keys(sspData).map(function (key) { return key + '=' + sspData[key] }).join('&') + '&' }); } } @@ -182,29 +197,57 @@ function interpretResponse(serverResponse, bidRequest) { } else { try { let bidResponse = {}; - if (bidRequest && bidRequest.data && bidRequest.data.bidId && bidRequest.data.bidId !== '') { - let sspXmlString = serverResponse.body; - let sspXml = new window.DOMParser().parseFromString(sspXmlString, 'text/xml'); - if (sspXml && sspXml.getElementsByTagName('parsererror').length == 0) { - let sspUrl = bidRequest.url.concat(); - - bidResponse.requestId = bidRequest.data.bidId; - bidResponse.bidderCode = BIDDER_CODE; - bidResponse.ad = ''; - bidResponse.cpm = parseFloat(sspXml.getElementsByTagName('Pricing')[0].textContent); - bidResponse.width = bidRequest.data.bidWidth; - bidResponse.height = bidRequest.data.bidHeight; - bidResponse.ttl = BID_TTL_DEFAULT; - bidResponse.creativeId = sspXml.getElementsByTagName('Ad')[0].getAttribute('id'); - bidResponse.currency = sspXml.getElementsByTagName('Pricing')[0].getAttribute('currency'); - bidResponse.netRevenue = true; - bidResponse.vastUrl = sspUrl; - bidResponse.vastXml = sspXmlString; - bidResponse.mediaType = VIDEO; - - bidResponses.push(bidResponse); + if (bidRequest && bidRequest.data && typeof bidRequest.data === 'string') { + let sspData; + let sspBidId; + let sspBidWidth; + let sspBidHeight; + if (window.URLSearchParams) { + sspData = new URLSearchParams(bidRequest.data); + sspBidId = sspData.get('bidId'); + sspBidWidth = sspData.get('bidWidth'); + sspBidHeight = sspData.get('bidHeight'); + } else { + if (bidRequest.data.indexOf('bidId=') >= 0) { + sspBidId = bidRequest.data.substr(bidRequest.data.indexOf('bidId=') + 6, bidRequest.data.length); + sspBidId = sspBidId.split('&')[0]; + } + if (bidRequest.data.indexOf('bidWidth=') >= 0) { + sspBidWidth = bidRequest.data.substr(bidRequest.data.indexOf('bidWidth=') + 9, bidRequest.data.length); + sspBidWidth = sspBidWidth.split('&')[0]; + } + if (bidRequest.data.indexOf('bidHeight=') >= 0) { + sspBidHeight = bidRequest.data.substr(bidRequest.data.indexOf('bidHeight=') + 10, bidRequest.data.length); + sspBidHeight = sspBidHeight.split('&')[0]; + } + } + + if (sspBidId) { + let sspXmlString = serverResponse.body; + let sspXml = new window.DOMParser().parseFromString(sspXmlString, 'text/xml'); + if (sspXml && sspXml.getElementsByTagName('parsererror').length == 0) { + let sspUrl = bidRequest.url.concat(); + + bidResponse.requestId = sspBidId; + bidResponse.bidderCode = BIDDER_CODE; + bidResponse.ad = ''; + bidResponse.cpm = parseFloat(sspXml.getElementsByTagName('Pricing')[0].textContent); + bidResponse.width = sspBidWidth; + bidResponse.height = sspBidHeight; + bidResponse.ttl = BID_TTL_DEFAULT; + bidResponse.creativeId = sspXml.getElementsByTagName('Ad')[0].getAttribute('id'); + bidResponse.currency = sspXml.getElementsByTagName('Pricing')[0].getAttribute('currency'); + bidResponse.netRevenue = true; + bidResponse.vastUrl = sspUrl; + bidResponse.vastXml = sspXmlString; + bidResponse.mediaType = VIDEO; + + bidResponses.push(bidResponse); + } else { + utils.logError('Error: Server response contained invalid XML'); + } } else { - utils.logError('Error: Server response contained invalid XML'); + utils.logError('Error: Could not associate bid request to server response'); } } else { utils.logError('Error: Could not associate bid request to server response'); diff --git a/modules/lkqdBidAdapter.md b/modules/lkqdBidAdapter.md index 2ea2ef95b4b..1bd57ced4e0 100644 --- a/modules/lkqdBidAdapter.md +++ b/modules/lkqdBidAdapter.md @@ -19,10 +19,12 @@ For more information about [LKQD Ad Serving and Management](http://www.lkqd.com/ var videoAdUnit = [ { code: 'video1', - sizes: [ - [300, 250], - [640, 480] - ], + mediaTypes: { + video: { + context: "instream", + playerSize: [640, 480] + } + }, bids: [{ bidder: 'lkqd', params: { diff --git a/test/spec/modules/lkqdBidAdapter_spec.js b/test/spec/modules/lkqdBidAdapter_spec.js index 1c7f55d4242..e43ff9b2667 100644 --- a/test/spec/modules/lkqdBidAdapter_spec.js +++ b/test/spec/modules/lkqdBidAdapter_spec.js @@ -2,16 +2,16 @@ import { spec } from 'modules/lkqdBidAdapter'; import { newBidder } from 'src/adapters/bidderFactory'; const { expect } = require('chai'); -describe('LKQD Bid Adapter Test', function () { +describe('LKQD Bid Adapter Test', () => { const adapter = newBidder(spec); - describe('inherited functions', function () { - it('exists and is a function', function () { + describe('inherited functions', () => { + it('exists and is a function', () => { expect(adapter.callBids).to.exist.and.to.be.a('function'); }); }); - describe('isBidRequestValid', function () { + describe('isBidRequestValid', () => { let bid = { 'bidder': 'lkqd', 'params': { @@ -26,11 +26,11 @@ describe('LKQD Bid Adapter Test', function () { 'transactionId': 'd6f6b392-54a9-454c-85fb-a2fd882c4a2d', }; - it('should return true when required params found', function () { + it('should return true when required params found', () => { expect(spec.isBidRequestValid(bid)).to.equal(true); }); - it('should return false when required params are not passed', function () { + it('should return false when required params are not passed', () => { let bid = Object.assign({}, bid); delete bid.params; bid.params = { @@ -62,7 +62,8 @@ describe('LKQD Bid Adapter Test', function () { 'bidder': 'lkqd', 'params': { 'siteId': '662921', - 'placementId': '263' + 'placementId': '263', + 'schain': '1.0,1!exchange1.com,1234%21abcd,1,bid-request-1,publisher%2c%20Inc.,publisher.com' }, 'adUnitCode': 'lkqd', 'sizes': [640, 480], @@ -73,61 +74,52 @@ describe('LKQD Bid Adapter Test', function () { } ]; - it('should populate available parameters', function () { + it('should populate available parameters', () => { const requests = spec.buildRequests(bidRequests); expect(requests.length).to.equal(2); const r1 = requests[0].data; - expect(r1).to.have.property('pid'); - expect(r1.pid).to.equal('263'); - expect(r1).to.have.property('sid'); - expect(r1.sid).to.equal('662921'); - expect(r1).to.have.property('width'); - expect(r1.width).to.equal(300); - expect(r1).to.have.property('height'); - expect(r1.height).to.equal(250); + expect(r1).to.have.string('pid=263&'); + expect(r1).to.have.string('&sid=662921&'); + expect(r1).to.have.string('&width=300&'); + expect(r1).to.have.string('&height=250&'); const r2 = requests[1].data; - expect(r2).to.have.property('pid'); - expect(r2.pid).to.equal('263'); - expect(r2).to.have.property('sid'); - expect(r2.sid).to.equal('662921'); - expect(r2).to.have.property('width'); - expect(r2.width).to.equal(640); - expect(r2).to.have.property('height'); - expect(r2.height).to.equal(480); + expect(r2).to.have.string('pid=263&'); + expect(r2).to.have.string('&sid=662921&'); + expect(r2).to.have.string('&width=640&'); + expect(r2).to.have.string('&height=480&'); }); - it('should not populate unspecified parameters', function () { + it('should not populate unspecified parameters', () => { const requests = spec.buildRequests(bidRequests); expect(requests.length).to.equal(2); const r1 = requests[0].data; - expect(r1).to.not.have.property('dnt'); - expect(r1).to.not.have.property('contentid'); - expect(r1).to.not.have.property('contenttitle'); - expect(r1).to.not.have.property('contentlength'); - expect(r1).to.not.have.property('contenturl'); + expect(r1).to.not.have.string('&dnt='); + expect(r1).to.not.have.string('&contentid='); + expect(r1).to.not.have.string('&contenttitle='); + expect(r1).to.not.have.string('&contentlength='); + expect(r1).to.not.have.string('&contenturl='); + expect(r1).to.not.have.string('&schain='); const r2 = requests[1].data; - expect(r2).to.not.have.property('dnt'); - expect(r2).to.not.have.property('contentid'); - expect(r2).to.not.have.property('contenttitle'); - expect(r2).to.not.have.property('contentlength'); - expect(r2).to.not.have.property('contenturl'); + expect(r2).to.not.have.string('&dnt='); + expect(r2).to.not.have.string('&contentid='); + expect(r2).to.not.have.string('&contenttitle='); + expect(r2).to.not.have.string('&contentlength='); + expect(r2).to.not.have.string('&contenturl='); + expect(r2).to.not.have.string('&schain='); }); - it('should handle single size request', function () { + it('should handle single size request', () => { const requests = spec.buildRequests(bidRequest); expect(requests.length).to.equal(1); const r1 = requests[0].data; - expect(r1).to.have.property('pid'); - expect(r1.pid).to.equal('263'); - expect(r1).to.have.property('sid'); - expect(r1.sid).to.equal('662921'); - expect(r1).to.have.property('width'); - expect(r1.width).to.equal(640); - expect(r1).to.have.property('height'); - expect(r1.height).to.equal(480); + expect(r1).to.have.string('pid=263&'); + expect(r1).to.have.string('&sid=662921&'); + expect(r1).to.have.string('&width=640&'); + expect(r1).to.have.string('&height=480&'); + expect(r1).to.have.string('&schain=1.0,1!exchange1.com,1234%21abcd,1,bid-request-1,publisher%2c%20Inc.,publisher.com&'); }); - it('sends bid request to ENDPOINT via GET', function () { + it('sends bid request to ENDPOINT via GET', () => { const requests = spec.buildRequests(bidRequests); expect(requests.length).to.equal(2); const r1 = requests[0]; @@ -139,14 +131,10 @@ describe('LKQD Bid Adapter Test', function () { }); }); - describe('interpretResponse', function () { + describe('interpretResponse', () => { let bidRequest = { 'url': 'https://ssp.lkqd.net/ad?pid=263&sid=662921&output=vast&execution=any&placement=&playinit=auto&volume=100&timeout=&width=300%E2%80%8C&height=250&pbt=[PREBID_TOKEN]%E2%80%8C&dnt=[DO_NOT_TRACK]%E2%80%8C&pageurl=[PAGEURL]%E2%80%8C&contentid=[CONTENT_ID]%E2%80%8C&contenttitle=[CONTENT_TITLE]%E2%80%8C&contentlength=[CONTENT_LENGTH]%E2%80%8C&contenturl=[CONTENT_URL]&prebid=true%E2%80%8C&rnd=874313435?bidId=253dcb69fb2577&bidWidth=300&bidHeight=250&', - 'data': { - 'bidId': '253dcb69fb2577', - 'bidWidth': '640', - 'bidHeight': '480' - } + 'data': 'pid=263&sid=662921&prebid=true&output=vast&execution=any&support=html5&playinit=auto&volume=100&width=640&height=480&rnd=89811791&bidId=20d2f9095ba4e3&bidWidth=640&bidHeight=480&' }; let serverResponse = {}; serverResponse.body = ` @@ -320,12 +308,12 @@ https://creative.lkqd.net/internal/lkqd_300x250.mp4 `; - it('should correctly parse valid bid response', function () { + it('should correctly parse valid bid response', () => { const BIDDER_CODE = 'lkqd'; let bidResponses = spec.interpretResponse(serverResponse, bidRequest); expect(bidResponses.length).to.equal(1); let bidResponse = bidResponses[0]; - expect(bidResponse.requestId).to.equal(bidRequest.data.bidId); + expect(bidResponse.requestId).to.equal('20d2f9095ba4e3'); expect(bidResponse.bidderCode).to.equal(BIDDER_CODE); expect(bidResponse.ad).to.equal(''); expect(bidResponse.cpm).to.equal(2.87); @@ -338,7 +326,7 @@ https://creative.lkqd.net/internal/lkqd_300x250.mp4 expect(bidResponse.mediaType).to.equal('video'); }); - it('safely handles XML parsing failure from invalid bid response', function () { + it('safely handles XML parsing failure from invalid bid response', () => { let invalidServerResponse = {}; invalidServerResponse.body = ''; @@ -346,7 +334,7 @@ https://creative.lkqd.net/internal/lkqd_300x250.mp4 expect(result.length).to.equal(0); }); - it('handles nobid responses', function () { + it('handles nobid responses', () => { let nobidResponse = {}; nobidResponse.body = '';