From 5a114cc568255a20b01b206487bab2edf34f0fa4 Mon Sep 17 00:00:00 2001 From: Filip Stamenkovic Date: Mon, 12 Aug 2024 13:56:20 +0200 Subject: [PATCH 01/20] switch to openRTB endpoint --- modules/showheroes-bsBidAdapter.js | 373 ++++++++--------------------- 1 file changed, 99 insertions(+), 274 deletions(-) diff --git a/modules/showheroes-bsBidAdapter.js b/modules/showheroes-bsBidAdapter.js index 062e567a1c1..9a1a6df03ed 100644 --- a/modules/showheroes-bsBidAdapter.js +++ b/modules/showheroes-bsBidAdapter.js @@ -1,25 +1,15 @@ import { deepAccess, - getWindowTop, + deepSetValue, triggerPixel, - logInfo, - logError, getBidIdParameter -} from '../src/utils.js'; -import { config } from '../src/config.js'; -import { Renderer } from '../src/Renderer.js'; + formatQS, + isFn, + logInfo} from '../src/utils.js'; +import { ortbConverter } from '../libraries/ortbConverter/converter.js'; import { registerBidder } from '../src/adapters/bidderFactory.js'; import { VIDEO, BANNER } from '../src/mediaTypes.js'; -/** - * See https://github.com/prebid/Prebid.js/pull/4222 for details on linting exception - * ShowHeroes only imports after winning a bid - * Also see https://github.com/prebid/Prebid.js/issues/11656 - */ -// eslint-disable-next-line no-restricted-imports -import { loadExternalScript } from '../src/adloader.js'; -const PROD_ENDPOINT = 'https://bs.showheroes.com/api/v1/bid'; -const STAGE_ENDPOINT = 'https://bid-service.stage.showheroes.com/api/v1/bid'; -const VIRALIZE_ENDPOINT = 'https://ads.viralize.tv/prebid-sh/'; +const VIRALIZE_ENDPOINT = 'https://ads.viralize.tv/openrtb2/auction'; const PROD_PUBLISHER_TAG = 'https://static.showheroes.com/publishertag.js'; const STAGE_PUBLISHER_TAG = 'https://pubtag.stage.showheroes.com/publishertag.js'; const PROD_VL = 'https://video-library.showheroes.com'; @@ -27,6 +17,55 @@ const STAGE_VL = 'https://video-library.stage.showheroes.com'; const BIDDER_CODE = 'showheroes-bs'; const TTL = 300; +const converter = ortbConverter({ + context: { + netRevenue: false, + ttl: TTL + }, + imp(buildImp, bidRequest, context) { + const imp = buildImp(bidRequest, context); + // video has higher priority, so if there is banner configured at the same time, send video only + if (imp?.video) { + delete imp['banner'] + } + let mediaTypeContenxt = deepAccess(bidRequest, 'mediaTypes.video.context'); + if (!mediaTypeContenxt) { + mediaTypeContenxt = BANNER; + } + deepSetValue(imp, 'ext.mediaType', mediaTypeContenxt); + imp.ext.params = bidRequest.params; + imp.ext.adUnitCode = bidRequest.adUnitCode; + if (!isFn(bidRequest.getFloor)) { + return imp + } + + let floor = bidRequest.getFloor({ + currency: 'EUR', + mediaType: '*', + size: '*', + }); + if (!isNaN(floor?.floor) && floor?.currency === 'EUR') { + imp.bidfloor = floor.floor; + imp.bidfloorcur = 'EUR'; + } + return imp; + }, + request(buildRequest, imps, bidderRequest, context) { + const req = buildRequest(imps, bidderRequest, context); + // delete user agent from oRTB, we'll get it from the header + (req?.device?.ua) && delete req.device['ua']; + // 'sua' is 2.6 standard, we operate with 2.5 + (req?.device?.sua) && delete req.device['sua']; + return req; + }, +}) + +var hasSynced = false; + +export function resetUserSync() { + hasSynced = false; +} + function getEnvURLs(isStage) { return { pubTag: isStage ? STAGE_PUBLISHER_TAG : PROD_PUBLISHER_TAG, @@ -41,175 +80,61 @@ export const spec = { gvlid: GVLID, aliases: ['showheroesBs'], supportedMediaTypes: [VIDEO, BANNER], - isBidRequestValid: function(bid) { - return !!bid.params.playerId || !!bid.params.unitId; + isBidRequestValid: function (bid) { + return !!bid.params.unitId; }, - buildRequests: function(validBidRequests, bidderRequest) { - let adUnits = []; - const pageURL = validBidRequests[0].params.contentPageUrl || - bidderRequest.refererInfo.canonicalUrl || - deepAccess(window, 'location.href'); - const isStage = !!validBidRequests[0].params.stage; - const isViralize = !!validBidRequests[0].params.unitId; - const isOutstream = deepAccess(validBidRequests[0], 'mediaTypes.video.context') === 'outstream'; - const isCustomRender = deepAccess(validBidRequests[0], 'params.outstreamOptions.customRender'); - const isNodeRender = deepAccess(validBidRequests[0], 'params.outstreamOptions.slot') || deepAccess(validBidRequests[0], 'params.outstreamOptions.iframe'); - const isNativeRender = deepAccess(validBidRequests[0], 'renderer'); - const outstreamOptions = deepAccess(validBidRequests[0], 'params.outstreamOptions'); - const isBanner = !!validBidRequests[0].mediaTypes.banner || (isOutstream && !(isCustomRender || isNativeRender || isNodeRender)); - const defaultSchain = validBidRequests[0].schain || {}; - - const consentData = bidderRequest.gdprConsent || {}; - const uspConsent = bidderRequest.uspConsent || ''; - const gdprConsent = { - apiVersion: consentData.apiVersion || 2, - gdprApplies: consentData.gdprApplies || 0, - consentString: consentData.consentString || '', - } - - validBidRequests.forEach((bid) => { - const videoSizes = getVideoSizes(bid); - const bannerSizes = getBannerSizes(bid); - const vpaidMode = getBidIdParameter('vpaidMode', bid.params); - - const makeBids = (type, size, isViralize) => { - let context = ''; - let streamType = 2; - - if (type === BANNER) { - streamType = 5; - } else { - context = deepAccess(bid, 'mediaTypes.video.context'); - if (vpaidMode && context === 'instream') { - streamType = 1; - } - if (context === 'outstream') { - streamType = 5; - } - } - - let rBid = { - type: streamType, - adUnitCode: bid.adUnitCode, - bidId: bid.bidId, - context: context, - // TODO: fix auctionId leak: https://github.com/prebid/Prebid.js/issues/9781 - auctionId: bidderRequest.auctionId, - start: +new Date(), - timeout: 3000, - params: bid.params, - schain: bid.schain || defaultSchain - }; - - if (isViralize) { - rBid.unitId = getBidIdParameter('unitId', bid.params); - rBid.sizes = size; - rBid.mediaTypes = { - [type]: {'context': context} - }; - } else { - rBid.playerId = getBidIdParameter('playerId', bid.params); - rBid.mediaType = type; - rBid.size = { - width: size[0], - height: size[1] - }; - rBid.gdprConsent = gdprConsent; - rBid.uspConsent = uspConsent; - } - - return rBid; - }; - - if (isViralize) { - if (videoSizes && videoSizes[0]) { - adUnits.push(makeBids(VIDEO, videoSizes, isViralize)); - } - if (bannerSizes && bannerSizes[0]) { - adUnits.push(makeBids(BANNER, bannerSizes, isViralize)); - } - } else { - videoSizes.forEach((size) => { - adUnits.push(makeBids(VIDEO, size)); - }); - - bannerSizes.forEach((size) => { - adUnits.push(makeBids(BANNER, size)); - }); - } - }); - - let endpointUrl; - let data; - - const QA = validBidRequests[0].params.qa || {}; - - if (isViralize) { - endpointUrl = VIRALIZE_ENDPOINT; - data = { - 'bidRequests': adUnits, - 'context': { - 'gdprConsent': gdprConsent, - 'uspConsent': uspConsent, - 'schain': defaultSchain, - 'pageURL': QA.pageURL || encodeURIComponent(pageURL) - } - } - } else { - endpointUrl = isStage ? STAGE_ENDPOINT : PROD_ENDPOINT; - - data = { - 'user': [], - 'meta': { - 'adapterVersion': 2, - 'pageURL': QA.pageURL || encodeURIComponent(pageURL), - 'vastCacheEnabled': (!!config.getConfig('cache') && !isBanner && !outstreamOptions) || false, - 'isDesktop': getWindowTop().document.documentElement.clientWidth > 700, - 'xmlAndTag': !!(isOutstream && isCustomRender) || false, - 'stage': isStage || undefined - }, - 'requests': adUnits, - 'debug': validBidRequests[0].params.debug || false, - } + buildRequests: function (validBidRequests, bidderRequest) { + const QA = validBidRequests[0].params.qa; + + const ortbData = converter.toORTB({ validBidRequests, bidderRequest }) + if (QA?.pageURL) { + deepSetValue(ortbData, 'site.page', QA.pageURL); + const u = new URL(QA.pageURL); + deepSetValue(ortbData, 'site.domain', u.host); + ortbData.test = 1; } return { - url: QA.endpoint || endpointUrl, + url: QA?.endpoint || VIRALIZE_ENDPOINT, method: 'POST', - options: {contentType: 'application/json', accept: 'application/json'}, - data: data + options: { contentType: 'application/json', accept: 'application/json' }, + data: ortbData, }; }, - interpretResponse: function(response, request) { + interpretResponse: function (response, request) { return createBids(response.body, request.data); }, - getUserSyncs: function(syncOptions, serverResponses) { - const syncs = []; + getUserSyncs: function (syncOptions, responses, gdprConsent, uspConsent, gppConsent) { + if (hasSynced || !syncOptions.iframeEnabled) return - if (!serverResponses.length || !serverResponses[0].body.userSync) { - return syncs; - } + // data is only assigned if params are available to pass to syncEndpoint + let params = {}; - const userSync = serverResponses[0].body.userSync; + if (gdprConsent) { + if (typeof gdprConsent.gdprApplies === 'boolean') { + params['gdpr'] = Number(gdprConsent.gdprApplies); + } + if (typeof gdprConsent.consentString === 'string') { + params['gdpr_consent'] = gdprConsent.consentString; + } + } - if (syncOptions.iframeEnabled) { - (userSync.iframes || []).forEach(url => { - syncs.push({ - type: 'iframe', - url - }); - }); + if (uspConsent) { + params['usp'] = encodeURIComponent(uspConsent); } - if (syncOptions.pixelEnabled) { - (userSync.pixels || []).forEach(url => { - syncs.push({ - type: 'image', - url - }); - }); + if (gppConsent?.gppString) { + params['gpp'] = gppConsent.gppString; + params['gpp_sid'] = gppConsent.applicableSections?.toString(); } - return syncs; + + params = Object.keys(params).length ? `?${formatQS(params)}` : ''; + + hasSynced = true; + return { + type: 'iframe', + url: `https://sync.dev.showheroes.com/cookie_sync` + params + }; }, onBidWon(bid) { @@ -238,10 +163,7 @@ function createBids(bidRes, reqData) { }); responseBids.forEach(function (bid) { - const requestId = bid.bidId || bid.requestId; - const reqBid = bidMap[requestId]; - const currentBidParams = reqBid.params; - const isViralize = !!reqBid.params.unitId; + const requestId = bid.requestId; const size = { width: bid.width || bid.size.width, height: bid.height || bid.size.height @@ -250,7 +172,7 @@ function createBids(bidRes, reqData) { let bidUnit = {}; bidUnit.cpm = bid.cpm; bidUnit.requestId = requestId; - bidUnit.adUnitCode = reqBid.adUnitCode; + bidUnit.adUnitCode = bid.adUnitCode; bidUnit.currency = bid.currency; bidUnit.mediaType = bid.mediaType || VIDEO; bidUnit.ttl = TTL; @@ -271,29 +193,7 @@ function createBids(bidRes, reqData) { bidUnit.vastUrl = bid.vastTag || bid.vastUrl; } if (bid.mediaType === BANNER) { - bidUnit.ad = getBannerHtml(bid, reqBid, reqData); - } else if (bid.context === 'outstream') { - const renderer = Renderer.install({ - id: requestId, - url: 'https://static.showheroes.com/renderer.js', - adUnitCode: reqBid.adUnitCode, - config: { - playerId: reqBid.playerId, - width: size.width, - height: size.height, - vastUrl: bid.vastTag, - vastXml: bid.vastXml, - ad: bid.ad, - debug: reqData.debug, - isStage: reqData.meta && !!reqData.meta.stage, - isViralize: isViralize, - customRender: getBidIdParameter('customRender', currentBidParams.outstreamOptions), - slot: getBidIdParameter('slot', currentBidParams.outstreamOptions), - iframe: getBidIdParameter('iframe', currentBidParams.outstreamOptions), - } - }); - renderer.setRender(outstreamRender); - bidUnit.renderer = renderer; + bidUnit.ad = getBannerHtml(bid, bid, reqData); } bids.push(bidUnit); }); @@ -301,67 +201,7 @@ function createBids(bidRes, reqData) { return bids; } -function outstreamRender(bid) { - let embedCode; - if (bid.renderer.config.isViralize) { - embedCode = createOutstreamEmbedCodeV2(bid); - } else { - embedCode = createOutstreamEmbedCode(bid); - } - if (typeof bid.renderer.config.customRender === 'function') { - bid.renderer.config.customRender(bid, embedCode); - } else { - try { - const inIframe = getBidIdParameter('iframe', bid.renderer.config); - if (inIframe && window.document.getElementById(inIframe).nodeName === 'IFRAME') { - const iframe = window.document.getElementById(inIframe); - let framedoc = iframe.contentDocument || (iframe.contentWindow && iframe.contentWindow.document); - framedoc.body.appendChild(embedCode); - return; - } - - const slot = getBidIdParameter('slot', bid.renderer.config) || bid.adUnitCode; - if (slot && window.document.getElementById(slot)) { - window.document.getElementById(slot).appendChild(embedCode); - } else if (slot) { - logError('[ShowHeroes][renderer] Error: spot not found'); - } - } catch (err) { - logError('[ShowHeroes][renderer] Error:' + err.message); - } - } -} - -function createOutstreamEmbedCode(bid) { - const isStage = getBidIdParameter('isStage', bid.renderer.config); - const urls = getEnvURLs(isStage); - - const fragment = window.document.createDocumentFragment(); - - let script = loadExternalScript(urls.pubTag, 'showheroes-bs', function () { - window.ShowheroesTag = this; - }); - script.setAttribute('data-player-host', urls.vlHost); - - const spot = window.document.createElement('div'); - spot.setAttribute('class', 'showheroes-spot'); - spot.setAttribute('data-player', getBidIdParameter('playerId', bid.renderer.config)); - spot.setAttribute('data-debug', getBidIdParameter('debug', bid.renderer.config)); - spot.setAttribute('data-ad-vast-tag', getBidIdParameter('vastUrl', bid.renderer.config)); - spot.setAttribute('data-stream-type', 'outstream'); - - fragment.appendChild(spot); - fragment.appendChild(script); - return fragment; -} - -function createOutstreamEmbedCodeV2(bid) { - const range = document.createRange(); - range.selectNode(document.getElementsByTagName('body')[0]); - return range.createContextualFragment(getBidIdParameter('ad', bid.renderer.config)); -} - -function getBannerHtml (bid, reqBid, reqData) { +function getBannerHtml(bid, reqBid, reqData) { const isStage = !!reqData.meta.stage; const urls = getEnvURLs(isStage); return ` @@ -380,19 +220,4 @@ function getBannerHtml (bid, reqBid, reqData) { `; } -function getVideoSizes(bidRequest) { - return formatSizes(deepAccess(bidRequest, 'mediaTypes.video.playerSize') || []); -} - -function getBannerSizes(bidRequest) { - return formatSizes(deepAccess(bidRequest, 'mediaTypes.banner.sizes') || []); -} - -function formatSizes(sizes) { - if (!sizes || !sizes.length) { - return [] - } - return Array.isArray(sizes[0]) ? sizes : [sizes]; -} - registerBidder(spec); From 539f6269030c76e0ce9c75fe9c79ba7e5c4d44f8 Mon Sep 17 00:00:00 2001 From: Filip Stamenkovic Date: Tue, 13 Aug 2024 16:25:49 +0200 Subject: [PATCH 02/20] refactor and add more tests --- modules/showheroes-bsBidAdapter.js | 50 +- .../modules/showheroes-bsBidAdapter_spec.js | 739 +++++------------- 2 files changed, 236 insertions(+), 553 deletions(-) diff --git a/modules/showheroes-bsBidAdapter.js b/modules/showheroes-bsBidAdapter.js index 9a1a6df03ed..4de8cd1fb07 100644 --- a/modules/showheroes-bsBidAdapter.js +++ b/modules/showheroes-bsBidAdapter.js @@ -17,15 +17,18 @@ const STAGE_VL = 'https://video-library.stage.showheroes.com'; const BIDDER_CODE = 'showheroes-bs'; const TTL = 300; +export const SYNC_URL = 'https://sync.dev.showheroes.com/cookie_sync' + const converter = ortbConverter({ context: { - netRevenue: false, - ttl: TTL + netRevenue: true, + ttl: TTL, + currency: 'EUR', }, imp(buildImp, bidRequest, context) { const imp = buildImp(bidRequest, context); // video has higher priority, so if there is banner configured at the same time, send video only - if (imp?.video) { + if (imp?.video && imp?.banner) { delete imp['banner'] } let mediaTypeContenxt = deepAccess(bidRequest, 'mediaTypes.video.context'); @@ -80,13 +83,13 @@ export const spec = { gvlid: GVLID, aliases: ['showheroesBs'], supportedMediaTypes: [VIDEO, BANNER], - isBidRequestValid: function (bid) { + isBidRequestValid: (bid) => { return !!bid.params.unitId; }, - buildRequests: function (validBidRequests, bidderRequest) { - const QA = validBidRequests[0].params.qa; + buildRequests: (bidRequests, bidderRequest) => { + const QA = bidRequests[0].params.qa; - const ortbData = converter.toORTB({ validBidRequests, bidderRequest }) + const ortbData = converter.toORTB({ bidRequests, bidderRequest }) if (QA?.pageURL) { deepSetValue(ortbData, 'site.page', QA.pageURL); const u = new URL(QA.pageURL); @@ -97,26 +100,21 @@ export const spec = { return { url: QA?.endpoint || VIRALIZE_ENDPOINT, method: 'POST', - options: { contentType: 'application/json', accept: 'application/json' }, data: ortbData, }; }, - interpretResponse: function (response, request) { + interpretResponse: (response, request) => { return createBids(response.body, request.data); }, - getUserSyncs: function (syncOptions, responses, gdprConsent, uspConsent, gppConsent) { - if (hasSynced || !syncOptions.iframeEnabled) return + getUserSyncs: (syncOptions, responses, gdprConsent, uspConsent, gppConsent) => { + if (hasSynced || !syncOptions.iframeEnabled) return; // data is only assigned if params are available to pass to syncEndpoint let params = {}; if (gdprConsent) { - if (typeof gdprConsent.gdprApplies === 'boolean') { - params['gdpr'] = Number(gdprConsent.gdprApplies); - } - if (typeof gdprConsent.consentString === 'string') { - params['gdpr_consent'] = gdprConsent.consentString; - } + params['gdpr'] = gdprConsent.gdprApplies ? 1 : 0; + params['gdpr_consent'] = encodeURIComponent(gdprConsent.consentString); } if (uspConsent) { @@ -125,7 +123,7 @@ export const spec = { if (gppConsent?.gppString) { params['gpp'] = gppConsent.gppString; - params['gpp_sid'] = gppConsent.applicableSections?.toString(); + params['gpp_sid'] = gppConsent.applicableSections?.join(); } params = Object.keys(params).length ? `?${formatQS(params)}` : ''; @@ -133,7 +131,7 @@ export const spec = { hasSynced = true; return { type: 'iframe', - url: `https://sync.dev.showheroes.com/cookie_sync` + params + url: SYNC_URL + params, }; }, @@ -157,12 +155,8 @@ function createBids(bidRes, reqData) { } const bids = []; - const bidMap = {}; - (reqData.requests || reqData.bidRequests || []).forEach((bid) => { - bidMap[bid.bidId] = bid; - }); - responseBids.forEach(function (bid) { + responseBids.forEach((bid) => { const requestId = bid.requestId; const size = { width: bid.width || bid.size.width, @@ -193,7 +187,7 @@ function createBids(bidRes, reqData) { bidUnit.vastUrl = bid.vastTag || bid.vastUrl; } if (bid.mediaType === BANNER) { - bidUnit.ad = getBannerHtml(bid, bid, reqData); + bidUnit.ad = getBannerHtml(bid, reqData); } bids.push(bidUnit); }); @@ -201,8 +195,8 @@ function createBids(bidRes, reqData) { return bids; } -function getBannerHtml(bid, reqBid, reqData) { - const isStage = !!reqData.meta.stage; +function getBannerHtml(bid, reqData) { + const isStage = !!reqData.meta?.stage; const urls = getEnvURLs(isStage); return ` @@ -214,7 +208,7 @@ function getBannerHtml(bid, reqBid, reqData) { data-player-host="${urls.vlHost}">
`; diff --git a/test/spec/modules/showheroes-bsBidAdapter_spec.js b/test/spec/modules/showheroes-bsBidAdapter_spec.js index 30e95b04ccf..00269f87e98 100644 --- a/test/spec/modules/showheroes-bsBidAdapter_spec.js +++ b/test/spec/modules/showheroes-bsBidAdapter_spec.js @@ -1,98 +1,67 @@ -import {expect} from 'chai' -import {spec} from 'modules/showheroes-bsBidAdapter.js' -import {newBidder} from 'src/adapters/bidderFactory.js' -import {VIDEO, BANNER} from 'src/mediaTypes.js' +import { expect } from 'chai' +import { spec, SYNC_URL, resetUserSync } from 'modules/showheroes-bsBidAdapter.js' +import { syncAddFPDToBidderRequest } from '../../helpers/fpd.js'; +import 'modules/priceFloors.js'; +import 'modules/consentManagementTcf.js'; +import 'modules/consentManagementUsp.js'; +import 'modules/schain.js'; +import { VIDEO, BANNER } from 'src/mediaTypes.js' const bidderRequest = { refererInfo: { - canonicalUrl: 'https://example.com' + page: 'https://example.com/home', + ref: 'https://referrer' } } const adomain = ['showheroes.com']; const gdpr = { - 'gdprConsent': { - 'apiVersion': 2, - 'consentString': 'BOEFEAyOEFEAyAHABDENAI4AAAB9vABAASA', - 'gdprApplies': true + gdprConsent: { + apiVersion: 2, + consentString: 'CONSENT', + vendorData: { purpose: { consents: { 1: true } } }, + gdprApplies: true, } } const uspConsent = '1---'; const schain = { - 'schain': { - 'validation': 'strict', - 'config': { - 'ver': '1.0', - 'complete': 1, - 'nodes': [ + schain: { + validation: 'strict', + config: { + ver: '1.0', + complete: 1, + nodes: [ { - 'asi': 'some.com', - 'sid': '00001', - 'hp': 1 + asi: 'some.com', + sid: '00001', + hp: 1 } ] } } } -const bidRequestCommonParams = { - 'bidder': 'showheroes-bs', - 'params': { - 'playerId': '47427aa0-f11a-4d24-abca-1295a46a46cd', - }, - 'adUnitCode': 'adunit-code-1', - 'sizes': [[640, 480]], - 'bidId': '38b373e1e31c18', - 'bidderRequestId': '12e3ade2543ba6', - 'auctionId': '43aa080090a47f', -} - const bidRequestCommonParamsV2 = { - 'bidder': 'showheroes-bs', - 'params': { - 'unitId': 'AACBWAcof-611K4U', + bidder: 'showheroes-bs', + params: { + unitId: 'AACBWAcof-611K4U', }, - 'adUnitCode': 'adunit-code-1', - 'sizes': [[640, 480]], - 'bidId': '38b373e1e31c18', - 'bidderRequestId': '12e3ade2543ba6', - 'auctionId': '43aa080090a47f', -} - -const bidRequestVideo = { - ...bidRequestCommonParams, - ...{ - 'mediaTypes': { - 'video': { - 'playerSize': [640, 480], - 'context': 'instream', - } - } - } -} - -const bidRequestOutstream = { - ...bidRequestCommonParams, - ...{ - 'mediaTypes': { - 'video': { - 'playerSize': [640, 480], - 'context': 'outstream', - } - } - } + adUnitCode: 'adunit-code-1', + bidId: '38b373e1e31c18', + bidderRequestId: '12e3ade2543ba6', + auctionId: '43aa080090a47f', } const bidRequestVideoV2 = { ...bidRequestCommonParamsV2, ...{ - 'mediaTypes': { - 'video': { - 'playerSize': [640, 480], - 'context': 'instream', + mediaTypes: { + video: { + playerSize: [640, 480], + context: 'instream', } } } @@ -101,322 +70,133 @@ const bidRequestVideoV2 = { const bidRequestOutstreamV2 = { ...bidRequestCommonParamsV2, ...{ - 'mediaTypes': { - 'video': { - 'playerSize': [640, 480], - 'context': 'outstream' - } - } - } -} - -const bidRequestVideoVpaid = { - ...bidRequestCommonParams, - ...{ - 'params': { - 'playerId': '47427aa0-f11a-4d24-abca-1295a46a46cd', - 'vpaidMode': true, - }, - 'mediaTypes': { - 'video': { - 'playerSize': [640, 480], - 'context': 'instream', - } + mediaTypes: { + video: { + playerSize: [640, 480], + context: 'outstream' + }, } } } const bidRequestBanner = { - ...bidRequestCommonParams, - ...{ - 'mediaTypes': { - 'banner': { - 'sizes': [[640, 360]] - } - } - } -} - -const bidRequestBannerMultiSizes = { - ...bidRequestCommonParams, + ...bidRequestCommonParamsV2, ...{ - 'mediaTypes': { - 'banner': { - 'sizes': [[640, 360], [480, 320]] + mediaTypes: { + banner: { + sizes: [[640, 360]] } } } } const bidRequestVideoAndBanner = { - ...bidRequestCommonParams, - 'mediaTypes': { + ...bidRequestCommonParamsV2, + mediaTypes: { ...bidRequestBanner.mediaTypes, - ...bidRequestVideo.mediaTypes + ...bidRequestVideoV2.mediaTypes } } -describe('shBidAdapter', function () { - const adapter = newBidder(spec) - - describe('inherited functions', function () { - it('exists and is a function', function () { - expect(adapter.callBids).to.exist.and.to.be.a('function') - }) - }) - - describe('isBidRequestValid', function () { - it('should return true when required params found', function () { - const requestV1 = { - 'params': { - 'playerId': '47427aa0-f11a-4d24-abca-1295a46a46cd', - } - } - expect(spec.isBidRequestValid(requestV1)).to.equal(true) - - const requestV2 = { - 'params': { - 'unitId': 'AACBTwsZVANd9NlB', - } - } - expect(spec.isBidRequestValid(requestV2)).to.equal(true) - }) - - it('should return false when required params are not passed', function () { - const request = { - 'params': {} - } - expect(spec.isBidRequestValid(request)).to.equal(false) - }) - }) - - describe('buildRequests', function () { - it('sends bid request to ENDPOINT via POST', function () { - const request = spec.buildRequests([bidRequestVideo], bidderRequest) - expect(request.method).to.equal('POST') - - const requestV2 = spec.buildRequests([bidRequestVideoV2], bidderRequest) - expect(requestV2.method).to.equal('POST') - }) - - it('check sizes formats', function () { - const request = spec.buildRequests([{ - 'params': {}, - 'mediaTypes': { - 'banner': { - 'sizes': [[320, 240]] - } - }, - }], bidderRequest) - const payload = request.data.requests[0]; - expect(payload).to.be.an('object'); - expect(payload.size).to.have.property('width', 320); - expect(payload.size).to.have.property('height', 240); - - const request2 = spec.buildRequests([{ - 'params': {}, - 'mediaTypes': { - 'video': { - 'playerSize': [640, 360] - } - }, - }], bidderRequest) - const payload2 = request2.data.requests[0]; - expect(payload).to.be.an('object'); - expect(payload2.size).to.have.property('width', 640); - expect(payload2.size).to.have.property('height', 360); - }) - - it('should get size from mediaTypes when sizes property is empty', function () { - const request = spec.buildRequests([{ - 'params': {}, - 'mediaTypes': { - 'video': { - 'playerSize': [640, 480] - } - }, - 'sizes': [], - }], bidderRequest) - const payload = request.data.requests[0]; - expect(payload).to.be.an('object'); - expect(payload.size).to.have.property('width', 640); - expect(payload.size).to.have.property('height', 480); - - const request2 = spec.buildRequests([{ - 'params': {}, - 'mediaTypes': { - 'banner': { - 'sizes': [[320, 240]] - } - }, - 'sizes': [], - }], bidderRequest) - const payload2 = request2.data.requests[0]; - expect(payload).to.be.an('object'); - expect(payload2.size).to.have.property('width', 320); - expect(payload2.size).to.have.property('height', 240); - }) - - it('should attach valid params to the payload when type is video', function () { - const request = spec.buildRequests([bidRequestVideo], bidderRequest) - const payload = request.data.requests[0]; - expect(payload).to.be.an('object'); - expect(payload).to.have.property('playerId', '47427aa0-f11a-4d24-abca-1295a46a46cd'); - expect(payload).to.have.property('mediaType', VIDEO); - expect(payload).to.have.property('type', 2); - }) - - it('should attach valid params to the payload when type is video & vpaid mode on', function () { - const request = spec.buildRequests([bidRequestVideoVpaid], bidderRequest) - const payload = request.data.requests[0]; - expect(payload).to.be.an('object'); - expect(payload).to.have.property('playerId', '47427aa0-f11a-4d24-abca-1295a46a46cd'); - expect(payload).to.have.property('mediaType', VIDEO); - expect(payload).to.have.property('type', 1); - }) - - it('should attach valid params to the payload when type is banner', function () { - const request = spec.buildRequests([bidRequestBanner], bidderRequest) - const payload = request.data.requests[0]; - expect(payload).to.be.an('object'); - expect(payload).to.have.property('playerId', '47427aa0-f11a-4d24-abca-1295a46a46cd'); - expect(payload).to.have.property('mediaType', BANNER); - expect(payload).to.have.property('type', 5); - }) - - it('should attach valid params to the payload when type is banner (multi sizes)', function () { - const request = spec.buildRequests([bidRequestBannerMultiSizes], bidderRequest) - const payload = request.data.requests[0]; - expect(payload).to.be.an('object'); - expect(payload).to.have.property('playerId', '47427aa0-f11a-4d24-abca-1295a46a46cd'); - expect(payload).to.have.property('mediaType', BANNER); - expect(payload).to.have.property('type', 5); - expect(payload).to.have.nested.property('size.width', 640); - expect(payload).to.have.nested.property('size.height', 360); - const payload2 = request.data.requests[1]; - expect(payload2).to.be.an('object'); - expect(payload2).to.have.property('playerId', '47427aa0-f11a-4d24-abca-1295a46a46cd'); - expect(payload2).to.have.property('mediaType', BANNER); - expect(payload2).to.have.property('type', 5); - expect(payload2).to.have.nested.property('size.width', 480); - expect(payload2).to.have.nested.property('size.height', 320); - }) - - it('should attach valid params to the payload when type is banner and video', function () { - const request = spec.buildRequests([bidRequestVideoAndBanner], bidderRequest) - const payload = request.data.requests[0]; - expect(payload).to.be.an('object'); - expect(payload).to.have.property('playerId', '47427aa0-f11a-4d24-abca-1295a46a46cd'); - expect(payload).to.have.property('mediaType', VIDEO); - expect(payload).to.have.property('type', 2); - const payload2 = request.data.requests[1]; - expect(payload2).to.be.an('object'); - expect(payload2).to.have.property('playerId', '47427aa0-f11a-4d24-abca-1295a46a46cd'); - expect(payload2).to.have.property('mediaType', BANNER); - expect(payload2).to.have.property('type', 5); - }) - - it('should attach valid params to the payload when type is video (instream V2)', function () { - const request = spec.buildRequests([bidRequestVideoV2], bidderRequest) - const payload = request.data.bidRequests[0]; - expect(payload).to.be.an('object'); - expect(payload).to.have.property('unitId', 'AACBWAcof-611K4U'); - expect(payload.mediaTypes).to.eql({ - [VIDEO]: { - 'context': 'instream' - } - }); - }) - - it('should attach valid params to the payload when type is video (outstream V2)', function () { - const request = spec.buildRequests([bidRequestOutstreamV2], bidderRequest) - const payload = request.data.bidRequests[0]; - expect(payload).to.be.an('object'); - expect(payload).to.have.property('unitId', 'AACBWAcof-611K4U'); - expect(payload.mediaTypes).to.eql({ - [VIDEO]: { - 'context': 'outstream' - } - }); - }) - - it('passes gdpr & uspConsent if present', function () { - const request = spec.buildRequests([bidRequestVideo], { - ...bidderRequest, - ...gdpr, - uspConsent, - }) - const payload = request.data.requests[0]; - expect(payload).to.be.an('object'); - expect(payload.gdprConsent).to.eql(gdpr.gdprConsent) - expect(payload.uspConsent).to.eql(uspConsent) - }) +describe('shBidAdapter', () => { + it('validates request', () => { + const bid = { + params: { + testKey: 'testValue', + }, + }; + expect(spec.isBidRequestValid(bid)).to.eql(false); + bid.params = { + unitId: 'test_unit', + }; + expect(spec.isBidRequestValid(bid)).to.eql(true); + }); - it('passes gdpr & usp if present (V2)', function () { - const request = spec.buildRequests([bidRequestVideoV2], { - ...bidderRequest, - ...gdpr, - uspConsent, - }) - const context = request.data.context; - expect(context).to.be.an('object'); - expect(context.gdprConsent).to.eql(gdpr.gdprConsent) - expect(context.uspConsent).to.eql(uspConsent) - }) + it('passes gdpr, usp, schain, floor in ortb request', () => { + const bidRequest = Object.assign({}, bidRequestVideoV2) + const fullRequest = { + bids: [bidRequestVideoV2], + ...bidderRequest, + ...gdpr, + ...schain, + ...{ uspConsent: uspConsent }, + }; + bidRequest.schain = schain.schain.config; + const getFloorResponse = { currency: 'EUR', floor: 3 }; + bidRequest.getFloor = () => getFloorResponse; + const request = spec.buildRequests([bidRequest], syncAddFPDToBidderRequest(fullRequest)); + const payload = request.data; + expect(payload.regs.ext.gdpr).to.eql(Number(gdpr.gdprConsent.gdprApplies)); + expect(payload.regs.ext.us_privacy).to.eql(uspConsent); + expect(payload.user.ext.consent).to.eql(gdpr.gdprConsent.consentString); + expect(payload.source.ext.schain).to.eql(bidRequest.schain); + expect(payload.test).to.eql(0); + expect(payload.imp[0].bidfloor).eql(3); + expect(payload.imp[0].bidfloorcur).eql('EUR'); + expect(payload.site.page).to.eql('https://example.com/home'); + expect(payload.device.ua).to.undefined; + expect(payload.device.sua).to.undefined; + }); - it('passes schain object if present', function() { - const request = spec.buildRequests([{ - ...bidRequestVideo, - ...schain - }], bidderRequest) - const payload = request.data.requests[0]; - expect(payload).to.be.an('object'); - expect(payload.schain).to.eql(schain.schain); - }) + it('override QA params', () => { + const bidRequest = Object.assign({}, bidRequestVideoV2) + const fullRequest = { + bids: [bidRequestVideoV2], + }; + const bidEndpoint = 'https://bidder.com/endpoint'; + const fakePageURL = 'https://testing.page.com/' + bidRequest.params.qa = { + endpoint: bidEndpoint, + pageURL: fakePageURL, + }; + const request = spec.buildRequests([bidRequest], syncAddFPDToBidderRequest(fullRequest)); + expect(request.url).to.eql(bidEndpoint); + expect(request.data.site.page).to.eql(fakePageURL) + expect(request.data.site.domain).to.eql('testing.page.com'); + expect(request.data.test).to.eql(1); + }); - it('passes schain object if present (V2)', function() { - const request = spec.buildRequests([{ - ...bidRequestVideoV2, - ...schain - }], bidderRequest) - const context = request.data.context; - expect(context).to.be.an('object'); - expect(context.schain).to.eql(schain.schain); - }) - }) + // it('handle banner and video', () => { + // const bidRequest = Object.assign({}, bidRequestVideoAndBanner) + // const fullRequest = { + // bids: [bidRequest], + // }; + // const request = spec.buildRequests([bidRequest], syncAddFPDToBidderRequest(fullRequest)); + // const payload = request.data; + + // expect(payload.imp[0].video).to.be.a('object'); + // expect(payload.imp[0].ext.mediaType).eql('instream') + // expect(payload.imp[0].banner).to.be.undefined; + // const requestBanner = Object.assign({}, bidRequestBanner) + // const fullRequestBanner = { + // bids: [requestBanner], + // }; + // const bannerORTB = spec.buildRequests([requestBanner], syncAddFPDToBidderRequest(fullRequestBanner)); + // const payloadBanner = bannerORTB.data; + + // expect(payloadBanner.imp[0].banner).to.be.a('object'); + // expect(payloadBanner.imp[0].ext.mediaType).eql('banner') + // expect(payloadBanner.imp[0].video).to.be.undefined; + // }); describe('interpretResponse', function () { it('handles nobid responses', function () { - expect(spec.interpretResponse({body: {}}, {data: {meta: {}}}).length).to.equal(0) - expect(spec.interpretResponse({body: []}, {data: {meta: {}}}).length).to.equal(0) + expect(spec.interpretResponse({ body: {} }, { data: { meta: {} } }).length).to.equal(0) + expect(spec.interpretResponse({ body: [] }, { data: { meta: {} } }).length).to.equal(0) }) - const vastTag = 'https://test.com/commercial/wrapper?player_id=47427aa0-f11a-4d24-abca-1295a46a46cd&ad_bidder=showheroes-bs&master_shadt=1&description_url=https%3A%2F%2Fbid-service.stage.showheroes.com%2Fvast%2Fad%2Fcache%2F4840b920-40e1-4e09-9231-60bbf088c8d6' const vastXml = '' const basicResponse = { - 'cpm': 5, - 'currency': 'EUR', - 'mediaType': VIDEO, - 'context': 'instream', - 'bidId': '38b373e1e31c18', - 'size': {'width': 640, 'height': 480}, - 'vastTag': 'https:\/\/test.com\/commercial\/wrapper?player_id=47427aa0-f11a-4d24-abca-1295a46a46cd&ad_bidder=showheroes-bs&master_shadt=1&description_url=https%3A%2F%2Fbid-service.stage.showheroes.com%2Fvast%2Fad%2Fcache%2F4840b920-40e1-4e09-9231-60bbf088c8d6', - 'vastXml': vastXml, - 'adomain': adomain, - }; - - const responseVideo = { - 'bids': [{ - ...basicResponse, - }], - }; - - const responseVideoOutstream = { - 'bids': [{ - ...basicResponse, - 'context': 'outstream', - }], + cpm: 5, + currency: 'EUR', + mediaType: VIDEO, + context: 'instream', + bidId: '38b373e1e31c18', + size: { 'width': 640, 'height': 480 }, + vastTag: 'https:\/\/test.com\/commercial\/wrapper?player_id=47427aa0-f11a-4d24-abca-1295a46a46cd&ad_bidder=showheroes-bs&master_shadt=1&description_url=https%3A%2F%2Fbid-service.stage.showheroes.com%2Fvast%2Fad%2Fcache%2F4840b920-40e1-4e09-9231-60bbf088c8d6', + vastXml: vastXml, + adomain: adomain, }; const responseBanner = { @@ -427,128 +207,78 @@ describe('shBidAdapter', function () { }; const basicResponseV2 = { - 'requestId': '38b373e1e31c18', - 'adUnitCode': 'adunit-code-1', - 'cpm': 1, - 'currency': 'EUR', - 'width': 640, - 'height': 480, - 'advertiserDomain': [], - 'callbacks': { - 'won': ['https://test.com/track/?ver=15&session_id=01ecd03ce381505ccdeb88e555b05001&category=request_session&type=event&request_session_id=01ecd03ce381505ccdeb88e555b05001&label=prebid_won&reason=ok'] + requestId: '38b373e1e31c18', + adUnitCode: 'adunit-code-1', + cpm: 1, + currency: 'EUR', + width: 640, + height: 480, + advertiserDomain: [], + callbacks: { + won: ['https://test.com/track/?ver=15&session_id=01ecd03ce381505ccdeb88e555b05001&category=request_session&type=event&request_session_id=01ecd03ce381505ccdeb88e555b05001&label=prebid_won&reason=ok'] }, - 'mediaType': 'video', - 'adomain': adomain, + vastXml: vastXml, + mediaType: 'video', + adomain: adomain, }; const vastUrl = 'https://test.com/vast/?zid=AACBWAcof-611K4U&u=https://example.org/?foo=bar&gdpr=0&cs=XXXXXXXXXXXXXXXXXXXX&sid=01ecd03ce381505ccdeb88e555b05001&width=300&height=200&prebidmode=1' const responseVideoV2 = { - 'bidResponses': [{ + bidResponses: [{ ...basicResponseV2, - 'context': 'instream', - 'vastUrl': vastUrl, + context: 'instream', + vastUrl: vastUrl, }], }; const responseVideoOutstreamV2 = { - 'bidResponses': [{ + bidResponses: [{ ...basicResponseV2, - 'context': 'outstream', - 'ad': '', + context: 'outstream', + ad: '', + vastUrl: vastUrl, }], }; - it('should get correct bid response when type is video', function () { - const request = spec.buildRequests([bidRequestVideo], bidderRequest) - const expectedResponse = [ - { - 'cpm': 5, - 'creativeId': 'c_38b373e1e31c18', - 'adUnitCode': 'adunit-code-1', - 'currency': 'EUR', - 'width': 640, - 'height': 480, - 'mediaType': 'video', - 'netRevenue': true, - 'vastUrl': vastTag, - 'vastXml': vastXml, - 'requestId': '38b373e1e31c18', - 'ttl': 300, - 'adResponse': { - 'content': vastXml - }, - 'meta': { - 'advertiserDomains': adomain - } - } - ] - - const result = spec.interpretResponse({'body': responseVideo}, request) - expect(result).to.deep.equal(expectedResponse) - }) - it('should get correct bid response when type is video (V2)', function () { const request = spec.buildRequests([bidRequestVideoV2], bidderRequest) const expectedResponse = [ { - 'cpm': 1, - 'creativeId': 'c_38b373e1e31c18', - 'adUnitCode': 'adunit-code-1', - 'currency': 'EUR', - 'width': 640, - 'height': 480, - 'mediaType': 'video', - 'netRevenue': true, - 'vastUrl': vastUrl, - 'requestId': '38b373e1e31c18', - 'ttl': 300, - 'meta': { - 'advertiserDomains': adomain - } + cpm: 1, + creativeId: 'c_38b373e1e31c18', + adUnitCode: 'adunit-code-1', + currency: 'EUR', + width: 640, + height: 480, + mediaType: 'video', + netRevenue: true, + vastUrl: vastUrl, + requestId: '38b373e1e31c18', + ttl: 300, + meta: { + advertiserDomains: adomain + }, + vastXml: vastXml, + adResponse: { + content: vastXml, + }, } ] - const result = spec.interpretResponse({'body': responseVideoV2}, request) + const result = spec.interpretResponse({ 'body': responseVideoV2 }, request) expect(result).to.deep.equal(expectedResponse) }) it('should get correct bid response when type is banner', function () { const request = spec.buildRequests([bidRequestBanner], bidderRequest) - const result = spec.interpretResponse({'body': responseBanner}, request) + const result = spec.interpretResponse({ 'body': responseBanner }, request) expect(result[0]).to.have.property('mediaType', BANNER); expect(result[0].ad).to.include('', vastUrl: vastUrl, + rendererConfig: { + rendererUrl: 'https://test.com/render.js', + renderFunc: 'myRenderer.renderAd', + renderOptions: { + key: 'my renderer custom value', + } + }, }], }; @@ -264,6 +272,7 @@ describe('shBidAdapter', () => { adResponse: { content: vastXml, }, + extra: 'test', } ] @@ -281,11 +290,13 @@ describe('shBidAdapter', () => { }) it('should get correct bid response when type is outstream (slot V2)', function () { + window.myRenderer = { + renderAd: function() { + return null; + } + } const bidRequestV2 = JSON.parse(JSON.stringify(bidRequestOutstreamV2)); const slotId = 'testSlot2' - bidRequestV2.params.outstreamOptions = { - slot: slotId - } const container = document.createElement('div') container.setAttribute('id', slotId) @@ -296,6 +307,16 @@ describe('shBidAdapter', () => { const result = spec.interpretResponse({ 'body': responseVideoOutstreamV2 }, request) const bid = result[0] expect(bid).to.have.property('mediaType', VIDEO); + expect(typeof bid.renderer).to.be.eql('object'); + expect(bid.renderer.url).to.eql('https://test.com/render.js'); + + sinon.spy(window.myRenderer, 'renderAd'); + bid.renderer.render(bid); + + const renderCall = window.myRenderer.renderAd.getCall(0); + const renderPayload = renderCall.args[0]; + expect(renderPayload.adResponse.content).to.eql(vastXml); + expect(renderPayload.key).to.eql('my renderer custom value'); }) it('should get correct bid response when type is outstream (customRender)', function () { From 6b27614ad0de58bbcd6a8af02a319796f0037ceb Mon Sep 17 00:00:00 2001 From: Filip Stamenkovic Date: Fri, 30 Aug 2024 11:40:40 +0200 Subject: [PATCH 12/20] lint fix --- modules/showheroes-bsBidAdapter.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/modules/showheroes-bsBidAdapter.js b/modules/showheroes-bsBidAdapter.js index 6c34e59b41e..6e5e8dbbc93 100644 --- a/modules/showheroes-bsBidAdapter.js +++ b/modules/showheroes-bsBidAdapter.js @@ -3,7 +3,8 @@ import { deepSetValue, triggerPixel, isFn, - logInfo} from '../src/utils.js'; + logInfo +} from '../src/utils.js'; import { Renderer } from '../src/Renderer.js'; import { ortbConverter } from '../libraries/ortbConverter/converter.js'; import { registerBidder } from '../src/adapters/bidderFactory.js'; @@ -188,8 +189,7 @@ function createBids(bidRes, reqData) { } if (bid.mediaType === BANNER) { bidUnit.ad = getBannerHtml(bid, reqData); - } - else if (bid.context === 'outstream') { + } else if (bid.context === 'outstream') { const renderConfig = { rendererUrl: bid.rendererConfig?.rendererUrl, renderFunc: bid.rendererConfig?.renderFunc, @@ -211,7 +211,7 @@ function outstreamRender(response, renderConfig) { if (!isFn(func)) { return; } - const renderPayload = {...response, ...renderConfig.renderOptions}; + const renderPayload = { ...response, ...renderConfig.renderOptions }; func(renderPayload); }); } From 40ea39c29f4fa26626abc19e5233c74768e375cd Mon Sep 17 00:00:00 2001 From: Filip Stamenkovic Date: Tue, 17 Sep 2024 17:00:19 +0200 Subject: [PATCH 13/20] remove banner support --- modules/showheroes-bsBidAdapter.js | 65 +++----------- .../modules/showheroes-bsBidAdapter_spec.js | 90 +------------------ 2 files changed, 11 insertions(+), 144 deletions(-) diff --git a/modules/showheroes-bsBidAdapter.js b/modules/showheroes-bsBidAdapter.js index 6e5e8dbbc93..0a5e0def1bb 100644 --- a/modules/showheroes-bsBidAdapter.js +++ b/modules/showheroes-bsBidAdapter.js @@ -8,13 +8,9 @@ import { import { Renderer } from '../src/Renderer.js'; import { ortbConverter } from '../libraries/ortbConverter/converter.js'; import { registerBidder } from '../src/adapters/bidderFactory.js'; -import { VIDEO, BANNER } from '../src/mediaTypes.js'; +import { VIDEO } from '../src/mediaTypes.js'; -const VIRALIZE_ENDPOINT = 'https://ads.viralize.tv/openrtb2/auction'; -const PROD_PUBLISHER_TAG = 'https://static.showheroes.com/publishertag.js'; -const STAGE_PUBLISHER_TAG = 'https://pubtag.stage.showheroes.com/publishertag.js'; -const PROD_VL = 'https://video-library.showheroes.com'; -const STAGE_VL = 'https://video-library.stage.showheroes.com'; +const ENDPOINT = 'https://ads.viralize.tv/openrtb2/auction'; const BIDDER_CODE = 'showheroes-bs'; const TTL = 300; @@ -26,15 +22,8 @@ const converter = ortbConverter({ }, imp(buildImp, bidRequest, context) { const imp = buildImp(bidRequest, context); - // video has higher priority, so if there is banner configured at the same time, send video only - if (imp?.video && imp?.banner) { - delete imp['banner'] - } - let mediaTypeContenxt = deepAccess(bidRequest, 'mediaTypes.video.context'); - if (!mediaTypeContenxt) { - mediaTypeContenxt = BANNER; - } - deepSetValue(imp, 'ext.mediaType', mediaTypeContenxt); + const mediaTypeContext = deepAccess(bidRequest, 'mediaTypes.video.context'); + deepSetValue(imp, 'ext.mediaType', mediaTypeContext); imp.ext.params = bidRequest.params; imp.ext.adUnitCode = bidRequest.adUnitCode; @@ -68,20 +57,13 @@ const converter = ortbConverter({ }, }) -function getEnvURLs(isStage) { - return { - pubTag: isStage ? STAGE_PUBLISHER_TAG : PROD_PUBLISHER_TAG, - vlHost: isStage ? STAGE_VL : PROD_VL - } -} - const GVLID = 111; export const spec = { code: BIDDER_CODE, gvlid: GVLID, aliases: ['showheroesBs'], - supportedMediaTypes: [VIDEO, BANNER], + supportedMediaTypes: [VIDEO], isBidRequestValid: (bid) => { return !!bid.params.unitId; }, @@ -89,21 +71,15 @@ export const spec = { const QA = bidRequests[0].params.qa; const ortbData = converter.toORTB({ bidRequests, bidderRequest }) - if (QA?.pageURL) { - deepSetValue(ortbData, 'site.page', QA.pageURL); - const u = new URL(QA.pageURL); - deepSetValue(ortbData, 'site.domain', u.host); - ortbData.test = 1; - } return { - url: QA?.endpoint || VIRALIZE_ENDPOINT, + url: QA?.endpoint || ENDPOINT, method: 'POST', data: ortbData, }; }, - interpretResponse: (response, request) => { - return createBids(response.body, request.data); + interpretResponse: (response) => { + return createBids(response.body); }, getUserSyncs: (syncOptions, serverResponses) => { const syncs = []; @@ -145,7 +121,7 @@ export const spec = { }, }; -function createBids(bidRes, reqData) { +function createBids(bidRes) { if (!bidRes) { return []; } @@ -187,9 +163,7 @@ function createBids(bidRes, reqData) { if (bid.vastTag || bid.vastUrl) { bidUnit.vastUrl = bid.vastTag || bid.vastUrl; } - if (bid.mediaType === BANNER) { - bidUnit.ad = getBannerHtml(bid, reqData); - } else if (bid.context === 'outstream') { + if (bid.context === 'outstream') { const renderConfig = { rendererUrl: bid.rendererConfig?.rendererUrl, renderFunc: bid.rendererConfig?.renderFunc, @@ -229,23 +203,4 @@ function createRenderer(bid, renderConfig) { return renderer; } -function getBannerHtml(bid, reqData) { - const isStage = !!reqData.meta?.stage; - const urls = getEnvURLs(isStage); - return ` - - - -
- - `; -} - registerBidder(spec); diff --git a/test/spec/modules/showheroes-bsBidAdapter_spec.js b/test/spec/modules/showheroes-bsBidAdapter_spec.js index 0b27cd88daa..d611f3ebe00 100644 --- a/test/spec/modules/showheroes-bsBidAdapter_spec.js +++ b/test/spec/modules/showheroes-bsBidAdapter_spec.js @@ -5,7 +5,7 @@ import 'modules/priceFloors.js'; import 'modules/consentManagementTcf.js'; import 'modules/consentManagementUsp.js'; import 'modules/schain.js'; -import { VIDEO, BANNER } from 'src/mediaTypes.js' +import { VIDEO } from 'src/mediaTypes.js' const bidderRequest = { refererInfo: { @@ -79,25 +79,6 @@ const bidRequestOutstreamV2 = { } } -const bidRequestBanner = { - ...bidRequestCommonParamsV2, - ...{ - mediaTypes: { - banner: { - sizes: [[640, 360]] - } - } - } -} - -const bidRequestVideoAndBanner = { - ...bidRequestCommonParamsV2, - mediaTypes: { - ...bidRequestBanner.mediaTypes, - ...bidRequestVideoV2.mediaTypes - } -} - describe('shBidAdapter', () => { it('validates request', () => { const bid = { @@ -139,47 +120,6 @@ describe('shBidAdapter', () => { expect(payload.device.sua).to.undefined; }); - it('override QA params', () => { - const bidRequest = Object.assign({}, bidRequestVideoV2) - const fullRequest = { - bids: [bidRequestVideoV2], - }; - const bidEndpoint = 'https://bidder.com/endpoint'; - const fakePageURL = 'https://testing.page.com/' - bidRequest.params.qa = { - endpoint: bidEndpoint, - pageURL: fakePageURL, - }; - const request = spec.buildRequests([bidRequest], syncAddFPDToBidderRequest(fullRequest)); - expect(request.url).to.eql(bidEndpoint); - expect(request.data.site.page).to.eql(fakePageURL) - expect(request.data.site.domain).to.eql('testing.page.com'); - expect(request.data.test).to.eql(1); - }); - - it('handle banner and video', () => { - const bidRequest = Object.assign({}, bidRequestVideoAndBanner) - const fullRequest = { - bids: [bidRequest], - }; - const request = spec.buildRequests([bidRequest], syncAddFPDToBidderRequest(fullRequest)); - const payload = request.data; - - expect(payload.imp[0].video).to.be.a('object'); - expect(payload.imp[0].ext.mediaType).eql('instream') - expect(payload.imp[0].banner).to.be.undefined; - const requestBanner = Object.assign({}, bidRequestBanner) - const fullRequestBanner = { - bids: [requestBanner], - }; - const bannerORTB = spec.buildRequests([requestBanner], syncAddFPDToBidderRequest(fullRequestBanner)); - const payloadBanner = bannerORTB.data; - - expect(payloadBanner.imp[0].banner).to.be.a('object'); - expect(payloadBanner.imp[0].ext.mediaType).eql('banner') - expect(payloadBanner.imp[0].video).to.be.undefined; - }); - describe('interpretResponse', function () { it('handles nobid responses', function () { expect(spec.interpretResponse({ body: {} }, { data: { meta: {} } }).length).to.equal(0) @@ -188,25 +128,6 @@ describe('shBidAdapter', () => { const vastXml = '' - const basicResponse = { - cpm: 5, - currency: 'EUR', - mediaType: VIDEO, - context: 'instream', - bidId: '38b373e1e31c18', - size: { 'width': 640, 'height': 480 }, - vastTag: 'https:\/\/test.com\/commercial\/wrapper?player_id=47427aa0-f11a-4d24-abca-1295a46a46cd&ad_bidder=showheroes-bs&master_shadt=1&description_url=https%3A%2F%2Fbid-service.stage.showheroes.com%2Fvast%2Fad%2Fcache%2F4840b920-40e1-4e09-9231-60bbf088c8d6', - vastXml: vastXml, - adomain: adomain, - }; - - const responseBanner = { - 'bids': [{ - ...basicResponse, - 'mediaType': BANNER, - }], - }; - const basicResponseV2 = { requestId: '38b373e1e31c18', adUnitCode: 'adunit-code-1', @@ -280,15 +201,6 @@ describe('shBidAdapter', () => { expect(result).to.deep.equal(expectedResponse) }) - it('should get correct bid response when type is banner', function () { - const request = spec.buildRequests([bidRequestBanner], bidderRequest) - - const result = spec.interpretResponse({ 'body': responseBanner }, request) - expect(result[0]).to.have.property('mediaType', BANNER); - expect(result[0].ad).to.include('', - vastUrl: vastUrl, - rendererConfig: { - rendererUrl: 'https://test.com/render.js', - renderFunc: 'myRenderer.renderAd', - renderOptions: { - key: 'my renderer custom value', - } - }, - }], - }; - it('should get correct bid response when type is video (V2)', function () { const request = spec.buildRequests([bidRequestVideoV2], bidderRequest) const expectedResponse = [ @@ -183,7 +164,6 @@ describe('shBidAdapter', () => { height: 480, mediaType: 'video', netRevenue: true, - vastUrl: vastUrl, requestId: '38b373e1e31c18', ttl: 300, meta: { @@ -193,11 +173,14 @@ describe('shBidAdapter', () => { adResponse: { content: vastXml, }, + callbacks: { + won: [callback_won], + }, extra: 'test', } ] - const result = spec.interpretResponse({ 'body': responseVideoV2 }, request) + const result = spec.interpretResponse({ 'body': basicResponse }, request) expect(result).to.deep.equal(expectedResponse) }) @@ -208,6 +191,14 @@ describe('shBidAdapter', () => { } } const bidRequestV2 = JSON.parse(JSON.stringify(bidRequestOutstreamV2)); + const bidResponse = JSON.parse(JSON.stringify(basicResponse)); + bidResponse.seatbid[0].bid[0].ext.rendererConfig = { + rendererUrl: 'https://test.com/render.js', + renderFunc: 'myRenderer.renderAd', + renderOptions: { + key: 'my renderer custom value', + } + }; const slotId = 'testSlot2' const container = document.createElement('div') @@ -216,7 +207,7 @@ describe('shBidAdapter', () => { const request = spec.buildRequests([bidRequestV2], bidderRequest) - const result = spec.interpretResponse({ 'body': responseVideoOutstreamV2 }, request) + const result = spec.interpretResponse({ 'body': bidResponse }, request) const bid = result[0] expect(bid).to.have.property('mediaType', VIDEO); expect(typeof bid.renderer).to.be.eql('object'); @@ -236,21 +227,37 @@ describe('shBidAdapter', () => { const request = spec.buildRequests([bidRequest], bidderRequest) - const result = spec.interpretResponse({ 'body': responseVideoOutstreamV2 }, request) + const result = spec.interpretResponse({ 'body': basicResponse }, request) + const bid = result[0]; + expect(bid).to.have.property('mediaType', VIDEO); + + expect(bid.vastXml).to.eql(vastXml); + }) + + it('should get vast url', function () { + const bidRequest = JSON.parse(JSON.stringify(bidRequestOutstreamV2)); + const bidResponse = JSON.parse(JSON.stringify(basicResponse)); + bidResponse.seatbid[0].bid[0].nurl = vastUrl + + const request = spec.buildRequests([bidRequest], bidderRequest) + + const result = spec.interpretResponse({ 'body': bidResponse }, request) const bid = result[0]; expect(bid).to.have.property('mediaType', VIDEO); expect(bid.vastXml).to.eql(vastXml); - expect(bid.vastUrl).to.equal(vastUrl); + expect(bid.vastUrl).to.eql(vastUrl); }) }); describe('getUserSyncs', function () { const response = [{ body: { - userSync: { - iframes: ['https://sync.showheroes.com/iframe'], - pixels: ['https://sync.showheroes.com/pixel'] + ext: { + userSync: { + iframes: ['https://sync.showheroes.com/iframe'], + pixels: ['https://sync.showheroes.com/pixel'] + } } } }] From 797141a4851f2f0ba2599b00768ed2a9f663088a Mon Sep 17 00:00:00 2001 From: Filip Stamenkovic Date: Thu, 19 Sep 2024 16:02:40 +0200 Subject: [PATCH 15/20] use fromORTB to simplify bidder --- modules/showheroes-bsBidAdapter.js | 86 +++++++------------ .../modules/showheroes-bsBidAdapter_spec.js | 14 +-- 2 files changed, 34 insertions(+), 66 deletions(-) diff --git a/modules/showheroes-bsBidAdapter.js b/modules/showheroes-bsBidAdapter.js index 85f1dd02e33..7ed71071361 100644 --- a/modules/showheroes-bsBidAdapter.js +++ b/modules/showheroes-bsBidAdapter.js @@ -19,6 +19,7 @@ const converter = ortbConverter({ netRevenue: true, ttl: TTL, currency: 'EUR', + mediaType: VIDEO, }, imp(buildImp, bidRequest, context) { const imp = buildImp(bidRequest, context); @@ -55,6 +56,24 @@ const converter = ortbConverter({ (req?.device?.sua) && delete req.device['sua']; return req; }, + + bidResponse(buildBidResponse, bid, context) { + const bidResponse = buildBidResponse(bid, context); + + if (context.imp?.ext?.mediaType === 'outstream') { + const renderConfig = { + rendererUrl: bid.ext?.rendererConfig?.rendererUrl, + renderFunc: bid.ext?.rendererConfig?.renderFunc, + renderOptions: bid.ext?.rendererConfig?.renderOptions, + }; + if (renderConfig.renderFunc && renderConfig.rendererUrl) { + bidResponse.renderer = createRenderer(bidResponse, renderConfig); + } + } + bidResponse.callbacks = bid.ext.callbacks; + bidResponse.extra = bid.ext?.extra; + return bidResponse; + }, }) const GVLID = 111; @@ -79,7 +98,12 @@ export const spec = { }; }, interpretResponse: (response, request) => { - return createBids(response.body, request.data); + if (!response.body) { + return []; + } + + const bids = converter.fromORTB({response: response.body, request: request.data}).bids; + return bids; }, getUserSyncs: (syncOptions, serverResponses) => { const syncs = []; @@ -121,61 +145,6 @@ export const spec = { }, }; -function createBids(bidRes, bidReq) { - if (!bidRes || !bidRes.seatbid) { - return []; - } - const bids = []; - - bidRes.seatbid.forEach((seatbid) => { - if (!seatbid.bid?.length) { - return; - } - seatbid.bid.forEach((bid) => { - const imp = bidReq.imp.find((imp) => imp.id === bid.impid); - const bidUnit = { - cpm: bid.price, - requestId: bid.impid, - adUnitCode: imp?.ext?.adUnitCode, - currency: bidRes.cur, - mediaType: VIDEO, - ttl: bid.exp || TTL, - netRevenue: true, - extra: bid.extra, - width: bid.w, - height: bid.h, - creativeId: bid.crid, - callbacks: bid?.ext?.callbacks, - meta: { - advertiserDomains: bid.adomain || [], - }, - }; - if (bid.adm) { - bidUnit.vastXml = bid.adm; - bidUnit.adResponse = { - content: bid.adm, - }; - } - if (bid.nurl) { - bidUnit.vastUrl = bid.nurl; - } - if (imp?.ext?.mediaType === 'outstream') { - const renderConfig = { - rendererUrl: bid.ext?.rendererConfig?.rendererUrl, - renderFunc: bid.ext?.rendererConfig?.renderFunc, - renderOptions: bid.ext?.rendererConfig?.renderOptions, - }; - if (renderConfig.renderFunc && renderConfig.rendererUrl) { - bidUnit.renderer = createRenderer(bidUnit, renderConfig); - } - }; - bids.push(bidUnit); - }); - }); - - return bids; -} - function outstreamRender(response, renderConfig) { response.renderer.push(() => { const func = deepAccess(window, renderConfig.renderFunc); @@ -183,6 +152,11 @@ function outstreamRender(response, renderConfig) { return; } const renderPayload = { ...response, ...renderConfig.renderOptions }; + if (renderPayload.vastXml) { + renderPayload.adResponse = { + content: renderPayload.vastXml, + }; + } func(renderPayload); }); } diff --git a/test/spec/modules/showheroes-bsBidAdapter_spec.js b/test/spec/modules/showheroes-bsBidAdapter_spec.js index 7cffad37ace..1366ffef3c4 100644 --- a/test/spec/modules/showheroes-bsBidAdapter_spec.js +++ b/test/spec/modules/showheroes-bsBidAdapter_spec.js @@ -121,11 +121,6 @@ describe('shBidAdapter', () => { }); describe('interpretResponse', function () { - it('handles nobid responses', function () { - expect(spec.interpretResponse({ body: {} }, { data: { meta: {} } }).length).to.equal(0) - expect(spec.interpretResponse({ body: [] }, { data: { meta: {} } }).length).to.equal(0) - }) - const vastXml = '' const callback_won = 'https://test.com/track/?ver=15&session_id=01ecd03ce381505ccdeb88e555b05001&category=request_session&type=event&request_session_id=01ecd03ce381505ccdeb88e555b05001&label=prebid_won&reason=ok' @@ -139,12 +134,12 @@ describe('shBidAdapter', () => { adm: vastXml, impid: '38b373e1e31c18', crid: 'c_38b373e1e31c18', - extra: 'test', adomain: adomain, ext: { callbacks: { won: [callback_won], }, + extra: 'test', }, }], seat: 'showheroes', @@ -158,10 +153,12 @@ describe('shBidAdapter', () => { { cpm: 1, creativeId: 'c_38b373e1e31c18', - adUnitCode: 'adunit-code-1', + creative_id: 'c_38b373e1e31c18', currency: 'EUR', width: 640, height: 480, + playerHeight: 480, + playerWidth: 640, mediaType: 'video', netRevenue: true, requestId: '38b373e1e31c18', @@ -170,9 +167,6 @@ describe('shBidAdapter', () => { advertiserDomains: adomain }, vastXml: vastXml, - adResponse: { - content: vastXml, - }, callbacks: { won: [callback_won], }, From 14f73a2d46dcf99255148e3681e1093b0c865d56 Mon Sep 17 00:00:00 2001 From: Filip Stamenkovic Date: Thu, 19 Sep 2024 17:05:49 +0200 Subject: [PATCH 16/20] don't pass entire bid to renderer --- modules/showheroes-bsBidAdapter.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/showheroes-bsBidAdapter.js b/modules/showheroes-bsBidAdapter.js index 7ed71071361..f8c1aab8198 100644 --- a/modules/showheroes-bsBidAdapter.js +++ b/modules/showheroes-bsBidAdapter.js @@ -151,10 +151,10 @@ function outstreamRender(response, renderConfig) { if (!isFn(func)) { return; } - const renderPayload = { ...response, ...renderConfig.renderOptions }; - if (renderPayload.vastXml) { + const renderPayload = { ...renderConfig.renderOptions }; + if (response.vastXml) { renderPayload.adResponse = { - content: renderPayload.vastXml, + content: response.vastXml, }; } func(renderPayload); From 15a7d72292471af71f05873e14a95548a6e03336 Mon Sep 17 00:00:00 2001 From: Filip Stamenkovic Date: Fri, 20 Sep 2024 10:46:41 +0200 Subject: [PATCH 17/20] set video context in ext --- modules/showheroes-bsBidAdapter.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/modules/showheroes-bsBidAdapter.js b/modules/showheroes-bsBidAdapter.js index f8c1aab8198..a008addc77e 100644 --- a/modules/showheroes-bsBidAdapter.js +++ b/modules/showheroes-bsBidAdapter.js @@ -23,8 +23,9 @@ const converter = ortbConverter({ }, imp(buildImp, bidRequest, context) { const imp = buildImp(bidRequest, context); - const mediaTypeContext = deepAccess(bidRequest, 'mediaTypes.video.context'); - deepSetValue(imp, 'ext.mediaType', mediaTypeContext); + const videoContext = deepAccess(bidRequest, 'mediaTypes.video.context'); + deepSetValue(imp, 'video.ext.context', videoContext); + imp.ext = imp.ext || {}; imp.ext.params = bidRequest.params; imp.ext.adUnitCode = bidRequest.adUnitCode; @@ -60,7 +61,7 @@ const converter = ortbConverter({ bidResponse(buildBidResponse, bid, context) { const bidResponse = buildBidResponse(bid, context); - if (context.imp?.ext?.mediaType === 'outstream') { + if (context.imp?.video?.ext?.context === 'outstream') { const renderConfig = { rendererUrl: bid.ext?.rendererConfig?.rendererUrl, renderFunc: bid.ext?.rendererConfig?.renderFunc, From f328975024328634c37afa502f23f1e690ee2258 Mon Sep 17 00:00:00 2001 From: Filip Stamenkovic Date: Mon, 30 Sep 2024 14:33:59 +0200 Subject: [PATCH 18/20] endpoint should end with / --- modules/showheroes-bsBidAdapter.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/showheroes-bsBidAdapter.js b/modules/showheroes-bsBidAdapter.js index a008addc77e..1de34f9befb 100644 --- a/modules/showheroes-bsBidAdapter.js +++ b/modules/showheroes-bsBidAdapter.js @@ -10,7 +10,7 @@ import { ortbConverter } from '../libraries/ortbConverter/converter.js'; import { registerBidder } from '../src/adapters/bidderFactory.js'; import { VIDEO } from '../src/mediaTypes.js'; -const ENDPOINT = 'https://ads.viralize.tv/openrtb2/auction'; +const ENDPOINT = 'https://ads.viralize.tv/openrtb2/auction/'; const BIDDER_CODE = 'showheroes-bs'; const TTL = 300; From 489d1178d214e6787d3077cdceee159a0b39410b Mon Sep 17 00:00:00 2001 From: Filip Stamenkovic Date: Mon, 30 Sep 2024 14:53:25 +0200 Subject: [PATCH 19/20] update documentation unitId --- modules/showheroes-bsBidAdapter.js | 2 +- modules/showheroes-bsBidAdapter.md | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/showheroes-bsBidAdapter.js b/modules/showheroes-bsBidAdapter.js index 1de34f9befb..65fa45bf0ed 100644 --- a/modules/showheroes-bsBidAdapter.js +++ b/modules/showheroes-bsBidAdapter.js @@ -71,7 +71,7 @@ const converter = ortbConverter({ bidResponse.renderer = createRenderer(bidResponse, renderConfig); } } - bidResponse.callbacks = bid.ext.callbacks; + bidResponse.callbacks = bid.ext?.callbacks; bidResponse.extra = bid.ext?.extra; return bidResponse; }, diff --git a/modules/showheroes-bsBidAdapter.md b/modules/showheroes-bsBidAdapter.md index 49640b7e8e7..f306593a783 100644 --- a/modules/showheroes-bsBidAdapter.md +++ b/modules/showheroes-bsBidAdapter.md @@ -25,7 +25,7 @@ A module that connects to ShowHeroes demand source to fetch bids. { bidder: "showheroes-bs", params: { - unitId: 'AACBWAcof-611K4U', + unitId: '1234abcd-5678efgh', } } ] @@ -42,7 +42,7 @@ A module that connects to ShowHeroes demand source to fetch bids. { bidder: "showheroes-bs", params: { - unitId: 'AACBTwsZVANd9NlB', + unitId: '1234abcd-5678efgh', } } ] From 54a8fc1120c0ebe56d081815f04d2084553e9454 Mon Sep 17 00:00:00 2001 From: Filip Stamenkovic Date: Mon, 30 Sep 2024 16:23:07 +0200 Subject: [PATCH 20/20] check if video features are enabled for tests --- .../modules/showheroes-bsBidAdapter_spec.js | 160 +++++++++--------- 1 file changed, 81 insertions(+), 79 deletions(-) diff --git a/test/spec/modules/showheroes-bsBidAdapter_spec.js b/test/spec/modules/showheroes-bsBidAdapter_spec.js index 1366ffef3c4..1b37eeec892 100644 --- a/test/spec/modules/showheroes-bsBidAdapter_spec.js +++ b/test/spec/modules/showheroes-bsBidAdapter_spec.js @@ -147,101 +147,103 @@ describe('shBidAdapter', () => { } const vastUrl = 'https://test.com/vast/?zid=AACBWAcof-611K4U&u=https://example.org/?foo=bar&gdpr=0&cs=XXXXXXXXXXXXXXXXXXXX&sid=01ecd03ce381505ccdeb88e555b05001&width=300&height=200&prebidmode=1' - it('should get correct bid response when type is video (V2)', function () { - const request = spec.buildRequests([bidRequestVideoV2], bidderRequest) - const expectedResponse = [ - { - cpm: 1, - creativeId: 'c_38b373e1e31c18', - creative_id: 'c_38b373e1e31c18', - currency: 'EUR', - width: 640, - height: 480, - playerHeight: 480, - playerWidth: 640, - mediaType: 'video', - netRevenue: true, - requestId: '38b373e1e31c18', - ttl: 300, - meta: { - advertiserDomains: adomain - }, - vastXml: vastXml, - callbacks: { - won: [callback_won], - }, - extra: 'test', - } - ] + if (FEATURES.VIDEO) { + it('should get correct bid response when type is video (V2)', function () { + const request = spec.buildRequests([bidRequestVideoV2], bidderRequest) + const expectedResponse = [ + { + cpm: 1, + creativeId: 'c_38b373e1e31c18', + creative_id: 'c_38b373e1e31c18', + currency: 'EUR', + width: 640, + height: 480, + playerHeight: 480, + playerWidth: 640, + mediaType: 'video', + netRevenue: true, + requestId: '38b373e1e31c18', + ttl: 300, + meta: { + advertiserDomains: adomain + }, + vastXml: vastXml, + callbacks: { + won: [callback_won], + }, + extra: 'test', + } + ] - const result = spec.interpretResponse({ 'body': basicResponse }, request) - expect(result).to.deep.equal(expectedResponse) - }) + const result = spec.interpretResponse({ 'body': basicResponse }, request) + expect(result).to.deep.equal(expectedResponse) + }) - it('should get correct bid response when type is outstream (slot V2)', function () { - window.myRenderer = { - renderAd: function() { - return null; - } - } - const bidRequestV2 = JSON.parse(JSON.stringify(bidRequestOutstreamV2)); - const bidResponse = JSON.parse(JSON.stringify(basicResponse)); - bidResponse.seatbid[0].bid[0].ext.rendererConfig = { - rendererUrl: 'https://test.com/render.js', - renderFunc: 'myRenderer.renderAd', - renderOptions: { - key: 'my renderer custom value', + it('should get correct bid response when type is outstream (slot V2)', function () { + window.myRenderer = { + renderAd: function() { + return null; + } } - }; - const slotId = 'testSlot2' + const bidRequestV2 = JSON.parse(JSON.stringify(bidRequestOutstreamV2)); + const bidResponse = JSON.parse(JSON.stringify(basicResponse)); + bidResponse.seatbid[0].bid[0].ext.rendererConfig = { + rendererUrl: 'https://test.com/render.js', + renderFunc: 'myRenderer.renderAd', + renderOptions: { + key: 'my renderer custom value', + } + }; + const slotId = 'testSlot2' - const container = document.createElement('div') - container.setAttribute('id', slotId) - document.body.appendChild(container) + const container = document.createElement('div') + container.setAttribute('id', slotId) + document.body.appendChild(container) - const request = spec.buildRequests([bidRequestV2], bidderRequest) + const request = spec.buildRequests([bidRequestV2], bidderRequest) - const result = spec.interpretResponse({ 'body': bidResponse }, request) - const bid = result[0] - expect(bid).to.have.property('mediaType', VIDEO); - expect(typeof bid.renderer).to.be.eql('object'); - expect(bid.renderer.url).to.eql('https://test.com/render.js'); + const result = spec.interpretResponse({ 'body': bidResponse }, request) + const bid = result[0] + expect(bid).to.have.property('mediaType', VIDEO); + expect(typeof bid.renderer).to.be.eql('object'); + expect(bid.renderer.url).to.eql('https://test.com/render.js'); - sinon.spy(window.myRenderer, 'renderAd'); - bid.renderer.render(bid); + sinon.spy(window.myRenderer, 'renderAd'); + bid.renderer.render(bid); - const renderCall = window.myRenderer.renderAd.getCall(0); - const renderPayload = renderCall.args[0]; - expect(renderPayload.adResponse.content).to.eql(vastXml); - expect(renderPayload.key).to.eql('my renderer custom value'); - }) + const renderCall = window.myRenderer.renderAd.getCall(0); + const renderPayload = renderCall.args[0]; + expect(renderPayload.adResponse.content).to.eql(vastXml); + expect(renderPayload.key).to.eql('my renderer custom value'); + }) - it('should get correct bid response when type is outstream (customRender)', function () { - const bidRequest = JSON.parse(JSON.stringify(bidRequestOutstreamV2)); + it('should get correct bid response when type is outstream (customRender)', function () { + const bidRequest = JSON.parse(JSON.stringify(bidRequestOutstreamV2)); - const request = spec.buildRequests([bidRequest], bidderRequest) + const request = spec.buildRequests([bidRequest], bidderRequest) - const result = spec.interpretResponse({ 'body': basicResponse }, request) - const bid = result[0]; - expect(bid).to.have.property('mediaType', VIDEO); + const result = spec.interpretResponse({ 'body': basicResponse }, request) + const bid = result[0]; + expect(bid).to.have.property('mediaType', VIDEO); - expect(bid.vastXml).to.eql(vastXml); - }) + expect(bid.vastXml).to.eql(vastXml); + }) - it('should get vast url', function () { - const bidRequest = JSON.parse(JSON.stringify(bidRequestOutstreamV2)); - const bidResponse = JSON.parse(JSON.stringify(basicResponse)); - bidResponse.seatbid[0].bid[0].nurl = vastUrl + it('should get vast url', function () { + const bidRequest = JSON.parse(JSON.stringify(bidRequestOutstreamV2)); + const bidResponse = JSON.parse(JSON.stringify(basicResponse)); + bidResponse.seatbid[0].bid[0].nurl = vastUrl - const request = spec.buildRequests([bidRequest], bidderRequest) + const request = spec.buildRequests([bidRequest], bidderRequest) - const result = spec.interpretResponse({ 'body': bidResponse }, request) - const bid = result[0]; - expect(bid).to.have.property('mediaType', VIDEO); + const result = spec.interpretResponse({ 'body': bidResponse }, request) + const bid = result[0]; + expect(bid).to.have.property('mediaType', VIDEO); - expect(bid.vastXml).to.eql(vastXml); - expect(bid.vastUrl).to.eql(vastUrl); - }) + expect(bid.vastXml).to.eql(vastXml); + expect(bid.vastUrl).to.eql(vastUrl); + }) + } }); describe('getUserSyncs', function () {