From 2bc2197220b91066fc5613a7c3e5204a84dac173 Mon Sep 17 00:00:00 2001 From: Leonard Labat Date: Mon, 8 Jul 2019 14:28:06 +0200 Subject: [PATCH 1/8] assign adapter version --- modules/criteoBidAdapter.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/criteoBidAdapter.js b/modules/criteoBidAdapter.js index 0507ba428be..7362a0c808e 100644 --- a/modules/criteoBidAdapter.js +++ b/modules/criteoBidAdapter.js @@ -7,7 +7,7 @@ import JSEncrypt from 'jsencrypt/bin/jsencrypt'; import sha256 from 'crypto-js/sha256'; import { config } from '../src/config'; -const ADAPTER_VERSION = 17; +const ADAPTER_VERSION = 19; const BIDDER_CODE = 'criteo'; const CDB_ENDPOINT = '//bidder.criteo.com/cdb'; const CRITEO_VENDOR_ID = 91; From 098cc16a6f14bd88267efbc39a9da1fa6dbeb4c1 Mon Sep 17 00:00:00 2001 From: Leonard Labat Date: Tue, 9 Jul 2019 13:56:01 +0200 Subject: [PATCH 2/8] Mapped video parameter from prebid.js to cdb --- modules/criteoBidAdapter.js | 91 +++++++- test/spec/modules/criteoBidAdapter_spec.js | 231 ++++++++++++++++++++- 2 files changed, 316 insertions(+), 6 deletions(-) diff --git a/modules/criteoBidAdapter.js b/modules/criteoBidAdapter.js index 7362a0c808e..323d8b5fd42 100644 --- a/modules/criteoBidAdapter.js +++ b/modules/criteoBidAdapter.js @@ -1,11 +1,12 @@ import { loadExternalScript } from '../src/adloader'; import { registerBidder } from '../src/adapters/bidderFactory'; +import { config } from '../src/config'; +import { BANNER, VIDEO } from '../src/mediaTypes'; import { parse } from '../src/url'; import * as utils from '../src/utils'; import find from 'core-js/library/fn/array/find'; import JSEncrypt from 'jsencrypt/bin/jsencrypt'; import sha256 from 'crypto-js/sha256'; -import { config } from '../src/config'; const ADAPTER_VERSION = 19; const BIDDER_CODE = 'criteo'; @@ -30,14 +31,25 @@ OmOSj0/qnYTAYCu0cR5LiyWG79KlIgUyMbp92ulGg24gAyGrVn4+v/4c53WlOEUp /** @type {BidderSpec} */ export const spec = { code: BIDDER_CODE, + supportedMediaTypes: [ BANNER, VIDEO ], /** * @param {object} bid * @return {boolean} */ - isBidRequestValid: bid => ( - !!(bid && bid.params && (bid.params.zoneId || bid.params.networkId)) - ), + isBidRequestValid: (bid) => { + // either one of zoneId or networkId should be set + if (!(bid && bid.params && (bid.params.zoneId || bid.params.networkId))) { + return false; + } + + // video media types requires some mandatory params + if (hasVideoMediaType(bid) && (!hasValidVideoMediaType(bid) || !hasValidVideoParams(bid))) { + return false; + } + + return true; + }, /** * @param {BidRequest[]} bidRequests @@ -112,6 +124,9 @@ export const spec = { } if (slot.native) { bid.ad = createNativeAd(bidId, slot.native, bidRequest.params.nativeCallback); + } else if (slot.video) { + bid.vastUrl = slot.creative; + bid.mediaType = VIDEO; } else { bid.ad = slot.creative; } @@ -225,7 +240,7 @@ function buildCdbRequest(context, bidRequests, bidderRequest) { impid: bidRequest.adUnitCode, transactionid: bidRequest.transactionId, auctionId: bidRequest.auctionId, - sizes: bidRequest.sizes.map(size => size[0] + 'x' + size[1]), + sizes: getBannerSizes(bidRequest), }; if (bidRequest.params.zoneId) { slot.zoneid = bidRequest.params.zoneId; @@ -236,6 +251,23 @@ function buildCdbRequest(context, bidRequests, bidderRequest) { if (bidRequest.params.nativeCallback) { slot.native = true; } + if (hasVideoMediaType(bidRequest)) { + const video = { + playerSizes: getVideoSizes(bidRequest), + mimes: bidRequest.mediaTypes.video.mimes, + protocols: bidRequest.mediaTypes.video.protocols, + maxduration: bidRequest.mediaTypes.video.maxduration, + api: bidRequest.mediaTypes.video.api + } + + video.skip = bidRequest.params.video.skip; + video.placement = bidRequest.params.video.placement; + video.minduration = bidRequest.params.video.minduration; + video.playbackmethod = bidRequest.params.video.playbackmethod; + video.startdelay = bidRequest.params.video.startdelay; + + slot.video = video; + } return slot; }), }; @@ -262,6 +294,55 @@ function buildCdbRequest(context, bidRequests, bidderRequest) { return request; } +function getVideoSizes(bidRequest) { + return parseSizes(utils.deepAccess(bidRequest, 'mediaTypes.video.playerSize')); +} + +function getBannerSizes(bidRequest) { + return parseSizes(utils.deepAccess(bidRequest, 'mediaTypes.banner.sizes') || bidRequest.sizes); +} + +function parseSizes(sizes) { + return sizes.map(size => size[0] + 'x' + size[1]); +} + +function hasVideoMediaType(bidRequest) { + if (typeof utils.deepAccess(bidRequest, 'params.video') !== 'object') { + return false; + } + return (typeof utils.deepAccess(bidRequest, `mediaTypes.${VIDEO}`) !== 'undefined'); +} + +function hasValidVideoMediaType(bidRequest) { + let isValid = true; + + var requiredParams = ['mimes', 'playerSize', 'maxduration', 'protocols', 'api']; + + requiredParams.forEach(function(param) { + if (utils.deepAccess(bidRequest, `mediaTypes.${VIDEO}.` + param) === undefined) { + isValid = false; + utils.logError('Criteo Bid Adapter: mediaTypes.video.' + param + ' is required'); + } + }); + + return isValid; +} + +function hasValidVideoParams(bidRequest) { + let isValid = true; + + var requiredParams = ['skip', 'placement', 'playbackmethod']; + + requiredParams.forEach(function(param) { + if (utils.deepAccess(bidRequest, 'params.video.' + param) === undefined) { + isValid = false; + utils.logError('Criteo Bid Adapter: params.video.' + param + ' is required'); + } + }); + + return isValid; +} + /** * @param {string} id * @param {*} payload diff --git a/test/spec/modules/criteoBidAdapter_spec.js b/test/spec/modules/criteoBidAdapter_spec.js index ac9ae53af07..d1071736a8f 100755 --- a/test/spec/modules/criteoBidAdapter_spec.js +++ b/test/spec/modules/criteoBidAdapter_spec.js @@ -53,6 +53,191 @@ describe('The Criteo bidding adapter', function () { const isValid = spec.isBidRequestValid(bid); expect(isValid).to.equal(true); }); + + it('should return true when given a valid video bid request', function () { + expect(spec.isBidRequestValid({ + bidder: 'criteo', + mediaTypes: { + video: { + mimes: ['video/mpeg'], + playerSize: [640, 480], + protocols: [5, 6], + maxduration: 30, + api: [1, 2] + } + }, + params: { + networkId: 456, + video: { + skip: 1, + placement: 1, + playbackmethod: 1 + } + }, + })).to.equal(true); + }); + + it('should return false when given an invalid video bid request', function () { + expect(spec.isBidRequestValid({ + bidder: 'criteo', + mediaTypes: { + video: { + playerSize: [640, 480], + protocols: [5, 6], + maxduration: 30, + api: [1, 2] + } + }, + params: { + networkId: 456, + video: { + skip: 1, + placement: 1, + playbackmethod: 1 + } + }, + })).to.equal(false); + + expect(spec.isBidRequestValid({ + bidder: 'criteo', + mediaTypes: { + video: { + mimes: ['video/mpeg'], + protocols: [5, 6], + maxduration: 30, + api: [1, 2] + } + }, + params: { + networkId: 456, + video: { + skip: 1, + placement: 1, + playbackmethod: 1 + } + }, + })).to.equal(false); + + expect(spec.isBidRequestValid({ + bidder: 'criteo', + mediaTypes: { + video: { + mimes: ['video/mpeg'], + playerSize: [640, 480], + maxduration: 30, + api: [1, 2] + } + }, + params: { + networkId: 456, + video: { + skip: 1, + placement: 1, + playbackmethod: 1 + } + }, + })).to.equal(false); + + expect(spec.isBidRequestValid({ + bidder: 'criteo', + mediaTypes: { + video: { + mimes: ['video/mpeg'], + playerSize: [640, 480], + protocols: [5, 6], + api: [1, 2] + } + }, + params: { + networkId: 456, + video: { + skip: 1, + placement: 1, + playbackmethod: 1 + } + }, + })).to.equal(false); + + expect(spec.isBidRequestValid({ + bidder: 'criteo', + mediaTypes: { + video: { + mimes: ['video/mpeg'], + playerSize: [640, 480], + protocols: [5, 6], + maxduration: 30 + } + }, + params: { + networkId: 456, + video: { + skip: 1, + placement: 1, + playbackmethod: 1 + } + }, + })).to.equal(false); + + expect(spec.isBidRequestValid({ + bidder: 'criteo', + mediaTypes: { + video: { + mimes: ['video/mpeg'], + playerSize: [640, 480], + protocols: [5, 6], + maxduration: 30, + api: [1, 2] + } + }, + params: { + networkId: 456, + video: { + placement: 1, + playbackmethod: 1 + } + }, + })).to.equal(false); + + expect(spec.isBidRequestValid({ + bidder: 'criteo', + mediaTypes: { + video: { + mimes: ['video/mpeg'], + playerSize: [640, 480], + protocols: [5, 6], + maxduration: 30, + api: [1, 2] + } + }, + params: { + networkId: 456, + video: { + skip: 1, + playbackmethod: 1 + } + }, + })).to.equal(false); + + expect(spec.isBidRequestValid({ + bidder: 'criteo', + mediaTypes: { + video: { + mimes: ['video/mpeg'], + playerSize: [640, 480], + protocols: [5, 6], + maxduration: 30, + api: [1, 2] + } + }, + params: { + networkId: 456, + video: { + skip: 1, + placement: 1 + } + }, + })).to.equal(false); + }); }); describe('buildRequests', function () { @@ -118,7 +303,11 @@ describe('The Criteo bidding adapter', function () { bidder: 'criteo', adUnitCode: 'bid-123', transactionId: 'transaction-123', - sizes: [[300, 250], [728, 90]], + mediaTypes: { + banner: { + sizes: [[300, 250], [728, 90]] + } + }, params: { networkId: 456, }, @@ -205,6 +394,46 @@ describe('The Criteo bidding adapter', function () { expect(ortbRequest.gdprConsent.consentGiven).to.equal(undefined); }); + it('should properly build a video request', function () { + const bidRequests = [ + { + bidder: 'criteo', + adUnitCode: 'bid-123', + transactionId: 'transaction-123', + sizes: [[728, 90]], + mediaTypes: { + video: { + playerSize: [[640, 480]], + mimes: ['video/mp4', 'video/x-flv'], + maxduration: 30, + api: [1, 2], + protocols: [2, 3] + } + }, + params: { + zoneId: 123, + video: { + skip: 1, + minduration: 5, + startdelay: 5, + playbackmethod: [1, 3], + placement: 2 + } + }, + }, + ]; + const request = spec.buildRequests(bidRequests, bidderRequest); + expect(request.url).to.match(/^\/\/bidder\.criteo\.com\/cdb\?profileId=207&av=\d+&wv=[^&]+&cb=\d/); + expect(request.method).to.equal('POST'); + const ortbRequest = request.data; + expect(ortbRequest.slots[0].video.skip).to.equal(1); + expect(ortbRequest.slots[0].video.minduration).to.equal(5); + expect(ortbRequest.slots[0].video.startdelay).to.equal(5); + expect(ortbRequest.slots[0].video.playerSizes).to.deep.equal(['640x480']); + expect(ortbRequest.slots[0].video.playbackmethod).to.deep.equal([1, 3]); + expect(ortbRequest.slots[0].video.placement).to.equal(2); + }); + it('should properly build a request with ceh', function () { const bidRequests = [ { From 65517374f75b9cc7824a9f2e01d9d66c0fa6f646 Mon Sep 17 00:00:00 2001 From: Leonard Labat Date: Tue, 9 Jul 2019 13:56:01 +0200 Subject: [PATCH 3/8] Mapped video parameter from prebid.js to cdb --- test/spec/modules/criteoBidAdapter_spec.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/test/spec/modules/criteoBidAdapter_spec.js b/test/spec/modules/criteoBidAdapter_spec.js index d1071736a8f..a80540badc4 100755 --- a/test/spec/modules/criteoBidAdapter_spec.js +++ b/test/spec/modules/criteoBidAdapter_spec.js @@ -426,10 +426,13 @@ describe('The Criteo bidding adapter', function () { expect(request.url).to.match(/^\/\/bidder\.criteo\.com\/cdb\?profileId=207&av=\d+&wv=[^&]+&cb=\d/); expect(request.method).to.equal('POST'); const ortbRequest = request.data; + expect(ortbRequest.slots[0].video.mimes).to.deep.equal(['video/mp4', 'video/x-flv']); + expect(ortbRequest.slots[0].video.maxduration).to.equal(30); + expect(ortbRequest.slots[0].video.api).to.deep.equal([1, 2]); + expect(ortbRequest.slots[0].video.protocols).to.deep.equal([2, 3]); expect(ortbRequest.slots[0].video.skip).to.equal(1); expect(ortbRequest.slots[0].video.minduration).to.equal(5); expect(ortbRequest.slots[0].video.startdelay).to.equal(5); - expect(ortbRequest.slots[0].video.playerSizes).to.deep.equal(['640x480']); expect(ortbRequest.slots[0].video.playbackmethod).to.deep.equal([1, 3]); expect(ortbRequest.slots[0].video.placement).to.equal(2); }); From b74ace50d984e4e06a94d34d81190dab1071b103 Mon Sep 17 00:00:00 2001 From: Leonard Labat Date: Fri, 19 Jul 2019 10:47:29 +0200 Subject: [PATCH 4/8] Ensure that context is consistent with placement and that we do not support longform --- modules/criteoBidAdapter.js | 33 +++--- test/spec/modules/criteoBidAdapter_spec.js | 118 +++++++++++++++++++++ 2 files changed, 137 insertions(+), 14 deletions(-) diff --git a/modules/criteoBidAdapter.js b/modules/criteoBidAdapter.js index 323d8b5fd42..d72abcf972e 100644 --- a/modules/criteoBidAdapter.js +++ b/modules/criteoBidAdapter.js @@ -44,8 +44,10 @@ export const spec = { } // video media types requires some mandatory params - if (hasVideoMediaType(bid) && (!hasValidVideoMediaType(bid) || !hasValidVideoParams(bid))) { - return false; + if (hasVideoMediaType(bid)) { + if (!hasValidVideoMediaType(bid)) { + return false; + } } return true; @@ -307,30 +309,24 @@ function parseSizes(sizes) { } function hasVideoMediaType(bidRequest) { - if (typeof utils.deepAccess(bidRequest, 'params.video') !== 'object') { + if (utils.deepAccess(bidRequest, 'params.video') === undefined) { return false; } - return (typeof utils.deepAccess(bidRequest, `mediaTypes.${VIDEO}`) !== 'undefined'); + return utils.deepAccess(bidRequest, 'mediaTypes.video') !== undefined; } function hasValidVideoMediaType(bidRequest) { let isValid = true; - var requiredParams = ['mimes', 'playerSize', 'maxduration', 'protocols', 'api']; + var requiredMediaTypesParams = ['mimes', 'playerSize', 'maxduration', 'protocols', 'api']; - requiredParams.forEach(function(param) { - if (utils.deepAccess(bidRequest, `mediaTypes.${VIDEO}.` + param) === undefined) { + requiredMediaTypesParams.forEach(function(param) { + if (utils.deepAccess(bidRequest, 'mediaTypes.video.' + param) === undefined) { isValid = false; utils.logError('Criteo Bid Adapter: mediaTypes.video.' + param + ' is required'); } }); - return isValid; -} - -function hasValidVideoParams(bidRequest) { - let isValid = true; - var requiredParams = ['skip', 'placement', 'playbackmethod']; requiredParams.forEach(function(param) { @@ -340,7 +336,16 @@ function hasValidVideoParams(bidRequest) { } }); - return isValid; + if (isValid) { + // We do not support long form for now, also we have to check that context & placement are consistent + if (bidRequest.mediaTypes.video.context == 'instream' && bidRequest.params.video.placement === 1) { + return true; + } else if (bidRequest.mediaTypes.video.context == 'outstream' && bidRequest.params.video.placement !== 1) { + return true; + } + } + + return false; } /** diff --git a/test/spec/modules/criteoBidAdapter_spec.js b/test/spec/modules/criteoBidAdapter_spec.js index a80540badc4..e2a9e2bfe71 100755 --- a/test/spec/modules/criteoBidAdapter_spec.js +++ b/test/spec/modules/criteoBidAdapter_spec.js @@ -59,6 +59,7 @@ describe('The Criteo bidding adapter', function () { bidder: 'criteo', mediaTypes: { video: { + context: 'instream', mimes: ['video/mpeg'], playerSize: [640, 480], protocols: [5, 6], @@ -75,6 +76,28 @@ describe('The Criteo bidding adapter', function () { } }, })).to.equal(true); + + expect(spec.isBidRequestValid({ + bidder: 'criteo', + mediaTypes: { + video: { + context: 'outstream', + mimes: ['video/mpeg'], + playerSize: [640, 480], + protocols: [5, 6], + maxduration: 30, + api: [1, 2] + } + }, + params: { + networkId: 456, + video: { + skip: 1, + placement: 2, + playbackmethod: 1 + } + }, + })).to.equal(true); }); it('should return false when given an invalid video bid request', function () { @@ -82,6 +105,94 @@ describe('The Criteo bidding adapter', function () { bidder: 'criteo', mediaTypes: { video: { + mimes: ['video/mpeg'], + playerSize: [640, 480], + protocols: [5, 6], + maxduration: 30, + api: [1, 2] + } + }, + params: { + networkId: 456, + video: { + skip: 1, + placement: 1, + playbackmethod: 1 + } + }, + })).to.equal(false); + + expect(spec.isBidRequestValid({ + bidder: 'criteo', + mediaTypes: { + video: { + context: 'instream', + mimes: ['video/mpeg'], + playerSize: [640, 480], + protocols: [5, 6], + maxduration: 30, + api: [1, 2] + } + }, + params: { + networkId: 456, + video: { + skip: 1, + placement: 2, + playbackmethod: 1 + } + }, + })).to.equal(false); + + expect(spec.isBidRequestValid({ + bidder: 'criteo', + mediaTypes: { + video: { + context: 'outstream', + mimes: ['video/mpeg'], + playerSize: [640, 480], + protocols: [5, 6], + maxduration: 30, + api: [1, 2] + } + }, + params: { + networkId: 456, + video: { + skip: 1, + placement: 1, + playbackmethod: 1 + } + }, + })).to.equal(false); + + expect(spec.isBidRequestValid({ + bidder: 'criteo', + mediaTypes: { + video: { + context: 'adpod', + mimes: ['video/mpeg'], + playerSize: [640, 480], + protocols: [5, 6], + maxduration: 30, + api: [1, 2] + } + }, + params: { + networkId: 456, + video: { + skip: 1, + placement: 1, + playbackmethod: 1 + } + }, + })).to.equal(false); + + expect(spec.isBidRequestValid({ + bidder: 'criteo', + mediaTypes: { + video: { + context: 'instream', playerSize: [640, 480], protocols: [5, 6], maxduration: 30, @@ -102,6 +213,7 @@ describe('The Criteo bidding adapter', function () { bidder: 'criteo', mediaTypes: { video: { + context: 'instream', mimes: ['video/mpeg'], protocols: [5, 6], maxduration: 30, @@ -122,6 +234,7 @@ describe('The Criteo bidding adapter', function () { bidder: 'criteo', mediaTypes: { video: { + context: 'instream', mimes: ['video/mpeg'], playerSize: [640, 480], maxduration: 30, @@ -142,6 +255,7 @@ describe('The Criteo bidding adapter', function () { bidder: 'criteo', mediaTypes: { video: { + context: 'instream', mimes: ['video/mpeg'], playerSize: [640, 480], protocols: [5, 6], @@ -162,6 +276,7 @@ describe('The Criteo bidding adapter', function () { bidder: 'criteo', mediaTypes: { video: { + context: 'instream', mimes: ['video/mpeg'], playerSize: [640, 480], protocols: [5, 6], @@ -182,6 +297,7 @@ describe('The Criteo bidding adapter', function () { bidder: 'criteo', mediaTypes: { video: { + context: 'instream', mimes: ['video/mpeg'], playerSize: [640, 480], protocols: [5, 6], @@ -202,6 +318,7 @@ describe('The Criteo bidding adapter', function () { bidder: 'criteo', mediaTypes: { video: { + context: 'instream', mimes: ['video/mpeg'], playerSize: [640, 480], protocols: [5, 6], @@ -222,6 +339,7 @@ describe('The Criteo bidding adapter', function () { bidder: 'criteo', mediaTypes: { video: { + context: 'instream', mimes: ['video/mpeg'], playerSize: [640, 480], protocols: [5, 6], From 8a919796d3103607f2cc732049cbf2df91912baa Mon Sep 17 00:00:00 2001 From: Leonard Labat Date: Fri, 19 Jul 2019 10:55:52 +0200 Subject: [PATCH 5/8] updated playersize property name --- modules/criteoBidAdapter.js | 2 +- test/spec/modules/criteoBidAdapter_spec.js | 35 ++++++++++++++++++++++ 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/modules/criteoBidAdapter.js b/modules/criteoBidAdapter.js index d72abcf972e..0106061128d 100644 --- a/modules/criteoBidAdapter.js +++ b/modules/criteoBidAdapter.js @@ -255,7 +255,7 @@ function buildCdbRequest(context, bidRequests, bidderRequest) { } if (hasVideoMediaType(bidRequest)) { const video = { - playerSizes: getVideoSizes(bidRequest), + playersize: getVideoSizes(bidRequest), mimes: bidRequest.mediaTypes.video.mimes, protocols: bidRequest.mediaTypes.video.protocols, maxduration: bidRequest.mediaTypes.video.maxduration, diff --git a/test/spec/modules/criteoBidAdapter_spec.js b/test/spec/modules/criteoBidAdapter_spec.js index e2a9e2bfe71..24fd0e99c50 100755 --- a/test/spec/modules/criteoBidAdapter_spec.js +++ b/test/spec/modules/criteoBidAdapter_spec.js @@ -4,6 +4,7 @@ import { createBid } from 'src/bidfactory'; import CONSTANTS from 'src/constants.json'; import * as utils from 'src/utils'; import { config } from '../../../src/config'; +import { VIDEO } from '../../../src/mediaTypes'; describe('The Criteo bidding adapter', function () { beforeEach(function () { @@ -545,6 +546,7 @@ describe('The Criteo bidding adapter', function () { expect(request.method).to.equal('POST'); const ortbRequest = request.data; expect(ortbRequest.slots[0].video.mimes).to.deep.equal(['video/mp4', 'video/x-flv']); + expect(ortbRequest.slots[0].video.playersize).to.deep.equal(['640x480']); expect(ortbRequest.slots[0].video.maxduration).to.equal(30); expect(ortbRequest.slots[0].video.api).to.deep.equal([1, 2]); expect(ortbRequest.slots[0].video.protocols).to.deep.equal([2, 3]); @@ -649,6 +651,39 @@ describe('The Criteo bidding adapter', function () { expect(bids[0].height).to.equal(90); }); + it('should properly parse a bid responsewith with a video', function () { + const response = { + body: { + slots: [{ + impid: 'test-requestId', + bidId: 'abc123', + cpm: 1.23, + creative: 'test-ad', + width: 728, + height: 90, + zoneid: 123, + video: true + }], + }, + }; + const request = { + bidRequests: [{ + adUnitCode: 'test-requestId', + bidId: 'test-bidId', + params: { + zoneId: 123, + }, + }] + }; + const bids = spec.interpretResponse(response, request); + expect(bids).to.have.lengthOf(1); + expect(bids[0].requestId).to.equal('test-bidId'); + expect(bids[0].adId).to.equal('abc123'); + expect(bids[0].cpm).to.equal(1.23); + expect(bids[0].vastUrl).to.equal('test-ad'); + expect(bids[0].mediaType).to.equal(VIDEO); + }); + it('should properly parse a bid responsewith with a zoneId passed as a string', function () { const response = { body: { From f268ad6fbbd2a0c5bfe459eb9bd2eb55bcb8728b Mon Sep 17 00:00:00 2001 From: Leonard Labat Date: Fri, 19 Jul 2019 11:27:31 +0200 Subject: [PATCH 6/8] fixed size parsing to be able to handle single player size as well as several --- modules/criteoBidAdapter.js | 10 ++++- test/spec/modules/criteoBidAdapter_spec.js | 46 +++++++++++++++++++++- 2 files changed, 54 insertions(+), 2 deletions(-) diff --git a/modules/criteoBidAdapter.js b/modules/criteoBidAdapter.js index 0106061128d..c3a02af2e36 100644 --- a/modules/criteoBidAdapter.js +++ b/modules/criteoBidAdapter.js @@ -304,8 +304,16 @@ function getBannerSizes(bidRequest) { return parseSizes(utils.deepAccess(bidRequest, 'mediaTypes.banner.sizes') || bidRequest.sizes); } +function parseSize(size) { + return size[0] + 'x' + size[1]; +} + function parseSizes(sizes) { - return sizes.map(size => size[0] + 'x' + size[1]); + if (Array.isArray(sizes[0])) { // is there several sizes ? (ie. [[728,90],[200,300]]) + return sizes.map(size => parseSize(size)); + } + + return [parseSize(sizes)]; // or a single one ? (ie. [728,90]) } function hasVideoMediaType(bidRequest) { diff --git a/test/spec/modules/criteoBidAdapter_spec.js b/test/spec/modules/criteoBidAdapter_spec.js index 24fd0e99c50..3289330fb2d 100755 --- a/test/spec/modules/criteoBidAdapter_spec.js +++ b/test/spec/modules/criteoBidAdapter_spec.js @@ -522,7 +522,7 @@ describe('The Criteo bidding adapter', function () { sizes: [[728, 90]], mediaTypes: { video: { - playerSize: [[640, 480]], + playerSize: [640, 480], mimes: ['video/mp4', 'video/x-flv'], maxduration: 30, api: [1, 2], @@ -557,6 +557,50 @@ describe('The Criteo bidding adapter', function () { expect(ortbRequest.slots[0].video.placement).to.equal(2); }); + it('should properly build a video request with more than one player size', function () { + const bidRequests = [ + { + bidder: 'criteo', + adUnitCode: 'bid-123', + transactionId: 'transaction-123', + sizes: [[728, 90]], + mediaTypes: { + video: { + playerSize: [[640, 480], [800, 600]], + mimes: ['video/mp4', 'video/x-flv'], + maxduration: 30, + api: [1, 2], + protocols: [2, 3] + } + }, + params: { + zoneId: 123, + video: { + skip: 1, + minduration: 5, + startdelay: 5, + playbackmethod: [1, 3], + placement: 2 + } + }, + }, + ]; + const request = spec.buildRequests(bidRequests, bidderRequest); + expect(request.url).to.match(/^\/\/bidder\.criteo\.com\/cdb\?profileId=207&av=\d+&wv=[^&]+&cb=\d/); + expect(request.method).to.equal('POST'); + const ortbRequest = request.data; + expect(ortbRequest.slots[0].video.mimes).to.deep.equal(['video/mp4', 'video/x-flv']); + expect(ortbRequest.slots[0].video.playersize).to.deep.equal(['640x480', '800x600']); + expect(ortbRequest.slots[0].video.maxduration).to.equal(30); + expect(ortbRequest.slots[0].video.api).to.deep.equal([1, 2]); + expect(ortbRequest.slots[0].video.protocols).to.deep.equal([2, 3]); + expect(ortbRequest.slots[0].video.skip).to.equal(1); + expect(ortbRequest.slots[0].video.minduration).to.equal(5); + expect(ortbRequest.slots[0].video.startdelay).to.equal(5); + expect(ortbRequest.slots[0].video.playbackmethod).to.deep.equal([1, 3]); + expect(ortbRequest.slots[0].video.placement).to.equal(2); + }); + it('should properly build a request with ceh', function () { const bidRequests = [ { From 99abb85b45502949928d551fe5c39cc3a3efe968 Mon Sep 17 00:00:00 2001 From: Leonard Labat Date: Fri, 19 Jul 2019 12:27:45 +0200 Subject: [PATCH 7/8] Changed playersize to plural playersizes in CDB contract --- modules/criteoBidAdapter.js | 2 +- test/spec/modules/criteoBidAdapter_spec.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/criteoBidAdapter.js b/modules/criteoBidAdapter.js index c3a02af2e36..d289744111d 100644 --- a/modules/criteoBidAdapter.js +++ b/modules/criteoBidAdapter.js @@ -255,7 +255,7 @@ function buildCdbRequest(context, bidRequests, bidderRequest) { } if (hasVideoMediaType(bidRequest)) { const video = { - playersize: getVideoSizes(bidRequest), + playersizes: getVideoSizes(bidRequest), mimes: bidRequest.mediaTypes.video.mimes, protocols: bidRequest.mediaTypes.video.protocols, maxduration: bidRequest.mediaTypes.video.maxduration, diff --git a/test/spec/modules/criteoBidAdapter_spec.js b/test/spec/modules/criteoBidAdapter_spec.js index 3289330fb2d..76b2a188687 100755 --- a/test/spec/modules/criteoBidAdapter_spec.js +++ b/test/spec/modules/criteoBidAdapter_spec.js @@ -546,7 +546,7 @@ describe('The Criteo bidding adapter', function () { expect(request.method).to.equal('POST'); const ortbRequest = request.data; expect(ortbRequest.slots[0].video.mimes).to.deep.equal(['video/mp4', 'video/x-flv']); - expect(ortbRequest.slots[0].video.playersize).to.deep.equal(['640x480']); + expect(ortbRequest.slots[0].video.playersizes).to.deep.equal(['640x480']); expect(ortbRequest.slots[0].video.maxduration).to.equal(30); expect(ortbRequest.slots[0].video.api).to.deep.equal([1, 2]); expect(ortbRequest.slots[0].video.protocols).to.deep.equal([2, 3]); @@ -590,7 +590,7 @@ describe('The Criteo bidding adapter', function () { expect(request.method).to.equal('POST'); const ortbRequest = request.data; expect(ortbRequest.slots[0].video.mimes).to.deep.equal(['video/mp4', 'video/x-flv']); - expect(ortbRequest.slots[0].video.playersize).to.deep.equal(['640x480', '800x600']); + expect(ortbRequest.slots[0].video.playersizes).to.deep.equal(['640x480', '800x600']); expect(ortbRequest.slots[0].video.maxduration).to.equal(30); expect(ortbRequest.slots[0].video.api).to.deep.equal([1, 2]); expect(ortbRequest.slots[0].video.protocols).to.deep.equal([2, 3]); From 1e8068d3262f4da019cbb6f454d5e2a13d918bf9 Mon Sep 17 00:00:00 2001 From: Leonard Labat Date: Fri, 26 Jul 2019 14:17:34 +0200 Subject: [PATCH 8/8] Use displayurl instead of creative as we want to fetch the direct url vast cache instead a vast wrapper --- modules/criteoBidAdapter.js | 2 +- test/spec/modules/criteoBidAdapter_spec.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/criteoBidAdapter.js b/modules/criteoBidAdapter.js index d289744111d..56e22e45017 100644 --- a/modules/criteoBidAdapter.js +++ b/modules/criteoBidAdapter.js @@ -127,7 +127,7 @@ export const spec = { if (slot.native) { bid.ad = createNativeAd(bidId, slot.native, bidRequest.params.nativeCallback); } else if (slot.video) { - bid.vastUrl = slot.creative; + bid.vastUrl = slot.displayurl; bid.mediaType = VIDEO; } else { bid.ad = slot.creative; diff --git a/test/spec/modules/criteoBidAdapter_spec.js b/test/spec/modules/criteoBidAdapter_spec.js index 76b2a188687..4fe60bba17c 100755 --- a/test/spec/modules/criteoBidAdapter_spec.js +++ b/test/spec/modules/criteoBidAdapter_spec.js @@ -702,7 +702,7 @@ describe('The Criteo bidding adapter', function () { impid: 'test-requestId', bidId: 'abc123', cpm: 1.23, - creative: 'test-ad', + displayurl: 'http://test-ad', width: 728, height: 90, zoneid: 123, @@ -724,7 +724,7 @@ describe('The Criteo bidding adapter', function () { expect(bids[0].requestId).to.equal('test-bidId'); expect(bids[0].adId).to.equal('abc123'); expect(bids[0].cpm).to.equal(1.23); - expect(bids[0].vastUrl).to.equal('test-ad'); + expect(bids[0].vastUrl).to.equal('http://test-ad'); expect(bids[0].mediaType).to.equal(VIDEO); });