diff --git a/modules/tpmnBidAdapter.js b/modules/tpmnBidAdapter.js index 8130d7db032..9df8fa0bb49 100644 --- a/modules/tpmnBidAdapter.js +++ b/modules/tpmnBidAdapter.js @@ -14,25 +14,7 @@ const SUPPORTED_AD_TYPES = [BANNER, VIDEO]; // const BIDDER_ENDPOINT_URL = 'http://localhost:8081/ortb/pbjs_bidder'; const BIDDER_ENDPOINT_URL = 'https://gat.tpmn.io/ortb/pbjs_bidder'; const IFRAMESYNC = 'https://gat.tpmn.io/sync/iframe'; -const VIDEO_ORTB_PARAMS = [ - 'mimes', - 'minduration', - 'maxduration', - 'placement', - 'protocols', - 'startdelay', - 'skip', - 'skipafter', - 'minbitrate', - 'maxbitrate', - 'delivery', - 'playbackmethod', - 'api', - 'linearity', - 'battr', - 'plcmt' -]; -const BANNER_ORTB_PARAMS = [ +const COMMON_PARAMS = [ 'battr' ]; @@ -80,18 +62,22 @@ function isValidVideoRequest(bid) { } function buildRequests(validBidRequests, bidderRequest) { - if (validBidRequests.length === 0 || !bidderRequest) return []; - let bannerBids = validBidRequests.filter(bid => utils.deepAccess(bid, 'mediaTypes.banner')); - let videoBids = validBidRequests.filter(bid => utils.deepAccess(bid, 'mediaTypes.video')); let requests = []; + try { + if (validBidRequests.length === 0 || !bidderRequest) return []; + let bannerBids = validBidRequests.filter(bid => utils.deepAccess(bid, 'mediaTypes.banner')); + let videoBids = validBidRequests.filter(bid => utils.deepAccess(bid, 'mediaTypes.video')); - bannerBids.forEach(bid => { - requests.push(createRequest([bid], bidderRequest, BANNER)); - }); + bannerBids.forEach(bid => { + requests.push(createRequest([bid], bidderRequest, BANNER)); + }); - videoBids.forEach(bid => { - requests.push(createRequest([bid], bidderRequest, VIDEO)); - }); + videoBids.forEach(bid => { + requests.push(createRequest([bid], bidderRequest, VIDEO)); + }); + } catch (err) { + utils.logWarn('buildRequests', err); + } return requests; } @@ -100,19 +86,7 @@ function createRequest(bidRequests, bidderRequest, mediaType) { const rtbData = CONVERTER.toORTB({ bidRequests, bidderRequest, context: { mediaType } }) const bid = bidRequests.find((b) => b.params.inventoryId) - // console.log('createRequest : ', mediaType, bid); - - if (!rtbData.site) rtbData.site = {} - rtbData.site = createSite(bidderRequest.refererInfo) - if (bidderRequest.gdprConsent) { - if (!rtbData.user) rtbData.user = {}; - if (!rtbData.user.ext) rtbData.user.ext = {}; - if (!rtbData.regs) rtbData.regs = {}; - if (!rtbData.regs.ext) rtbData.regs.ext = {}; - rtbData.user.ext.consent = bidderRequest.gdprConsent.consentString; - rtbData.regs.ext.gdpr = bidderRequest.gdprConsent.gdprApplies ? 1 : 0; - } if (bid.params.inventoryId) rtbData.ext = {}; if (bid.params.inventoryId) rtbData.ext.inventoryId = bid.params.inventoryId @@ -145,7 +119,7 @@ function interpretResponse(response, request) { registerBidder(spec); -const CONVERTER = ortbConverter({ +export const CONVERTER = ortbConverter({ context: { netRevenue: true, ttl: DEFAULT_BID_TTL, @@ -153,16 +127,16 @@ const CONVERTER = ortbConverter({ }, imp(buildImp, bidRequest, context) { let imp = buildImp(bidRequest, context); - imp.secure = Number(window.location.protocol === 'https:'); if (!imp.bidfloor && bidRequest.params.bidFloor) { imp.bidfloor = bidRequest.params.bidFloor; } - if (bidRequest.mediaTypes[VIDEO]) { - imp = buildVideoImp(bidRequest, imp); - } else if (bidRequest.mediaTypes[BANNER]) { - imp = buildBannerImp(bidRequest, imp); - } - + [VIDEO, BANNER].forEach(namespace => { + COMMON_PARAMS.forEach(param => { + if (bidRequest.params.hasOwnProperty(param)) { + utils.deepSetValue(imp, `${namespace}.${param}`, bidRequest.params[param]) + } + }) + }) return imp; }, bidResponse(buildBidResponse, bid, context) { @@ -183,6 +157,18 @@ const CONVERTER = ortbConverter({ } } return bidResponse; + }, + overrides: { + imp: { + video(orig, imp, bidRequest, context) { + let videoParams = bidRequest.mediaTypes[VIDEO]; + if (videoParams) { + videoParams = Object.assign({}, videoParams, bidRequest.params.video); + bidRequest = {...bidRequest, mediaTypes: {[VIDEO]: videoParams}} + } + orig(imp, bidRequest, context); + }, + }, } }); @@ -220,81 +206,6 @@ function handleOutstreamRendererEvents(bid, id, eventName) { bid.renderer.handleVideoEvent({ id, eventName }); } -/** - * Creates site description object - */ -function createSite(refInfo) { - let url = utils.parseUrl(refInfo.page || ''); - let site = { - 'domain': url.hostname, - 'page': url.protocol + '://' + url.hostname + url.pathname - }; - - if (refInfo.ref) { - site.ref = refInfo.ref - } - let keywords = document.getElementsByTagName('meta')['keywords']; - if (keywords && keywords.content) { - site.keywords = keywords.content; - } - return site; -} - -function buildVideoImp(bidRequest, imp) { - const videoAdUnitParams = utils.deepAccess(bidRequest, `mediaTypes.${VIDEO}`, {}); - const videoBidderParams = utils.deepAccess(bidRequest, `params.${VIDEO}`, {}); - - const videoParams = { ...videoAdUnitParams, ...videoBidderParams }; - - const videoSizes = (videoAdUnitParams && videoAdUnitParams.playerSize) || []; - - if (videoSizes && videoSizes.length > 0) { - utils.deepSetValue(imp, 'video.w', videoSizes[0][0]); - utils.deepSetValue(imp, 'video.h', videoSizes[0][1]); - } - - VIDEO_ORTB_PARAMS.forEach((param) => { - if (videoParams.hasOwnProperty(param)) { - utils.deepSetValue(imp, `video.${param}`, videoParams[param]); - } - }); - - if (imp.video && videoParams?.context === 'instream') { - imp.video.placement = imp.video.placement || 1; - imp.video.plcmt = imp.video.plcmt || 1; - imp.video.playbackmethod = imp.video.playbackmethod || [1]; - } - if (imp.video && videoParams?.context === 'outstream') { - imp.video.placement = imp.video.placement || 4; - imp.video.plcmt = imp.video.plcmt || 4; - imp.video.playbackmethod = imp.video.playbackmethod || [2]; - } - - return { ...imp }; -} - -function buildBannerImp(bidRequest, imp) { - const bannerAdUnitParams = utils.deepAccess(bidRequest, `mediaTypes.${BANNER}`, {}); - const bannerBidderParams = utils.deepAccess(bidRequest, `params.${BANNER}`, {}); - - const bannerParams = { ...bannerAdUnitParams, ...bannerBidderParams }; - - let sizes = bidRequest.mediaTypes.banner.sizes; - - if (sizes) { - utils.deepSetValue(imp, 'banner.w', sizes[0][0]); - utils.deepSetValue(imp, 'banner.h', sizes[0][1]); - } - - BANNER_ORTB_PARAMS.forEach((param) => { - if (bannerParams.hasOwnProperty(param)) { - utils.deepSetValue(imp, `banner.${param}`, bannerParams[param]); - } - }); - - return { ...imp }; -} - function getUserSyncs(syncOptions, serverResponses, gdprConsent, uspConsent) { const syncArr = []; if (syncOptions.iframeEnabled) { diff --git a/test/spec/modules/tpmnBidAdapter_spec.js b/test/spec/modules/tpmnBidAdapter_spec.js index a896aff775b..c9994353a30 100644 --- a/test/spec/modules/tpmnBidAdapter_spec.js +++ b/test/spec/modules/tpmnBidAdapter_spec.js @@ -4,6 +4,9 @@ import { generateUUID } from '../../../src/utils.js'; import { expect } from 'chai'; import * as utils from 'src/utils'; import * as sinon from 'sinon'; +import 'modules/consentManagement.js'; +import {syncAddFPDToBidderRequest} from '../../helpers/fpd.js'; +import {mockGdprConsent} from '../../helpers/consentData.js'; const BIDDER_CODE = 'tpmn'; const BANNER_BID = { @@ -172,12 +175,12 @@ describe('tpmnAdapterTests', function () { it('should have gdpr data if applicable', function () { const bid = utils.deepClone(BANNER_BID); - const req = Object.assign({}, BIDDER_REQUEST, { + const req = syncAddFPDToBidderRequest(Object.assign({}, BIDDER_REQUEST, { gdprConsent: { consentString: 'consentString', gdprApplies: true, } - }); + })); let request = spec.buildRequests([bid], req)[0]; const payload = request.data; @@ -188,7 +191,7 @@ describe('tpmnAdapterTests', function () { it('should properly forward ORTB blocking params', function () { let bid = utils.deepClone(BANNER_BID); bid = utils.mergeDeep(bid, { - params: { bcat: ['IAB1-1'], badv: ['example.com'], bapp: ['com.example'] }, + params: { bcat: ['IAB1-1'], badv: ['example.com'], bapp: ['com.example'], battr: [1] }, mediaTypes: { banner: { battr: [1] } } }); @@ -208,9 +211,9 @@ describe('tpmnAdapterTests', function () { const [request] = spec.buildRequests([bid], BIDDER_REQUEST); const requestData = request.data; - - expect(requestData.imp[0].banner.w).to.equal(300); - expect(requestData.imp[0].banner.h).to.equal(250); + // expect(requestData.imp[0].banner).to.equal(null); + expect(requestData.imp[0].banner.format[0].w).to.equal(300); + expect(requestData.imp[0].banner.format[0].h).to.equal(250); }); it('should create request data', function () { @@ -238,35 +241,111 @@ describe('tpmnAdapterTests', function () { expect(spec.isBidRequestValid(bid)).to.equal(false); }); - it('should use bidder video params if they are set', () => { - const videoBidWithParams = utils.deepClone(VIDEO_BID); - const bidderVideoParams = { - api: [1, 2], - mimes: ['video/mp4', 'video/x-flv'], - playbackmethod: [3, 4], - protocols: [5, 6], + it('when mediaType is Video - check', () => { + const bid = utils.deepClone(VIDEO_BID); + const check = { + w: 1024, + h: 768, + mimes: ['video/mp4'], + playbackmethod: [2, 4, 6], + api: [1, 2, 4, 6], + protocols: [3, 4, 7, 8, 10], placement: 1, - plcmt: 1, minduration: 0, maxduration: 60, - w: 1024, - h: 768, - startdelay: 0 + startdelay: 0, + plcmt: 1 }; + setTimeout(() => { + expect(spec.isBidRequestValid(bid)).to.equal(true); + const requests = spec.buildRequests([bid], BIDDER_REQUEST); + const request = requests[0].data; + expect(request.imp[0].video).to.deep.include({...check}); + done(); + }, 200); + }); - videoBidWithParams.params.video = bidderVideoParams; + it('when mediaType New Video', () => { + const NEW_VIDEO_BID = { + 'bidder': 'tpmn', + 'params': {'inventoryId': 2, 'bidFloor': 2}, + 'userId': {'pubcid': '88a49ee6-beeb-4dd6-92ac-3b6060e127e1'}, + 'mediaTypes': { + 'video': { + 'context': 'outstream', + 'mimes': ['video/mp4'], + 'playerSize': [[1024, 768]], + 'playbackmethod': [2, 4, 6], + 'protocols': [3, 4], + 'api': [1, 2, 3, 6], + 'placement': 1, + 'minduration': 0, + 'maxduration': 30, + 'startdelay': 0, + 'skip': 1, + 'plcmt': 4 + } + }, + }; - const requests = spec.buildRequests([videoBidWithParams], BIDDER_REQUEST); - const request = requests[0].data; + const check = { + w: 1024, + h: 768, + mimes: [ 'video/mp4' ], + playbackmethod: [2, 4, 6], + api: [1, 2, 3, 6], + protocols: [3, 4], + placement: 1, + minduration: 0, + maxduration: 30, + startdelay: 0, + skip: 1, + plcmt: 4 + } - expect(request.imp[0]).to.deep.include({ - video: { - ...bidderVideoParams, - w: videoBidWithParams.mediaTypes.video.playerSize[0][0], - h: videoBidWithParams.mediaTypes.video.playerSize[0][1], - }, - }); + setTimeout(() => { + expect(spec.isBidRequestValid(NEW_VIDEO_BID)).to.equal(true); + let requests = spec.buildRequests([NEW_VIDEO_BID], BIDDER_REQUEST); + const request = requests[0].data; + expect(request.imp[0].video.w).to.equal(check.w); + expect(request.imp[0].video.h).to.equal(check.h); + expect(request.imp[0].video.placement).to.equal(check.placement); + expect(request.imp[0].video.minduration).to.equal(check.minduration); + expect(request.imp[0].video.maxduration).to.equal(check.maxduration); + expect(request.imp[0].video.startdelay).to.equal(check.startdelay); + expect(request.imp[0].video.skip).to.equal(check.skip); + expect(request.imp[0].video.plcmt).to.equal(check.plcmt); + expect(request.imp[0].video.mimes).to.deep.have.same.members(check.mimes); + expect(request.imp[0].video.playbackmethod).to.deep.have.same.members(check.playbackmethod); + expect(request.imp[0].video.api).to.deep.have.same.members(check.api); + expect(request.imp[0].video.protocols).to.deep.have.same.members(check.protocols); + done(); + }, 200); }); + + // it('should use bidder video params if they are set', () => { + // const bid = utils.deepClone(VIDEO_BID); + // const check = { + // api: [1, 2], + // mimes: ['video/mp4', 'video/x-flv'], + // playbackmethod: [3, 4], + // protocols: [5, 6], + // placement: 1, + // plcmt: 4, + // minduration: 0, + // maxduration: 30, + // startdelay: 0 + // }; + // bid.mediaTypes.video = check; + // bid.mediaTypes.context = 'outstream'; + // setTimeout(() => { + // expect(spec.isBidRequestValid(bid)).to.equal(true); + // const requests = spec.buildRequests([bid], BIDDER_REQUEST); + // const request = requests[0].data; + // expect(request.imp[0].video).to.deep.include({...check}); + // done(); + // }, 200); + // }); }); });