From 95ad4157d2c37dbbe35bc45ccf1944e6d8a8e2c4 Mon Sep 17 00:00:00 2001 From: ksanksana Date: Thu, 5 Mar 2020 16:36:57 +0300 Subject: [PATCH 1/7] add mediaforce bid adapter --- modules/mediaforceBidAdapter.js | 151 +++++++++++ modules/mediaforceBidAdapter.md | 35 +++ .../spec/modules/mediaforceBidAdapter_spec.js | 240 ++++++++++++++++++ 3 files changed, 426 insertions(+) create mode 100644 modules/mediaforceBidAdapter.js create mode 100644 modules/mediaforceBidAdapter.md create mode 100644 test/spec/modules/mediaforceBidAdapter_spec.js diff --git a/modules/mediaforceBidAdapter.js b/modules/mediaforceBidAdapter.js new file mode 100644 index 00000000000..fc0c44f6d82 --- /dev/null +++ b/modules/mediaforceBidAdapter.js @@ -0,0 +1,151 @@ +import * as utils from '../src/utils.js'; +import {registerBidder} from '../src/adapters/bidderFactory.js'; +import {BANNER} from '../src/mediaTypes.js'; + +const BIDDER_CODE = 'mediaforce'; +const ENDPOINT_URL = 'https://rtb.mfadsrvr.com/header_bid'; + +export const spec = { + code: BIDDER_CODE, + supportedMediaTypes: [BANNER], + + /** + * Determines whether or not the given bid request is valid. + * + * @param {BidRequest} bid The bid params to validate. + * @return boolean True if this is a valid bid, and false otherwise. + */ + isBidRequestValid: function(bid) { + return !!((typeof bid.params === 'object') && bid.params.placement_id && bid.params.publisher_id); + }, + + /** + * Make a server request from the list of BidRequests. + * + * @param {validBidRequests[]} - an array of bids + * @return ServerRequest Info describing the request to the server. + */ + buildRequests: function(validBidRequests, bidderRequest) { + if (validBidRequests.length === 0) { + return; + } + + const referer = bidderRequest && bidderRequest.refererInfo ? encodeURIComponent(bidderRequest.refererInfo.referer) : ''; + const dnt = utils.getDNT() ? 1 : 0; + let imp = []; + let requests = [] + validBidRequests.forEach(bid => { + let tagid = bid.params.placement_id; + let bidfloor = bid.params.bidfloor ? parseFloat(bid.params.bidfloor) : 0; + let impObj = { + id: bid.bidId, + tagid: tagid, + secure: 1, + bidfloor: bidfloor, + }; + for (let mediaTypes in bid.mediaTypes) { + switch (mediaTypes) { + case BANNER: + impObj.banner = createBannerRequest(bid); + imp.push(impObj); + break; + default: return; + } + } + + let request = { + id: bid.transactionId, + site: { + page: referer, + ref: referer, + id: bid.params.publisher_id, + publisher: { + id: bid.params.publisher_id + }, + }, + device: { + ua: navigator.userAgent, + js: 1, + dnt: dnt, + language: getLanguage() + }, + imp + }; + requests.push({ + method: 'POST', + url: ENDPOINT_URL, + data: JSON.stringify(request) + }); + }); + return requests; + }, + + /** + * Unpack the response from the server into a list of bids. + * + * @param {ServerResponse} serverResponse A successful response from the server. + * @return {Bid[]} An array of bids which were nested inside the server. + */ + interpretResponse: function(serverResponse, bidRequest) { + if (!serverResponse || !serverResponse.body) { + return []; + } + + const responseBody = serverResponse.body; + const bidResponses = []; + const cur = responseBody.cur; + responseBody.seatbid.forEach((bids) => { + bids.bid.forEach((serverBid) => { + const bid = { + requestId: serverBid.impid, + cpm: parseFloat(serverBid.price), + width: serverBid.w, + height: serverBid.h, + creativeId: serverBid.adid, + currency: cur, + netRevenue: true, + ttl: serverBid.ttl || 300, + ad: serverBid.adm, + burl: serverBid.burl, + }; + + bidResponses.push(bid); + }) + }); + + return bidResponses; + }, + + /** + * Register bidder specific code, which will execute if a bid from this bidder won the auction + * @param {Bid} The bid that won the auction + */ + onBidWon: function(bid) { + const cpm = utils.deepAccess(bid, 'adserverTargeting.hb_pb') || ''; + if (utils.isStr(bid.burl) && bid.burl !== '') { + bid.burl = utils.replaceAuctionPrice(bid.burl, cpm); + utils.triggerPixel(bid.burl); + } + }, +} +registerBidder(spec); + +function getLanguage() { + const language = navigator.language ? 'language' : 'userLanguage'; + return navigator[language].split('-')[0]; +} + +function createBannerRequest(bid) { + const sizes = bid.mediaTypes.banner.sizes; + if (!sizes.length) return; + + let format = []; + let r = utils.parseGPTSingleSizeArrayToRtbSize(sizes[0]); + for (let f = 1; f < sizes.length; f++) { + format.push(utils.parseGPTSingleSizeArrayToRtbSize(sizes[f])); + } + if (format.length) { + r.format = format + } + return r +} diff --git a/modules/mediaforceBidAdapter.md b/modules/mediaforceBidAdapter.md new file mode 100644 index 00000000000..e16d4178b3f --- /dev/null +++ b/modules/mediaforceBidAdapter.md @@ -0,0 +1,35 @@ +# Overview + +``` +Module Name: MediaForce Bidder Adapter +Module Type: Bidder Adapter +Maintainer: little.grey.goblin@gmail.com +``` + +# Description + +Module that connects to mediaforce's demand sources + +# Test Parameters +``` + var adUnits = [ + { + code: 'test-div', + mediaTypes: { + banner: { + sizes: [[300, 250]], + } + }, + bids: [ + { + bidder: "mediaforce", + params: { + placement_id: 'pl12345', // required + publisher_id: 'pub12345', // required + bidfloor: 0.5, + } + } + ] + } + ]; +``` diff --git a/test/spec/modules/mediaforceBidAdapter_spec.js b/test/spec/modules/mediaforceBidAdapter_spec.js new file mode 100644 index 00000000000..9cf63efd5c2 --- /dev/null +++ b/test/spec/modules/mediaforceBidAdapter_spec.js @@ -0,0 +1,240 @@ +import {assert} from 'chai'; +import {spec} from 'modules/mediaforceBidAdapter.js'; +import * as utils from '../../../src/utils.js'; + +describe('mediaforce bid adapter', function () { + let sandbox; + + beforeEach(function () { + sandbox = sinon.sandbox.create(); + }); + + afterEach(function () { + sandbox.restore(); + }); + + function getLanguage() { + let language = navigator.language ? 'language' : 'userLanguage'; + return navigator[language].split('-')[0]; + } + + const language = getLanguage(); + const baseUrl = 'https://rtb.mfadsrvr.com' + + describe('isBidRequestValid()', function () { + const defaultBid = { + bidder: 'mediaforce', + params: { + property: '10433394', + bidfloor: 0.3, + }, + }; + + it('should not accept bid without required params', function () { + assert.equal(spec.isBidRequestValid(defaultBid), false); + }); + + it('should return false when params are not passed', function () { + let bid = utils.deepClone(defaultBid); + delete bid.params; + assert.equal(spec.isBidRequestValid(bid), false); + }); + + it('should return false when valid params are not passed', function () { + let bid = utils.deepClone(defaultBid); + bid.params = {placement_id: '', publisher_id: ''}; + assert.equal(spec.isBidRequestValid(bid), false); + }); + + it('should return true when valid params are passed', function () { + let bid = utils.deepClone(defaultBid); + bid.mediaTypes = { + banner: { + sizes: [[300, 250]] + } + }; + bid.params = {publisher_id: 2, placement_id: '123'}; + assert.equal(spec.isBidRequestValid(bid), true); + }); + + it('should return false when mediaTypes == native passed (native is not supported yet)', function () { + let bid = utils.deepClone(defaultBid); + bid.mediaTypes = { + native: { + sizes: [[300, 250]] + } + }; + bid.params = {publisher_id: 2, placement_id: '123'}; + assert.equal(spec.isBidRequestValid(bid), true); + }); + }); + + describe('buildRequests()', function () { + const defaultBid = { + bidder: 'mediaforce', + params: { + publisher_id: 'pub123', + placement_id: '202', + }, + mediaTypes: { + banner: { + sizes: [[300, 250]] + } + }, + transactionId: 'd45dd707-a418-42ec-b8a7-b70a6c6fab0b', + }; + + const refererInfo = { + referer: 'https://www.prebid.org', + reachedTop: true, + stack: [ + 'https://www.prebid.org/page.html', + 'https://www.prebid.org/iframe1.html', + ] + }; + + const requestUrl = `${baseUrl}/header_bid`; + const dnt = utils.getDNT() ? 1 : 0; + const secure = 1 + + it('should return undefined if no validBidRequests passed', function () { + assert.equal(spec.buildRequests([]), undefined); + }); + + it('should return proper request url: no refererInfo', function () { + let [request] = spec.buildRequests([defaultBid]); + assert.equal(request.url, requestUrl); + }); + + it('should return proper banner imp', function () { + let bid = utils.deepClone(defaultBid); + bid.params.bidfloor = 0.5; + + let bidRequests = [bid]; + let bidderRequest = {bids: bidRequests, refererInfo: refererInfo}; + + let [request] = spec.buildRequests(bidRequests, bidderRequest); + + let data = JSON.parse(request.data); + assert.deepEqual(data, { + id: bid.transactionId, + site: { + id: bid.params.publisher_id, + publisher: {id: bid.params.publisher_id}, + ref: encodeURIComponent(refererInfo.referer), + page: encodeURIComponent(refererInfo.referer), + }, + device: { + ua: navigator.userAgent, + dnt: dnt, + js: 1, + language: getLanguage(), + }, + imp: [{ + tagid: bid.params.placement_id, + secure: secure, + bidfloor: bid.params.bidfloor, + banner: {w: 300, h: 250}, + }], + }); + + assert.deepEqual(request, { + method: 'POST', + url: requestUrl, + data: '{"id":"d45dd707-a418-42ec-b8a7-b70a6c6fab0b","site":{"page":"https%3A%2F%2Fwww.prebid.org","ref":"https%3A%2F%2Fwww.prebid.org","id":"pub123","publisher":{"id":"pub123"}},"device":{"ua":"' + navigator.userAgent + '","js":1,"dnt":' + dnt + ',"language":"' + getLanguage() + '"},"imp":[{"tagid":"202","secure":1,"bidfloor":0.5,"banner":{"w":300,"h":250}}]}', + }); + }); + + it('multiple sizes', function () { + let bid = utils.deepClone(defaultBid); + bid.mediaTypes = { + banner: { + sizes: [[300, 600], [300, 250]], + } + }; + + let [request] = spec.buildRequests([bid]); + let data = JSON.parse(request.data); + assert.deepEqual(data.imp[0].banner, {w: 300, h: 600, format: [{w: 300, h: 250}]}); + }); + }); + + describe('interpretResponse() banner', function () { + it('not successfull response', function () { + assert.deepEqual(spec.interpretResponse(), []); + }); + + it('successfull response', function () { + let bid = { + price: 3, + w: 100, + id: '65599d0a-42d2-446a-9d39-6086c1433ffe', + burl: `${baseUrl}/burl/\${AUCTION_PRICE}`, + cid: '2_ssl', + h: 100, + cat: ['IAB1-1'], + crid: '2_ssl', + impid: '2b3c9d103723a7', + adid: '2_ssl', + adm: `` + }; + + let response = { + body: { + seatbid: [{ + bid: [bid] + }], + cur: 'USD', + id: '620190c2-7eef-42fa-91e2-f5c7fbc2bdd3' + } + }; + + let bids = spec.interpretResponse(response); + assert.deepEqual(bids, ([{ + ad: bid.adm, + cpm: bid.price, + creativeId: bid.adid, + currency: response.body.cur, + height: bid.h, + netRevenue: true, + burl: bid.burl, + requestId: bid.impid, + ttl: 300, + width: bid.w, + }])); + }); + }); + + describe('onBidWon()', function () { + beforeEach(function() { + sinon.stub(utils, 'triggerPixel'); + }); + afterEach(function() { + utils.triggerPixel.restore(); + }); + it('should expand price macros in burl', function () { + let burl = 'burl&s=${AUCTION_PRICE}'; + let bid = { + bidder: 'mediaforce', + width: 300, + height: 250, + adId: '330a22bdea4cac', + mediaType: 'banner', + cpm: 0.28, + ad: '...', + requestId: '418b37f85e772c', + adUnitCode: 'div-gpt-ad-1460505748561-0', + size: '350x250', + burl: burl, + adserverTargeting: { + hb_bidder: 'mediaforce', + hb_adid: '330a22bdea4cac', + hb_pb: '0.20', + hb_size: '350x250' + } + } + spec.onBidWon(bid); + assert.equal(bid.burl, 'burl&s=0.20'); + }); + }); +}); From 5203f41012e9a6d5fee66889af320c7f369273eb Mon Sep 17 00:00:00 2001 From: ksanksana Date: Tue, 10 Mar 2020 12:23:23 +0300 Subject: [PATCH 2/7] make use of unused variable language --- test/spec/modules/mediaforceBidAdapter_spec.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/spec/modules/mediaforceBidAdapter_spec.js b/test/spec/modules/mediaforceBidAdapter_spec.js index 9cf63efd5c2..09d997e9349 100644 --- a/test/spec/modules/mediaforceBidAdapter_spec.js +++ b/test/spec/modules/mediaforceBidAdapter_spec.js @@ -128,7 +128,7 @@ describe('mediaforce bid adapter', function () { ua: navigator.userAgent, dnt: dnt, js: 1, - language: getLanguage(), + language: language, }, imp: [{ tagid: bid.params.placement_id, @@ -141,7 +141,7 @@ describe('mediaforce bid adapter', function () { assert.deepEqual(request, { method: 'POST', url: requestUrl, - data: '{"id":"d45dd707-a418-42ec-b8a7-b70a6c6fab0b","site":{"page":"https%3A%2F%2Fwww.prebid.org","ref":"https%3A%2F%2Fwww.prebid.org","id":"pub123","publisher":{"id":"pub123"}},"device":{"ua":"' + navigator.userAgent + '","js":1,"dnt":' + dnt + ',"language":"' + getLanguage() + '"},"imp":[{"tagid":"202","secure":1,"bidfloor":0.5,"banner":{"w":300,"h":250}}]}', + data: '{"id":"d45dd707-a418-42ec-b8a7-b70a6c6fab0b","site":{"page":"https%3A%2F%2Fwww.prebid.org","ref":"https%3A%2F%2Fwww.prebid.org","id":"pub123","publisher":{"id":"pub123"}},"device":{"ua":"' + navigator.userAgent + '","js":1,"dnt":' + dnt + ',"language":"' + language + '"},"imp":[{"tagid":"202","secure":1,"bidfloor":0.5,"banner":{"w":300,"h":250}}]}', }); }); From 847191027a4a2a94e4c4032dbc62e48955b5a92d Mon Sep 17 00:00:00 2001 From: Nikolay Sokolov Date: Tue, 21 Jul 2020 18:45:05 +0300 Subject: [PATCH 3/7] Added native support for Mediaforce Bid Adapter --- modules/mediaforceBidAdapter.js | 232 ++++++++++++++++-- modules/mediaforceBidAdapter.md | 33 +++ .../spec/modules/mediaforceBidAdapter_spec.js | 228 +++++++++++++++-- 3 files changed, 452 insertions(+), 41 deletions(-) diff --git a/modules/mediaforceBidAdapter.js b/modules/mediaforceBidAdapter.js index fc0c44f6d82..db8cc11d690 100644 --- a/modules/mediaforceBidAdapter.js +++ b/modules/mediaforceBidAdapter.js @@ -1,30 +1,112 @@ import * as utils from '../src/utils.js'; import {registerBidder} from '../src/adapters/bidderFactory.js'; -import {BANNER} from '../src/mediaTypes.js'; +import {BANNER, NATIVE} from '../src/mediaTypes.js'; const BIDDER_CODE = 'mediaforce'; const ENDPOINT_URL = 'https://rtb.mfadsrvr.com/header_bid'; +const TEST_ENDPOINT_URL = 'http://staging-gce-sc-2.dorpat.iponweb.net/header_bid?debug_key=abcdefghijklmnop'; +const NATIVE_ID_MAP = {}; +const NATIVE_PARAMS = { + title: { + id: 1, + name: 'title' + }, + icon: { + id: 2, + type: 1, + name: 'img' + }, + image: { + id: 3, + type: 3, + name: 'img' + }, + body: { + id: 4, + name: 'data', + type: 2 + }, + sponsoredBy: { + id: 5, + name: 'data', + type: 1 + }, + cta: { + id: 6, + type: 12, + name: 'data' + }, + body2: { + id: 7, + name: 'data', + type: 10 + }, + rating: { + id: 8, + name: 'data', + type: 3 + }, + likes: { + id: 9, + name: 'data', + type: 4 + }, + downloads: { + id: 10, + name: 'data', + type: 5 + }, + displayUrl: { + id: 11, + name: 'data', + type: 11 + }, + price: { + id: 12, + name: 'data', + type: 6 + }, + salePrice: { + id: 13, + name: 'data', + type: 7 + }, + address: { + id: 14, + name: 'data', + type: 9 + }, + phone: { + id: 15, + name: 'data', + type: 8 + } +}; +Object.keys(NATIVE_PARAMS).forEach((key) => { + NATIVE_ID_MAP[NATIVE_PARAMS[key].id] = key; +}); export const spec = { code: BIDDER_CODE, - supportedMediaTypes: [BANNER], + supportedMediaTypes: [BANNER, NATIVE], /** - * Determines whether or not the given bid request is valid. - * - * @param {BidRequest} bid The bid params to validate. - * @return boolean True if this is a valid bid, and false otherwise. - */ + * Determines whether or not the given bid request is valid. + * + * @param {BidRequest} bid The bid params to validate. + * @return boolean True if this is a valid bid, and false otherwise. + */ isBidRequestValid: function(bid) { return !!((typeof bid.params === 'object') && bid.params.placement_id && bid.params.publisher_id); }, /** - * Make a server request from the list of BidRequests. - * - * @param {validBidRequests[]} - an array of bids - * @return ServerRequest Info describing the request to the server. - */ + * Make a server request from the list of BidRequests. + * + * @param {BidRequest[]} validBidRequests - an array of bids + * @param {bidderRequest} bidderRequest bidder request object + * @return ServerRequest Info describing the request to the server. + */ buildRequests: function(validBidRequests, bidderRequest) { if (validBidRequests.length === 0) { return; @@ -32,11 +114,12 @@ export const spec = { const referer = bidderRequest && bidderRequest.refererInfo ? encodeURIComponent(bidderRequest.refererInfo.referer) : ''; const dnt = utils.getDNT() ? 1 : 0; - let imp = []; - let requests = [] + let requests = []; validBidRequests.forEach(bid => { let tagid = bid.params.placement_id; let bidfloor = bid.params.bidfloor ? parseFloat(bid.params.bidfloor) : 0; + let imp = []; + let validImp = false; let impObj = { id: bid.bidId, tagid: tagid, @@ -47,11 +130,16 @@ export const spec = { switch (mediaTypes) { case BANNER: impObj.banner = createBannerRequest(bid); - imp.push(impObj); + validImp = true; + break; + case NATIVE: + impObj.native = createNativeRequest(bid); + validImp = true; break; default: return; } } + validImp && imp.push(impObj); let request = { id: bid.transactionId, @@ -73,7 +161,7 @@ export const spec = { }; requests.push({ method: 'POST', - url: ENDPOINT_URL, + url: bid.params.is_test ? TEST_ENDPOINT_URL : ENDPOINT_URL, data: JSON.stringify(request) }); }); @@ -81,11 +169,12 @@ export const spec = { }, /** - * Unpack the response from the server into a list of bids. - * - * @param {ServerResponse} serverResponse A successful response from the server. - * @return {Bid[]} An array of bids which were nested inside the server. - */ + * Unpack the response from the server into a list of bids. + * + * @param {ServerResponse} serverResponse A successful response from the server. + * @param {BidRequest} bidRequest + * @return {Bid[]} An array of bids which were nested inside the server. + */ interpretResponse: function(serverResponse, bidRequest) { if (!serverResponse || !serverResponse.body) { return []; @@ -99,15 +188,35 @@ export const spec = { const bid = { requestId: serverBid.impid, cpm: parseFloat(serverBid.price), - width: serverBid.w, - height: serverBid.h, creativeId: serverBid.adid, currency: cur, netRevenue: true, ttl: serverBid.ttl || 300, - ad: serverBid.adm, burl: serverBid.burl, }; + if (serverBid.dealid) { + bid.dealId = serverBid.dealid; + } + let jsonAdm; + let adm = serverBid.adm; + let ext = serverBid.ext; + try { + jsonAdm = JSON.parse(adm); + } catch (err) {} + if (jsonAdm && jsonAdm.native) { + ext = ext || {}; + ext.native = jsonAdm.native; + adm = null; + } + if (adm) { + bid.width = serverBid.w; + bid.height = serverBid.h; + bid.ad = adm; + bid.mediaType = BANNER; + } else if (ext && ext.native) { + bid.native = parseNative(ext.native); + bid.mediaType = NATIVE; + } bidResponses.push(bid); }) @@ -117,9 +226,9 @@ export const spec = { }, /** - * Register bidder specific code, which will execute if a bid from this bidder won the auction - * @param {Bid} The bid that won the auction - */ + * Register bidder specific code, which will execute if a bid from this bidder won the auction + * @param {Bid} The bid that won the auction + */ onBidWon: function(bid) { const cpm = utils.deepAccess(bid, 'adserverTargeting.hb_pb') || ''; if (utils.isStr(bid.burl) && bid.burl !== '') { @@ -149,3 +258,72 @@ function createBannerRequest(bid) { } return r } + +function parseNative(native) { + const {assets, link, imptrackers, jstracker} = native; + const result = { + clickUrl: link.url, + clickTrackers: link.clicktrackers || [], + impressionTrackers: imptrackers || [], + javascriptTrackers: jstracker ? [jstracker] : [] + }; + (assets || []).forEach((asset) => { + const {id, img, data, title} = asset; + const key = NATIVE_ID_MAP[id]; + if (key) { + if (!utils.isEmpty(title)) { + result.title = title.text + } else if (!utils.isEmpty(img)) { + result[key] = { + url: img.url, + height: img.h, + width: img.w + } + } else if (!utils.isEmpty(data)) { + result[key] = data.value; + } + } + }); + + return result; +} + +function createNativeRequest(bid) { + const assets = []; + if (bid.nativeParams) { + Object.keys(bid.nativeParams).forEach((key) => { + if (NATIVE_PARAMS[key]) { + const {name, type, id} = NATIVE_PARAMS[key]; + const assetObj = type ? {type} : {}; + let {len, sizes, required, aspect_ratios: aRatios} = bid.nativeParams[key]; + if (len) { + assetObj.len = len; + } + if (aRatios && aRatios[0]) { + aRatios = aRatios[0]; + let wmin = aRatios.min_width || 0; + let hmin = aRatios.ratio_height * wmin / aRatios.ratio_width | 0; + assetObj.wmin = wmin; + assetObj.hmin = hmin; + } + if (sizes && sizes.length) { + sizes = [].concat(...sizes); + assetObj.w = sizes[0]; + assetObj.h = sizes[1]; + } + const asset = {required: required ? 1 : 0, id}; + asset[name] = assetObj; + assets.push(asset); + } + }); + } + return { + ver: '1.2', + request: { + assets: assets, + context: 1, + plcmttype: 1, + ver: '1.2' + } + } +} diff --git a/modules/mediaforceBidAdapter.md b/modules/mediaforceBidAdapter.md index e16d4178b3f..f8e6903516f 100644 --- a/modules/mediaforceBidAdapter.md +++ b/modules/mediaforceBidAdapter.md @@ -33,3 +33,36 @@ Module that connects to mediaforce's demand sources } ]; ``` + +``` + var adUnits = [ + { + code: 'test-div', + mediaTypes: { + native: { + title: { + required: true, + len: 800 + }, + image: { + required: true, + sizes: [420, 315], + }, + sponsoredBy: { + required: false + } + } + }, + bids: [ + { + bidder: "mediaforce", + params: { + placement_id: 'pl12345', // required + publisher_id: 'pub111', // required + is_test: true + } + } + ] + } + ]; +``` diff --git a/test/spec/modules/mediaforceBidAdapter_spec.js b/test/spec/modules/mediaforceBidAdapter_spec.js index 09d997e9349..ee478acbc83 100644 --- a/test/spec/modules/mediaforceBidAdapter_spec.js +++ b/test/spec/modules/mediaforceBidAdapter_spec.js @@ -1,6 +1,7 @@ import {assert} from 'chai'; import {spec} from 'modules/mediaforceBidAdapter.js'; import * as utils from '../../../src/utils.js'; +import {BANNER, NATIVE} from '../../../src/mediaTypes.js'; describe('mediaforce bid adapter', function () { let sandbox; @@ -19,7 +20,7 @@ describe('mediaforce bid adapter', function () { } const language = getLanguage(); - const baseUrl = 'https://rtb.mfadsrvr.com' + const baseUrl = 'https://rtb.mfadsrvr.com'; describe('isBidRequestValid()', function () { const defaultBid = { @@ -56,17 +57,6 @@ describe('mediaforce bid adapter', function () { bid.params = {publisher_id: 2, placement_id: '123'}; assert.equal(spec.isBidRequestValid(bid), true); }); - - it('should return false when mediaTypes == native passed (native is not supported yet)', function () { - let bid = utils.deepClone(defaultBid); - bid.mediaTypes = { - native: { - sizes: [[300, 250]] - } - }; - bid.params = {publisher_id: 2, placement_id: '123'}; - assert.equal(spec.isBidRequestValid(bid), true); - }); }); describe('buildRequests()', function () { @@ -76,9 +66,35 @@ describe('mediaforce bid adapter', function () { publisher_id: 'pub123', placement_id: '202', }, + nativeParams: { + title: { + required: true, + len: 800 + }, + image: { + required: true, + sizes: [300, 250], + }, + sponsoredBy: { + required: true + } + }, mediaTypes: { banner: { sizes: [[300, 250]] + }, + native: { + title: { + required: true, + len: 800 + }, + image: { + required: true, + sizes: [300, 250], + }, + sponsoredBy: { + required: true + } } }, transactionId: 'd45dd707-a418-42ec-b8a7-b70a6c6fab0b', @@ -95,7 +111,7 @@ describe('mediaforce bid adapter', function () { const requestUrl = `${baseUrl}/header_bid`; const dnt = utils.getDNT() ? 1 : 0; - const secure = 1 + const secure = 1; it('should return undefined if no validBidRequests passed', function () { assert.equal(spec.buildRequests([]), undefined); @@ -135,13 +151,26 @@ describe('mediaforce bid adapter', function () { secure: secure, bidfloor: bid.params.bidfloor, banner: {w: 300, h: 250}, + native: { + ver: '1.2', + request: { + assets: [ + {id: 1, title: {len: 800}, required: 1}, + {id: 3, img: {w: 300, h: 250, type: 3}, required: 1}, + {id: 5, data: {type: 1}, required: 1} + ], + context: 1, + plcmttype: 1, + ver: '1.2' + } + }, }], }); assert.deepEqual(request, { method: 'POST', url: requestUrl, - data: '{"id":"d45dd707-a418-42ec-b8a7-b70a6c6fab0b","site":{"page":"https%3A%2F%2Fwww.prebid.org","ref":"https%3A%2F%2Fwww.prebid.org","id":"pub123","publisher":{"id":"pub123"}},"device":{"ua":"' + navigator.userAgent + '","js":1,"dnt":' + dnt + ',"language":"' + language + '"},"imp":[{"tagid":"202","secure":1,"bidfloor":0.5,"banner":{"w":300,"h":250}}]}', + data: '{"id":"d45dd707-a418-42ec-b8a7-b70a6c6fab0b","site":{"page":"https%3A%2F%2Fwww.prebid.org","ref":"https%3A%2F%2Fwww.prebid.org","id":"pub123","publisher":{"id":"pub123"}},"device":{"ua":"' + navigator.userAgent + '","js":1,"dnt":' + dnt + ',"language":"' + language + '"},"imp":[{"tagid":"202","secure":1,"bidfloor":0.5,"banner":{"w":300,"h":250},"native":{"ver":"1.2","request":{"assets":[{"required":1,"id":1,"title":{"len":800}},{"required":1,"id":3,"img":{"type":3,"w":300,"h":250}},{"required":1,"id":5,"data":{"type":1}}],"context":1,"plcmttype":1,"ver":"1.2"}}}]}', }); }); @@ -173,6 +202,7 @@ describe('mediaforce bid adapter', function () { cid: '2_ssl', h: 100, cat: ['IAB1-1'], + dealid: '3901521', crid: '2_ssl', impid: '2b3c9d103723a7', adid: '2_ssl', @@ -193,11 +223,13 @@ describe('mediaforce bid adapter', function () { assert.deepEqual(bids, ([{ ad: bid.adm, cpm: bid.price, + dealId: bid.dealid, creativeId: bid.adid, currency: response.body.cur, height: bid.h, netRevenue: true, burl: bid.burl, + mediaType: BANNER, requestId: bid.impid, ttl: 300, width: bid.w, @@ -205,6 +237,174 @@ describe('mediaforce bid adapter', function () { }); }); + describe('interpretResponse() native as object', function () { + it('successfull response', function () { + let titleText = 'Colorado Drivers With No DUI\'s Getting A Pay Day on Friday'; + let imgData = { + url: `${baseUrl}/image`, + w: 1200, + h: 627 + }; + let nativeLink = `${baseUrl}/click/`; + let nativeTracker = `${baseUrl}/imp-image`; + let sponsoredByValue = 'Comparisons.org'; + let bodyValue = 'Drivers With No Tickets In 3 Years Should Do This On June'; + let bid = { + price: 3, + id: '65599d0a-42d2-446a-9d39-6086c1433ffe', + burl: `${baseUrl}/burl/\${AUCTION_PRICE}`, + cid: '2_ssl', + cat: ['IAB1-1'], + crid: '2_ssl', + impid: '2b3c9d103723a7', + adid: '2_ssl', + ext: { + advertiser_name: 'MediaForce', + native: { + link: {url: nativeLink}, + assets: [{ + id: 1, + title: {text: titleText}, + required: 1 + }, { + id: 3, + img: imgData + }, { + id: 5, + data: {value: sponsoredByValue} + }, { + id: 4, + data: {value: bodyValue} + }], + imptrackers: [nativeTracker], + ver: '1' + }, + language: 'en', + agency_name: 'MediaForce DSP' + } + }; + + let response = { + body: { + seatbid: [{ + bid: [bid] + }], + cur: 'USD', + id: '620190c2-7eef-42fa-91e2-f5c7fbc2bdd3' + } + }; + + let bids = spec.interpretResponse(response); + assert.deepEqual(bids, ([{ + native: { + clickUrl: nativeLink, + clickTrackers: [], + impressionTrackers: [nativeTracker], + javascriptTrackers: [], + title: titleText, + image: { + url: imgData.url, + width: imgData.w, + height: imgData.h + }, + sponsoredBy: sponsoredByValue, + body: bodyValue + }, + cpm: bid.price, + creativeId: bid.adid, + currency: response.body.cur, + netRevenue: true, + burl: bid.burl, + mediaType: NATIVE, + requestId: bid.impid, + ttl: 300, + }])); + }); + }); + + describe('interpretResponse() native as string', function () { + it('successfull response', function () { + let titleText = 'Colorado Drivers With No DUI\'s Getting A Pay Day on Friday'; + let imgData = { + url: `${baseUrl}/image`, + w: 1200, + h: 627 + }; + let nativeLink = `${baseUrl}/click/`; + let nativeTracker = `${baseUrl}/imp-image`; + let sponsoredByValue = 'Comparisons.org'; + let bodyValue = 'Drivers With No Tickets In 3 Years Should Do This On June'; + let adm = JSON.stringify({ + native: { + link: {url: nativeLink}, + assets: [{ + id: 1, + title: {text: titleText}, + required: 1 + }, { + id: 3, + img: imgData + }, { + id: 5, + data: {value: sponsoredByValue} + }, { + id: 4, + data: {value: bodyValue} + }], + imptrackers: [nativeTracker], + ver: '1' + } + }); + let bid = { + price: 3, + id: '65599d0a-42d2-446a-9d39-6086c1433ffe', + burl: `${baseUrl}/burl/\${AUCTION_PRICE}`, + cid: '2_ssl', + cat: ['IAB1-1'], + crid: '2_ssl', + impid: '2b3c9d103723a7', + adid: '2_ssl', + adm: adm + }; + + let response = { + body: { + seatbid: [{ + bid: [bid] + }], + cur: 'USD', + id: '620190c2-7eef-42fa-91e2-f5c7fbc2bdd3' + } + }; + + let bids = spec.interpretResponse(response); + assert.deepEqual(bids, ([{ + native: { + clickUrl: nativeLink, + clickTrackers: [], + impressionTrackers: [nativeTracker], + javascriptTrackers: [], + title: titleText, + image: { + url: imgData.url, + width: imgData.w, + height: imgData.h + }, + sponsoredBy: sponsoredByValue, + body: bodyValue + }, + cpm: bid.price, + creativeId: bid.adid, + currency: response.body.cur, + netRevenue: true, + burl: bid.burl, + mediaType: NATIVE, + requestId: bid.impid, + ttl: 300, + }])); + }); + }); + describe('onBidWon()', function () { beforeEach(function() { sinon.stub(utils, 'triggerPixel'); From 6a3c4caa92aea0f9858ed7746dde1154ec4aec18 Mon Sep 17 00:00:00 2001 From: Nikolay Sokolov Date: Wed, 22 Jul 2020 13:15:48 +0300 Subject: [PATCH 4/7] Fix test endpoint url for Mediaforce Bid Adapter --- modules/mediaforceBidAdapter.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/mediaforceBidAdapter.js b/modules/mediaforceBidAdapter.js index db8cc11d690..f0ef810d184 100644 --- a/modules/mediaforceBidAdapter.js +++ b/modules/mediaforceBidAdapter.js @@ -4,7 +4,7 @@ import {BANNER, NATIVE} from '../src/mediaTypes.js'; const BIDDER_CODE = 'mediaforce'; const ENDPOINT_URL = 'https://rtb.mfadsrvr.com/header_bid'; -const TEST_ENDPOINT_URL = 'http://staging-gce-sc-2.dorpat.iponweb.net/header_bid?debug_key=abcdefghijklmnop'; +const TEST_ENDPOINT_URL = 'https://rtb.mfadsrvr.com/header_bid?debug_key=abcdefghijklmnop'; const NATIVE_ID_MAP = {}; const NATIVE_PARAMS = { title: { From 833be294f50bc1fd3966c02f1aec94a81089bfcb Mon Sep 17 00:00:00 2001 From: Nikolay Sokolov Date: Wed, 22 Jul 2020 15:32:28 +0300 Subject: [PATCH 5/7] cleanup --- modules/mediaforceBidAdapter.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/modules/mediaforceBidAdapter.js b/modules/mediaforceBidAdapter.js index f0ef810d184..7e5c06b1b48 100644 --- a/modules/mediaforceBidAdapter.js +++ b/modules/mediaforceBidAdapter.js @@ -82,6 +82,7 @@ const NATIVE_PARAMS = { type: 8 } }; + Object.keys(NATIVE_PARAMS).forEach((key) => { NATIVE_ID_MAP[NATIVE_PARAMS[key].id] = key; }); @@ -236,7 +237,8 @@ export const spec = { utils.triggerPixel(bid.burl); } }, -} +}; + registerBidder(spec); function getLanguage() { @@ -267,6 +269,7 @@ function parseNative(native) { impressionTrackers: imptrackers || [], javascriptTrackers: jstracker ? [jstracker] : [] }; + (assets || []).forEach((asset) => { const {id, img, data, title} = asset; const key = NATIVE_ID_MAP[id]; From 21173a94eb6d3f713a2111494f1743ddb9f7ad62 Mon Sep 17 00:00:00 2001 From: Nikolay Sokolov Date: Wed, 7 Oct 2020 18:12:52 +0300 Subject: [PATCH 6/7] Added the ability to send multiple bids in one ad request for mediaforce bid adapter --- modules/mediaforceBidAdapter.js | 76 +++++--- .../spec/modules/mediaforceBidAdapter_spec.js | 164 +++++++++++++++++- 2 files changed, 212 insertions(+), 28 deletions(-) diff --git a/modules/mediaforceBidAdapter.js b/modules/mediaforceBidAdapter.js index 7e5c06b1b48..eda77d4debe 100644 --- a/modules/mediaforceBidAdapter.js +++ b/modules/mediaforceBidAdapter.js @@ -114,18 +114,28 @@ export const spec = { } const referer = bidderRequest && bidderRequest.refererInfo ? encodeURIComponent(bidderRequest.refererInfo.referer) : ''; + const auctionId = bidderRequest && bidderRequest.auctionId; + const timeout = bidderRequest && bidderRequest.timeout; const dnt = utils.getDNT() ? 1 : 0; - let requests = []; + const requestsMap = {}; + const requests = []; + let isTest = false; validBidRequests.forEach(bid => { + isTest = isTest || bid.params.is_test; let tagid = bid.params.placement_id; let bidfloor = bid.params.bidfloor ? parseFloat(bid.params.bidfloor) : 0; - let imp = []; let validImp = false; let impObj = { id: bid.bidId, tagid: tagid, secure: 1, bidfloor: bidfloor, + ext: { + mediaforce: { + transactionId: bid.transactionId + } + } + }; for (let mediaTypes in bid.mediaTypes) { switch (mediaTypes) { @@ -140,31 +150,47 @@ export const spec = { default: return; } } - validImp && imp.push(impObj); - let request = { - id: bid.transactionId, - site: { - page: referer, - ref: referer, - id: bid.params.publisher_id, - publisher: { - id: bid.params.publisher_id + let request = requestsMap[bid.params.publisher_id]; + if (!request) { + request = { + id: Math.round(Math.random() * 1e16).toString(16), + site: { + page: referer, + ref: referer, + id: bid.params.publisher_id, + publisher: { + id: bid.params.publisher_id + }, }, - }, - device: { - ua: navigator.userAgent, - js: 1, - dnt: dnt, - language: getLanguage() - }, - imp - }; - requests.push({ - method: 'POST', - url: bid.params.is_test ? TEST_ENDPOINT_URL : ENDPOINT_URL, - data: JSON.stringify(request) - }); + device: { + ua: navigator.userAgent, + js: 1, + dnt: dnt, + language: getLanguage() + }, + ext: { + mediaforce: { + hb_key: auctionId + } + }, + tmax: timeout, + imp: [] + }; + requestsMap[bid.params.publisher_id] = request; + requests.push({ + method: 'POST', + url: ENDPOINT_URL, + data: request + }); + } + validImp && request.imp.push(impObj); + }); + requests.forEach((req) => { + if (isTest) { + req.url = TEST_ENDPOINT_URL; + } + req.data = JSON.stringify(req.data); }); return requests; }, diff --git a/test/spec/modules/mediaforceBidAdapter_spec.js b/test/spec/modules/mediaforceBidAdapter_spec.js index ee478acbc83..de4acf5bc0a 100644 --- a/test/spec/modules/mediaforceBidAdapter_spec.js +++ b/test/spec/modules/mediaforceBidAdapter_spec.js @@ -100,6 +100,37 @@ describe('mediaforce bid adapter', function () { transactionId: 'd45dd707-a418-42ec-b8a7-b70a6c6fab0b', }; + const multiBid = [ + { + publisher_id: 'pub123', + placement_id: '202', + }, + { + publisher_id: 'pub123', + placement_id: '203', + }, + { + publisher_id: 'pub124', + placement_id: '202', + }, + { + publisher_id: 'pub123', + placement_id: '203', + transactionId: '8df76688-1618-417a-87b1-60ad046841c9' + } + ].map(({publisher_id, placement_id, transactionId}) => { + return { + bidder: 'mediaforce', + params: {publisher_id, placement_id}, + mediaTypes: { + banner: { + sizes: [[300, 250], [600, 400]] + } + }, + transactionId: transactionId || 'd45dd707-a418-42ec-b8a7-b70a6c6fab0b' + } + }); + const refererInfo = { referer: 'https://www.prebid.org', reachedTop: true, @@ -112,6 +143,7 @@ describe('mediaforce bid adapter', function () { const requestUrl = `${baseUrl}/header_bid`; const dnt = utils.getDNT() ? 1 : 0; const secure = 1; + const timeout = 1500; it('should return undefined if no validBidRequests passed', function () { assert.equal(spec.buildRequests([]), undefined); @@ -127,13 +159,24 @@ describe('mediaforce bid adapter', function () { bid.params.bidfloor = 0.5; let bidRequests = [bid]; - let bidderRequest = {bids: bidRequests, refererInfo: refererInfo}; + let bidderRequest = { + bids: bidRequests, + refererInfo: refererInfo, + timeout: timeout, + auctionId: '210a474e-88f0-4646-837f-4253b7cf14fb' + }; let [request] = spec.buildRequests(bidRequests, bidderRequest); let data = JSON.parse(request.data); assert.deepEqual(data, { - id: bid.transactionId, + id: data.id, + tmax: timeout, + ext: { + mediaforce: { + hb_key: bidderRequest.auctionId + } + }, site: { id: bid.params.publisher_id, publisher: {id: bid.params.publisher_id}, @@ -150,6 +193,11 @@ describe('mediaforce bid adapter', function () { tagid: bid.params.placement_id, secure: secure, bidfloor: bid.params.bidfloor, + ext: { + mediaforce: { + transactionId: bid.transactionId + } + }, banner: {w: 300, h: 250}, native: { ver: '1.2', @@ -170,7 +218,7 @@ describe('mediaforce bid adapter', function () { assert.deepEqual(request, { method: 'POST', url: requestUrl, - data: '{"id":"d45dd707-a418-42ec-b8a7-b70a6c6fab0b","site":{"page":"https%3A%2F%2Fwww.prebid.org","ref":"https%3A%2F%2Fwww.prebid.org","id":"pub123","publisher":{"id":"pub123"}},"device":{"ua":"' + navigator.userAgent + '","js":1,"dnt":' + dnt + ',"language":"' + language + '"},"imp":[{"tagid":"202","secure":1,"bidfloor":0.5,"banner":{"w":300,"h":250},"native":{"ver":"1.2","request":{"assets":[{"required":1,"id":1,"title":{"len":800}},{"required":1,"id":3,"img":{"type":3,"w":300,"h":250}},{"required":1,"id":5,"data":{"type":1}}],"context":1,"plcmttype":1,"ver":"1.2"}}}]}', + data: '{"id":"' + data.id + '","site":{"page":"https%3A%2F%2Fwww.prebid.org","ref":"https%3A%2F%2Fwww.prebid.org","id":"pub123","publisher":{"id":"pub123"}},"device":{"ua":"' + navigator.userAgent + '","js":1,"dnt":' + dnt + ',"language":"' + language + '"},"ext":{"mediaforce":{"hb_key":"210a474e-88f0-4646-837f-4253b7cf14fb"}},"tmax":1500,"imp":[{"tagid":"202","secure":1,"bidfloor":0.5,"ext":{"mediaforce":{"transactionId":"d45dd707-a418-42ec-b8a7-b70a6c6fab0b"}},"banner":{"w":300,"h":250},"native":{"ver":"1.2","request":{"assets":[{"required":1,"id":1,"title":{"len":800}},{"required":1,"id":3,"img":{"type":3,"w":300,"h":250}},{"required":1,"id":5,"data":{"type":1}}],"context":1,"plcmttype":1,"ver":"1.2"}}}]}', }); }); @@ -186,6 +234,116 @@ describe('mediaforce bid adapter', function () { let data = JSON.parse(request.data); assert.deepEqual(data.imp[0].banner, {w: 300, h: 600, format: [{w: 300, h: 250}]}); }); + + it('should return proper requests for multiple imps', function () { + let bidderRequest = { + bids: multiBid, + refererInfo: refererInfo, + timeout: timeout, + auctionId: '210a474e-88f0-4646-837f-4253b7cf14fb' + }; + + let requests = spec.buildRequests(multiBid, bidderRequest); + assert.equal(requests.length, 2); + requests.forEach((req) => { + req.data = JSON.parse(req.data); + }); + + assert.deepEqual(requests, [ + { + method: 'POST', + url: requestUrl, + data: { + id: requests[0].data.id, + tmax: timeout, + ext: { + mediaforce: { + hb_key: bidderRequest.auctionId + } + }, + site: { + id: 'pub123', + publisher: {id: 'pub123'}, + ref: encodeURIComponent(refererInfo.referer), + page: encodeURIComponent(refererInfo.referer), + }, + device: { + ua: navigator.userAgent, + dnt: dnt, + js: 1, + language: language, + }, + imp: [{ + tagid: '202', + secure: secure, + bidfloor: 0, + ext: { + mediaforce: { + transactionId: 'd45dd707-a418-42ec-b8a7-b70a6c6fab0b' + } + }, + banner: {w: 300, h: 250, format: [{w: 600, h: 400}]}, + }, { + tagid: '203', + secure: secure, + bidfloor: 0, + ext: { + mediaforce: { + transactionId: 'd45dd707-a418-42ec-b8a7-b70a6c6fab0b' + } + }, + banner: {w: 300, h: 250, format: [{w: 600, h: 400}]}, + }, { + tagid: '203', + secure: secure, + bidfloor: 0, + ext: { + mediaforce: { + transactionId: '8df76688-1618-417a-87b1-60ad046841c9' + } + }, + banner: {w: 300, h: 250, format: [{w: 600, h: 400}]}, + }] + } + }, + { + method: 'POST', + url: requestUrl, + data: { + id: requests[1].data.id, + tmax: timeout, + ext: { + mediaforce: { + hb_key: bidderRequest.auctionId + } + }, + site: { + id: 'pub124', + publisher: {id: 'pub124'}, + ref: encodeURIComponent(refererInfo.referer), + page: encodeURIComponent(refererInfo.referer), + }, + device: { + ua: navigator.userAgent, + dnt: dnt, + js: 1, + language: language, + }, + imp: [{ + tagid: '202', + secure: secure, + bidfloor: 0, + ext: { + mediaforce: { + transactionId: 'd45dd707-a418-42ec-b8a7-b70a6c6fab0b' + } + }, + banner: {w: 300, h: 250, format: [{w: 600, h: 400}]}, + }] + } + } + ]); + }); }); describe('interpretResponse() banner', function () { From aa88b62b180811243c60b5304cd4afdeb6d48acb Mon Sep 17 00:00:00 2001 From: Nikolay Sokolov Date: Fri, 9 Oct 2020 17:48:40 +0300 Subject: [PATCH 7/7] Fixes after review for mediaforce bid adapter --- modules/mediaforceBidAdapter.js | 4 ++-- test/spec/modules/mediaforceBidAdapter_spec.js | 11 ++++++----- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/modules/mediaforceBidAdapter.js b/modules/mediaforceBidAdapter.js index eda77d4debe..7e29bb519b5 100644 --- a/modules/mediaforceBidAdapter.js +++ b/modules/mediaforceBidAdapter.js @@ -128,7 +128,7 @@ export const spec = { let impObj = { id: bid.bidId, tagid: tagid, - secure: 1, + secure: window.location.protocol === 'https' ? 1 : 0, bidfloor: bidfloor, ext: { mediaforce: { @@ -156,7 +156,7 @@ export const spec = { request = { id: Math.round(Math.random() * 1e16).toString(16), site: { - page: referer, + page: window.location.href, ref: referer, id: bid.params.publisher_id, publisher: { diff --git a/test/spec/modules/mediaforceBidAdapter_spec.js b/test/spec/modules/mediaforceBidAdapter_spec.js index de4acf5bc0a..0b3271da770 100644 --- a/test/spec/modules/mediaforceBidAdapter_spec.js +++ b/test/spec/modules/mediaforceBidAdapter_spec.js @@ -142,7 +142,8 @@ describe('mediaforce bid adapter', function () { const requestUrl = `${baseUrl}/header_bid`; const dnt = utils.getDNT() ? 1 : 0; - const secure = 1; + const secure = window.location.protocol === 'https' ? 1 : 0; + const pageUrl = window.location.href; const timeout = 1500; it('should return undefined if no validBidRequests passed', function () { @@ -181,7 +182,7 @@ describe('mediaforce bid adapter', function () { id: bid.params.publisher_id, publisher: {id: bid.params.publisher_id}, ref: encodeURIComponent(refererInfo.referer), - page: encodeURIComponent(refererInfo.referer), + page: pageUrl, }, device: { ua: navigator.userAgent, @@ -218,7 +219,7 @@ describe('mediaforce bid adapter', function () { assert.deepEqual(request, { method: 'POST', url: requestUrl, - data: '{"id":"' + data.id + '","site":{"page":"https%3A%2F%2Fwww.prebid.org","ref":"https%3A%2F%2Fwww.prebid.org","id":"pub123","publisher":{"id":"pub123"}},"device":{"ua":"' + navigator.userAgent + '","js":1,"dnt":' + dnt + ',"language":"' + language + '"},"ext":{"mediaforce":{"hb_key":"210a474e-88f0-4646-837f-4253b7cf14fb"}},"tmax":1500,"imp":[{"tagid":"202","secure":1,"bidfloor":0.5,"ext":{"mediaforce":{"transactionId":"d45dd707-a418-42ec-b8a7-b70a6c6fab0b"}},"banner":{"w":300,"h":250},"native":{"ver":"1.2","request":{"assets":[{"required":1,"id":1,"title":{"len":800}},{"required":1,"id":3,"img":{"type":3,"w":300,"h":250}},{"required":1,"id":5,"data":{"type":1}}],"context":1,"plcmttype":1,"ver":"1.2"}}}]}', + data: '{"id":"' + data.id + '","site":{"page":"' + pageUrl + '","ref":"https%3A%2F%2Fwww.prebid.org","id":"pub123","publisher":{"id":"pub123"}},"device":{"ua":"' + navigator.userAgent + '","js":1,"dnt":' + dnt + ',"language":"' + language + '"},"ext":{"mediaforce":{"hb_key":"210a474e-88f0-4646-837f-4253b7cf14fb"}},"tmax":1500,"imp":[{"tagid":"202","secure":' + secure + ',"bidfloor":0.5,"ext":{"mediaforce":{"transactionId":"d45dd707-a418-42ec-b8a7-b70a6c6fab0b"}},"banner":{"w":300,"h":250},"native":{"ver":"1.2","request":{"assets":[{"required":1,"id":1,"title":{"len":800}},{"required":1,"id":3,"img":{"type":3,"w":300,"h":250}},{"required":1,"id":5,"data":{"type":1}}],"context":1,"plcmttype":1,"ver":"1.2"}}}]}', }); }); @@ -265,7 +266,7 @@ describe('mediaforce bid adapter', function () { id: 'pub123', publisher: {id: 'pub123'}, ref: encodeURIComponent(refererInfo.referer), - page: encodeURIComponent(refererInfo.referer), + page: pageUrl, }, device: { ua: navigator.userAgent, @@ -321,7 +322,7 @@ describe('mediaforce bid adapter', function () { id: 'pub124', publisher: {id: 'pub124'}, ref: encodeURIComponent(refererInfo.referer), - page: encodeURIComponent(refererInfo.referer), + page: pageUrl, }, device: { ua: navigator.userAgent,