From c20da14b5b3f48a18ddee038f5aba0b25ea8cb28 Mon Sep 17 00:00:00 2001 From: goranbozicic Date: Wed, 27 Sep 2017 13:10:12 +0200 Subject: [PATCH 01/12] nanointeractive bid adapter --- modules/nanointeractiveBidAdapter.js | 156 ++++++++++ .../modules/nanointeractiveBidAdapter_spec.js | 273 ++++++++++++++++++ 2 files changed, 429 insertions(+) create mode 100644 modules/nanointeractiveBidAdapter.js create mode 100644 test/spec/modules/nanointeractiveBidAdapter_spec.js diff --git a/modules/nanointeractiveBidAdapter.js b/modules/nanointeractiveBidAdapter.js new file mode 100644 index 00000000000..aacc5e11050 --- /dev/null +++ b/modules/nanointeractiveBidAdapter.js @@ -0,0 +1,156 @@ +import bidfactory from 'src/bidfactory'; +import bidmanager from 'src/bidmanager'; +import * as utils from 'src/utils'; +import { ajax } from 'src/ajax'; +import { STATUS } from 'src/constants'; +import adaptermanager from 'src/adaptermanager'; + +const BIDDER_CODE = 'nanointeractive'; +const ENGINE_BASE_URL = 'https://www.audiencemanager.de/ad?type=js'; + +const SECURITY = 'sec'; +const DATA_PARTNER_ID = 'dpid'; +const DATA_PARTNER_PIXEL_ID = 'pid'; +const ALG = 'a§lg'; +const NQ = 'nq'; +const NQ_NAME = 'name'; +const CATEGORY = 'category'; + +const DEFAULT_ALG = 'ih'; + +const REQUEST_NQ = 'nq[]'; +const REQUEST_SIZE = 'size[]'; +const REQUEST_ALGORITHM = 'alg'; +const REQUEST_HEADER_BIDDING = 'hb'; +const REQUEST_HEADER_BID_ID = 'hbid'; +const REQUEST_DIRECT_CALL = 'dirCall'; + +class NanointeractiveBidAdapter { + constructor() { + this.QUERY_STRING = utils.getTopWindowLocation().href.split('?'); + this.QUERY_PARAMS = this.QUERY_STRING.length > 1 ? this.QUERY_STRING[1].split('&') : []; + } + + callBids(params) { + params.bids.forEach(bid => { + this.timeoutResponse(bid, params.timeout); + this.formatParamsAndCallEngine(bid); + }) + } + + timeoutResponse(bid, timeout) { + setTimeout(() => { + this.addNoBidResponse(bid); + }, timeout) + } + + formatParamsAndCallEngine(bid) { + const sec = bid.params[SECURITY]; + const dpid = bid.params[DATA_PARTNER_ID]; + const pid = bid.params[DATA_PARTNER_PIXEL_ID]; + const nq = bid.params[NQ_NAME] ? this.getQueryParam(bid.params[NQ_NAME]) : bid.params[NQ] || ''; + const alg = bid.params[ALG] || DEFAULT_ALG; + const category = bid.params[CATEGORY]; + + const sizes = bid.sizes.map(value => value[0] + 'x' + value[1]); + + if (!sec || !dpid || !pid) { + utils.logError('Required params are missing', bid); + this.addNoBidResponse(bid); + } else { + this.callEngine(sec, dpid, pid, nq, alg, category, sizes, bid); + } + } + + callEngine(sec, dpid, pid, nq, alg, category, sizes, bid) { + ajax( + this.getEndpoint(sec, dpid, pid, nq, alg, category, sizes, bid.bidId), + { + success: response => this.successCallback(bid, response), + error: err => this.handleEngineResponseError(bid, err) + } + ); + } + + getQueryParam(nq) { + for (let i = 0; i < this.QUERY_PARAMS.length; i++) { + const pair = this.QUERY_PARAMS[i].split('='); + if (pair[0] === nq) { + return decodeURIComponent(pair[1]) || null; + } + } + return null; + }; + + getEndpoint(sec, dpid, pid, nq, alg, category, sizes, bidId) { + return ENGINE_BASE_URL + + '&' + SECURITY + '=' + sec + + '&' + DATA_PARTNER_ID + '=' + dpid + + '&' + DATA_PARTNER_PIXEL_ID + '=' + pid + + this.formatSizes(sizes) + + '&' + REQUEST_NQ + '=' + nq + + '&' + REQUEST_ALGORITHM + '=' + alg + + this.formatCategory(category) + + '&' + REQUEST_HEADER_BIDDING + '=' + true + + '&' + REQUEST_HEADER_BID_ID + '=' + bidId + + '&' + REQUEST_DIRECT_CALL + '=' + 1 + } + + formatSizes(sizes) { + let sizesFormatted = ''; + for (let i = 0; i < sizes.length; i++) { + sizesFormatted += '&' + REQUEST_SIZE + '=' + sizes[i]; + } + return sizesFormatted; + } + + formatCategory(category) { + return category ? '&nq=' + category : '' + } + + successCallback(bid, response) { + try { + response = JSON.parse(response); + this.handleEngineResponse(bid, response); + } catch (err) { + this.handleEngineResponseError(bid, err); + } + } + + handleEngineResponse(bid, response) { + if (this.isEngineResponseValid(response) === true) { + this.addBidResponse(bid, response); + } else { + this.addNoBidResponse(bid); + } + } + + handleEngineResponseError(bid, error) { + utils.logError('Bid Response Error', bid, error); + this.addNoBidResponse(bid); + } + + isEngineResponseValid(response) { + return !!response.cpm && !!response.ad; + } + + addBidResponse(bid, response) { + let bidResponse = bidfactory.createBid(STATUS.GOOD, {bidId: bid.bidId}); + bidResponse.cpm = response.cpm; + bidResponse.ad = response.ad; + bidResponse.width = response.width; + bidResponse.height = response.height; + bidResponse.bidderCode = BIDDER_CODE; + bidmanager.addBidResponse(bid.placementCode, bidResponse); + } + + addNoBidResponse(bid) { + let bidResponse = bidfactory.createBid(STATUS.NO_BID, bid); + bidResponse.bidderCode = BIDDER_CODE; + bidmanager.addBidResponse(bid.placementCode, bidResponse); + } +} + +adaptermanager.registerBidAdapter(new NanointeractiveBidAdapter(), BIDDER_CODE); + +module.exports = NanointeractiveBidAdapter; diff --git a/test/spec/modules/nanointeractiveBidAdapter_spec.js b/test/spec/modules/nanointeractiveBidAdapter_spec.js new file mode 100644 index 00000000000..1904b8dd90c --- /dev/null +++ b/test/spec/modules/nanointeractiveBidAdapter_spec.js @@ -0,0 +1,273 @@ +import { expect } from 'chai'; +import bidmanager from 'src/bidmanager'; +import * as utils from 'src/utils'; +import NanointeractiveBidAdapter from 'modules/nanointeractiveBidAdapter'; +import * as ajax from 'src/ajax'; +import CONSTANTS from 'src/constants.json'; + +describe('nanointeractive adapter tests', function () { + const BIDDER_CODE = 'nanointeractive'; + const SEARCH_QUERY = 'rumpelstiltskin'; + const WIDTH = 300; + const HEIGHT = 250; + const SIZES = [[WIDTH, HEIGHT]]; + const AD = ' '; + const CPM = 1; + + const REQUEST = function (secParam, nameParam, nqParam) { + return { + bidderCode: BIDDER_CODE, + requestId: 'ac15bb68-4ef0-477f-93f4-de91c47f00a9', + bidderRequestId: '189135372acd55', + bids: [ + { + bidder: BIDDER_CODE, + params: (function () { + return { + sec: secParam === true ? 'sec1' : null, + dpid: 'dpid1', + pid: 'pid1', + nq: nqParam === false ? null : SEARCH_QUERY, + name: nameParam === true ? 'nq' : null + } + })(), + placementCode: 'div-gpt-ad-1460505748561-0', + transactionId: 'ee335735-ddd3-41f2-b6c6-e8aa99f81c0f', + sizes: SIZES, + bidId: '24a1c9ec270973', + bidderRequestId: '189135372acd55', + requestId: 'ac15bb68-4ef0-477f-93f4-de91c47f00a9' + } + ], + start: 1503482467787, + auctionStart: 1503482467785, + timeout: 3000 + }; + }; + + const VALID_RESPONSE = { + cpm: CPM, + ad: AD, + width: WIDTH, + height: HEIGHT, + bidderCode: BIDDER_CODE, + }; + + const INVALID_RESPONSE = { + cpm: null, + ad: AD, + width: WIDTH, + height: HEIGHT, + bidderCode: BIDDER_CODE, + }; + + function createAjaxSuccessStub(response) { + return sinon.stub(ajax, 'ajax', (url, callbacks) => { + callbacks.success( + JSON.stringify(response) + ); + }); + } + + function createAjaxErrorStub() { + return sinon.stub(ajax, 'ajax', (url, callbacks) => { + callbacks.error('Error'); + }); + } + + describe('NanoAdapter', () => { + let nanoBidAdapter; + let addBidResponse; + + let getTopWindowLocation = sinon.stub(utils, 'getTopWindowLocation'); + getTopWindowLocation.onFirstCall().returns({href: 'test?nq=TEST'}); + getTopWindowLocation.returns({href: 'test'}); + + beforeEach(() => { + addBidResponse = sinon.stub(bidmanager, 'addBidResponse'); + nanoBidAdapter = new NanointeractiveBidAdapter(); + }); + afterEach(() => { + addBidResponse.restore(); + }); + + it('exists and is a function', () => { + expect(nanoBidAdapter.callBids).to.exist.and.to.be.a('function'); + }); + + describe('Params', () => { + it('Test invalid sec params', function () { + let addNoBidResponseSinon = sinon.stub(nanoBidAdapter, 'addNoBidResponse'); + nanoBidAdapter.callBids(REQUEST(false)); + sinon.assert.calledOnce(addNoBidResponseSinon); + }); + + it('Test without nq param', function () { + let callEngineSinon = sinon.stub(nanoBidAdapter, 'callEngine'); + nanoBidAdapter.callBids(REQUEST(true, false, false)); + sinon.assert.calledOnce(callEngineSinon); + }); + + it('Test valid bid params', function () { + let callEngineSinon = sinon.stub(nanoBidAdapter, 'callEngine'); + nanoBidAdapter.callBids(REQUEST(true)); + sinon.assert.calledOnce(callEngineSinon); + }); + + it('Test name bid param', function () { + let getQueryParamSinon = sinon.stub(nanoBidAdapter, 'getQueryParam'); + nanoBidAdapter.callBids(REQUEST(false, true)); + sinon.assert.calledOnce(getQueryParamSinon); + }); + }); + + describe('Methods', () => { + it('Test getQueryParam() with valid param', function () { + nanoBidAdapter.QUERY_PARAMS = ['testParam=TEST2', 'nq=TEST']; + expect(nanoBidAdapter.getQueryParam('nq')).to.equal('TEST') + }); + + it('Test getQueryParam() with invalid param', function () { + nanoBidAdapter.QUERY_PARAMS = ['nq=']; + expect(nanoBidAdapter.getQueryParam('nq')).to.equal(null) + }); + + it('Test getQueryParam() without params', function () { + nanoBidAdapter.QUERY_PARAMS = []; + expect(nanoBidAdapter.getQueryParam('nq')).to.equal(null) + }); + + it('Test getEndpoint() without category', function () { + const endpoint = 'https://www.audiencemanager.de/ad?type=js' + + '&sec=sec1' + + '&dpid=dpid1' + + '&pid=pid1' + + '&size[]=300x250' + + '&size[]=728x90' + + '&nq[]=auto' + + '&alg=r' + + '&hb=true' + + '&hbid=testBidId' + + '&dirCall=1'; + expect(nanoBidAdapter.getEndpoint('sec1', 'dpid1', 'pid1', 'auto', 'r', undefined, ['300x250', '728x90'], 'testBidId')).to.equal(endpoint) + }); + + it('Test getEndpoint() with category', function () { + const endpoint = 'https://www.audiencemanager.de/ad?type=js' + + '&sec=sec1' + + '&dpid=dpid1' + + '&pid=pid1' + + '&size[]=300x250' + + '&size[]=728x90' + + '&nq[]=auto' + + '&alg=r' + + '&nq=AUTO' + + '&hb=true' + + '&hbid=testBidId' + + '&dirCall=1'; + expect(nanoBidAdapter.getEndpoint('sec1', 'dpid1', 'pid1', 'auto', 'r', 'AUTO', ['300x250', '728x90'], 'testBidId')).to.equal(endpoint) + }); + + it('Test formatSizes()', function () { + const sizes = ['300x250', '728x90']; + const sizesFormatted = '&size[]=300x250&size[]=728x90'; + expect(nanoBidAdapter.formatSizes(sizes)).to.equal(sizesFormatted) + }); + + it('Test successCallback() with valid response', function () { + let handleEngineResponseSinon = sinon.stub(nanoBidAdapter, 'handleEngineResponse'); + nanoBidAdapter.successCallback(REQUEST(true).bids[0], JSON.stringify(VALID_RESPONSE)); + sinon.assert.calledOnce(handleEngineResponseSinon); + }); + + it('Test successCallback() with invalid response', function () { + let handleEngineResponseErrorSinon = sinon.stub(nanoBidAdapter, 'handleEngineResponseError'); + nanoBidAdapter.successCallback(REQUEST(true).bids[0], null); + sinon.assert.calledOnce(handleEngineResponseErrorSinon); + }); + + it('Test handleEngineResponse() with valid response', function () { + let addBidResponseSinon = sinon.stub(nanoBidAdapter, 'addBidResponse'); + nanoBidAdapter.handleEngineResponse(REQUEST(true).bids[0], VALID_RESPONSE); + sinon.assert.calledOnce(addBidResponseSinon); + }); + + it('Test handleEngineResponse() with invalid response', function () { + let addNoBidResponseSinon = sinon.stub(nanoBidAdapter, 'addNoBidResponse'); + nanoBidAdapter.handleEngineResponse(REQUEST(true).bids[0], INVALID_RESPONSE); + sinon.assert.calledOnce(addNoBidResponseSinon); + }); + + it('Test handleEngineResponseError()', function () { + let addNoBidResponseSinon = sinon.stub(nanoBidAdapter, 'addNoBidResponse'); + let logErrorSinon = sinon.stub(utils, 'logError'); + nanoBidAdapter.handleEngineResponseError(REQUEST(true).bids[0], 'Error'); + sinon.assert.calledOnce(addNoBidResponseSinon); + sinon.assert.calledOnce(logErrorSinon); + }); + + it('Test isEngineResponseValid() with valid response', function () { + expect(nanoBidAdapter.isEngineResponseValid(VALID_RESPONSE)).to.equal(true); + }); + + it('Test isEngineResponseValid() with invalid response', function () { + expect(nanoBidAdapter.isEngineResponseValid(INVALID_RESPONSE)).to.equal(false); + }); + + it('Test addBidResponse()', function () { + nanoBidAdapter.addBidResponse(REQUEST(true).bids[0], VALID_RESPONSE); + let arg = addBidResponse.firstCall.args[1]; + expect(arg.bidderCode).to.equal(BIDDER_CODE); + expect(arg.width).to.equal(WIDTH); + expect(arg.height).to.equal(HEIGHT); + expect(arg.cpm).to.equal(CPM); + expect(arg.ad).to.equal(AD); + expect(arg.getStatusCode()).to.equal(CONSTANTS.STATUS.GOOD); + }); + + it('Test addNoBidResponse()', function () { + nanoBidAdapter.addNoBidResponse(REQUEST(true).bids[0]); + sinon.assert.calledOnce(addBidResponse); + }); + }); + + describe('Ajax success request', () => { + it('Test success Ajax call', function () { + let stubAjaxSuccess = createAjaxSuccessStub(VALID_RESPONSE); + nanoBidAdapter.callBids(REQUEST(true)); + sinon.assert.calledOnce(stubAjaxSuccess); + stubAjaxSuccess.restore(); + + let arg = addBidResponse.firstCall.args[1]; + expect(arg.bidderCode).to.equal(BIDDER_CODE); + expect(arg.width).to.equal(WIDTH); + expect(arg.height).to.equal(HEIGHT); + expect(arg.cpm).to.equal(CPM); + expect(arg.ad).to.equal(AD); + expect(arg.getStatusCode()).to.equal(CONSTANTS.STATUS.GOOD); + }); + }); + + describe('Ajax error request', () => { + it('Test error Ajax call', function () { + let stubAjaxError = createAjaxErrorStub(); + nanoBidAdapter.callBids(REQUEST(true)); + sinon.assert.calledOnce(stubAjaxError); + stubAjaxError.restore(); + + let arg = addBidResponse.firstCall.args[1]; + expect(arg.getStatusCode()).to.equal(CONSTANTS.STATUS.NO_BID); + }); + }); + + describe('Bid timeout', () => { + it('Test timeout response', function () { + nanoBidAdapter.timeoutResponse(REQUEST(true).bids[0], 0); + setTimeout(() => { + let addNoBidResponseSinon = sinon.stub(nanoBidAdapter, 'addNoBidResponse'); + sinon.assert.calledOnce(addNoBidResponseSinon); + }) + }); + }); + }); +}); From a60630bc29480d4e0af925283c4b2024ad25782f Mon Sep 17 00:00:00 2001 From: goranbozicic Date: Mon, 16 Oct 2017 11:06:39 +0200 Subject: [PATCH 02/12] nanointeractive bid adapter --- modules/nanointeractiveBidAdapter.js | 211 +++++------ .../modules/nanointeractiveBidAdapter_spec.js | 331 +++++------------- 2 files changed, 163 insertions(+), 379 deletions(-) diff --git a/modules/nanointeractiveBidAdapter.js b/modules/nanointeractiveBidAdapter.js index aacc5e11050..f5bae83875c 100644 --- a/modules/nanointeractiveBidAdapter.js +++ b/modules/nanointeractiveBidAdapter.js @@ -1,156 +1,101 @@ -import bidfactory from 'src/bidfactory'; -import bidmanager from 'src/bidmanager'; import * as utils from 'src/utils'; -import { ajax } from 'src/ajax'; -import { STATUS } from 'src/constants'; -import adaptermanager from 'src/adaptermanager'; +import { registerBidder } from '../src/adapters/bidderFactory'; +import { BANNER } from '../src/mediaTypes'; -const BIDDER_CODE = 'nanointeractive'; -const ENGINE_BASE_URL = 'https://www.audiencemanager.de/ad?type=js'; +export const BIDDER_CODE = 'nanointeractive'; +export const ENGINE_BASE_URL = 'http://tmp.audiencemanager.de/hb'; -const SECURITY = 'sec'; -const DATA_PARTNER_ID = 'dpid'; -const DATA_PARTNER_PIXEL_ID = 'pid'; -const ALG = 'a§lg'; -const NQ = 'nq'; -const NQ_NAME = 'name'; -const CATEGORY = 'category'; +export const SECURITY = 'sec'; +export const DATA_PARTNER_ID = 'dpid'; +export const DATA_PARTNER_PIXEL_ID = 'pid'; +export const ALG = 'alg'; +export const NQ = 'nq'; +export const NQ_NAME = 'name'; +export const CATEGORY = 'category'; const DEFAULT_ALG = 'ih'; -const REQUEST_NQ = 'nq[]'; -const REQUEST_SIZE = 'size[]'; -const REQUEST_ALGORITHM = 'alg'; -const REQUEST_HEADER_BIDDING = 'hb'; -const REQUEST_HEADER_BID_ID = 'hbid'; -const REQUEST_DIRECT_CALL = 'dirCall'; +export const spec = { -class NanointeractiveBidAdapter { - constructor() { - this.QUERY_STRING = utils.getTopWindowLocation().href.split('?'); - this.QUERY_PARAMS = this.QUERY_STRING.length > 1 ? this.QUERY_STRING[1].split('&') : []; - } - - callBids(params) { - params.bids.forEach(bid => { - this.timeoutResponse(bid, params.timeout); - this.formatParamsAndCallEngine(bid); - }) - } - - timeoutResponse(bid, timeout) { - setTimeout(() => { - this.addNoBidResponse(bid); - }, timeout) - } + code: BIDDER_CODE, + supportedMediaTypes: [BANNER], - formatParamsAndCallEngine(bid) { + isBidRequestValid(bid) { const sec = bid.params[SECURITY]; const dpid = bid.params[DATA_PARTNER_ID]; const pid = bid.params[DATA_PARTNER_PIXEL_ID]; - const nq = bid.params[NQ_NAME] ? this.getQueryParam(bid.params[NQ_NAME]) : bid.params[NQ] || ''; - const alg = bid.params[ALG] || DEFAULT_ALG; - const category = bid.params[CATEGORY]; - - const sizes = bid.sizes.map(value => value[0] + 'x' + value[1]); - - if (!sec || !dpid || !pid) { - utils.logError('Required params are missing', bid); - this.addNoBidResponse(bid); - } else { - this.callEngine(sec, dpid, pid, nq, alg, category, sizes, bid); - } - } - - callEngine(sec, dpid, pid, nq, alg, category, sizes, bid) { - ajax( - this.getEndpoint(sec, dpid, pid, nq, alg, category, sizes, bid.bidId), - { - success: response => this.successCallback(bid, response), - error: err => this.handleEngineResponseError(bid, err) + return !!(sec && dpid && pid); + }, + buildRequests(bidRequests) { + let payload = []; + bidRequests.forEach(bid => payload.push(createSingleBidRequest(bid))); + return { + method: 'POST', + url: ENGINE_BASE_URL, + data: JSON.stringify(payload) + }; + }, + interpretResponse(serverResponse) { + const bids = []; + serverResponse.forEach(serverBid => { + if (isEngineResponseValid(serverBid)) { + bids.push(createSingleBidResponse(serverBid)); } - ); + }); + return bids; } - - getQueryParam(nq) { - for (let i = 0; i < this.QUERY_PARAMS.length; i++) { - const pair = this.QUERY_PARAMS[i].split('='); - if (pair[0] === nq) { - return decodeURIComponent(pair[1]) || null; - } - } - return null; +}; + +function createSingleBidRequest(bid) { + return { + [SECURITY]: bid.params[SECURITY], + [DATA_PARTNER_ID]: bid.params[DATA_PARTNER_ID], + [DATA_PARTNER_PIXEL_ID]: bid.params[DATA_PARTNER_PIXEL_ID], + [ALG]: bid.params[ALG] || DEFAULT_ALG, + [NQ]: [createNqParam(bid), createCategoryParam(bid)], + sizes: bid.sizes.map(value => value[0] + 'x' + value[1]), + bidId: bid.bidId, + cors: document.domain.includes('localhost') ? null : document.domain }; +} - getEndpoint(sec, dpid, pid, nq, alg, category, sizes, bidId) { - return ENGINE_BASE_URL + - '&' + SECURITY + '=' + sec + - '&' + DATA_PARTNER_ID + '=' + dpid + - '&' + DATA_PARTNER_PIXEL_ID + '=' + pid + - this.formatSizes(sizes) + - '&' + REQUEST_NQ + '=' + nq + - '&' + REQUEST_ALGORITHM + '=' + alg + - this.formatCategory(category) + - '&' + REQUEST_HEADER_BIDDING + '=' + true + - '&' + REQUEST_HEADER_BID_ID + '=' + bidId + - '&' + REQUEST_DIRECT_CALL + '=' + 1 - } - - formatSizes(sizes) { - let sizesFormatted = ''; - for (let i = 0; i < sizes.length; i++) { - sizesFormatted += '&' + REQUEST_SIZE + '=' + sizes[i]; - } - return sizesFormatted; - } +function createSingleBidResponse(serverBid) { + return { + requestId: serverBid.id, + bidderCode: serverBid.bidderCode, + cpm: serverBid.cpm, + width: serverBid.width, + height: serverBid.height, + ad: serverBid.ad, + ttl: serverBid.ttl, + creativeId: serverBid.creativeId, + netRevenue: serverBid.netRevenue || true, + currency: serverBid.currency, + }; +} - formatCategory(category) { - return category ? '&nq=' + category : '' - } +function createNqParam(bid) { + return bid.params[NQ_NAME] ? getQueryParam(bid.params[NQ_NAME]) : bid.params[NQ] || null; +} - successCallback(bid, response) { - try { - response = JSON.parse(response); - this.handleEngineResponse(bid, response); - } catch (err) { - this.handleEngineResponseError(bid, err); - } - } +function createCategoryParam(bid) { + return bid.params[CATEGORY] || null; +} - handleEngineResponse(bid, response) { - if (this.isEngineResponseValid(response) === true) { - this.addBidResponse(bid, response); - } else { - this.addNoBidResponse(bid); +function getQueryParam(nq) { + const queryString = utils.getTopWindowLocation().href.split('?'); + const queryParams = queryString.length > 1 ? queryString[1].split('&') : []; + for (let i = 0; i < queryParams.length; i++) { + const pair = queryParams[i].split('='); + if (pair[0] === nq) { + return decodeURIComponent(pair[1]) || null; } } - - handleEngineResponseError(bid, error) { - utils.logError('Bid Response Error', bid, error); - this.addNoBidResponse(bid); - } - - isEngineResponseValid(response) { - return !!response.cpm && !!response.ad; - } - - addBidResponse(bid, response) { - let bidResponse = bidfactory.createBid(STATUS.GOOD, {bidId: bid.bidId}); - bidResponse.cpm = response.cpm; - bidResponse.ad = response.ad; - bidResponse.width = response.width; - bidResponse.height = response.height; - bidResponse.bidderCode = BIDDER_CODE; - bidmanager.addBidResponse(bid.placementCode, bidResponse); - } - - addNoBidResponse(bid) { - let bidResponse = bidfactory.createBid(STATUS.NO_BID, bid); - bidResponse.bidderCode = BIDDER_CODE; - bidmanager.addBidResponse(bid.placementCode, bidResponse); - } + return null; } -adaptermanager.registerBidAdapter(new NanointeractiveBidAdapter(), BIDDER_CODE); +function isEngineResponseValid(response) { + return !!response.cpm && !!response.ad; +} -module.exports = NanointeractiveBidAdapter; +registerBidder(spec); diff --git a/test/spec/modules/nanointeractiveBidAdapter_spec.js b/test/spec/modules/nanointeractiveBidAdapter_spec.js index 1904b8dd90c..59ddcc08b5d 100644 --- a/test/spec/modules/nanointeractiveBidAdapter_spec.js +++ b/test/spec/modules/nanointeractiveBidAdapter_spec.js @@ -1,12 +1,11 @@ import { expect } from 'chai'; -import bidmanager from 'src/bidmanager'; -import * as utils from 'src/utils'; -import NanointeractiveBidAdapter from 'modules/nanointeractiveBidAdapter'; -import * as ajax from 'src/ajax'; -import CONSTANTS from 'src/constants.json'; +import { + ALG, + BIDDER_CODE, CATEGORY, DATA_PARTNER_ID, DATA_PARTNER_PIXEL_ID, ENGINE_BASE_URL, NQ, NQ_NAME, SECURITY, + spec +} from '../../../modules/nanointeractiveBidAdapter'; describe('nanointeractive adapter tests', function () { - const BIDDER_CODE = 'nanointeractive'; const SEARCH_QUERY = 'rumpelstiltskin'; const WIDTH = 300; const HEIGHT = 250; @@ -14,259 +13,99 @@ describe('nanointeractive adapter tests', function () { const AD = ' '; const CPM = 1; - const REQUEST = function (secParam, nameParam, nqParam) { + function getBid(isValid) { return { - bidderCode: BIDDER_CODE, - requestId: 'ac15bb68-4ef0-477f-93f4-de91c47f00a9', - bidderRequestId: '189135372acd55', - bids: [ - { - bidder: BIDDER_CODE, - params: (function () { - return { - sec: secParam === true ? 'sec1' : null, - dpid: 'dpid1', - pid: 'pid1', - nq: nqParam === false ? null : SEARCH_QUERY, - name: nameParam === true ? 'nq' : null - } - })(), - placementCode: 'div-gpt-ad-1460505748561-0', - transactionId: 'ee335735-ddd3-41f2-b6c6-e8aa99f81c0f', - sizes: SIZES, - bidId: '24a1c9ec270973', - bidderRequestId: '189135372acd55', - requestId: 'ac15bb68-4ef0-477f-93f4-de91c47f00a9' + bidder: BIDDER_CODE, + params: (function () { + return { + [SECURITY]: isValid === true ? 'sec1' : null, + [DATA_PARTNER_ID]: 'dpid1', + [DATA_PARTNER_PIXEL_ID]: 'pid1', + [ALG]: 'ih', + [NQ]: SEARCH_QUERY, + [NQ_NAME]: null, + [CATEGORY]: null, } - ], - start: 1503482467787, - auctionStart: 1503482467785, - timeout: 3000 - }; + })(), + placementCode: 'div-gpt-ad-1460505748561-0', + transactionId: 'ee335735-ddd3-41f2-b6c6-e8aa99f81c0f', + sizes: SIZES, + bidId: '24a1c9ec270973', + bidderRequestId: '189135372acd55', + requestId: 'ac15bb68-4ef0-477f-93f4-de91c47f00a9' + } + } + + const SINGlE_BID_REQUEST = { + [SECURITY]: 'sec1', + [DATA_PARTNER_ID]: 'dpid1', + [DATA_PARTNER_PIXEL_ID]: 'pid1', + [ALG]: 'ih', + [NQ]: [SEARCH_QUERY, null], + sizes: [WIDTH + 'x' + HEIGHT], + bidId: '24a1c9ec270973', + cors: null }; - const VALID_RESPONSE = { + function getSingleBidResponse(isValid) { + return { + id: '24a1c9ec270973', + bidderCode: spec.code, + cpm: isValid === true ? CPM : null, + width: WIDTH, + height: HEIGHT, + ad: AD, + ttl: 360, + creativeId: 'TEST_ID', + netRevenue: false, + currency: 'EUR', + } + } + + const VALID_BID = { + requestId: '24a1c9ec270973', + bidderCode: spec.code, cpm: CPM, - ad: AD, width: WIDTH, height: HEIGHT, - bidderCode: BIDDER_CODE, - }; - - const INVALID_RESPONSE = { - cpm: null, ad: AD, - width: WIDTH, - height: HEIGHT, - bidderCode: BIDDER_CODE, + ttl: 360, + creativeId: 'TEST_ID', + netRevenue: false, + currency: 'EUR', }; - function createAjaxSuccessStub(response) { - return sinon.stub(ajax, 'ajax', (url, callbacks) => { - callbacks.success( - JSON.stringify(response) - ); - }); - } - - function createAjaxErrorStub() { - return sinon.stub(ajax, 'ajax', (url, callbacks) => { - callbacks.error('Error'); - }); - } - describe('NanoAdapter', () => { - let nanoBidAdapter; - let addBidResponse; - - let getTopWindowLocation = sinon.stub(utils, 'getTopWindowLocation'); - getTopWindowLocation.onFirstCall().returns({href: 'test?nq=TEST'}); - getTopWindowLocation.returns({href: 'test'}); - - beforeEach(() => { - addBidResponse = sinon.stub(bidmanager, 'addBidResponse'); - nanoBidAdapter = new NanointeractiveBidAdapter(); - }); - afterEach(() => { - addBidResponse.restore(); - }); - - it('exists and is a function', () => { - expect(nanoBidAdapter.callBids).to.exist.and.to.be.a('function'); - }); - - describe('Params', () => { - it('Test invalid sec params', function () { - let addNoBidResponseSinon = sinon.stub(nanoBidAdapter, 'addNoBidResponse'); - nanoBidAdapter.callBids(REQUEST(false)); - sinon.assert.calledOnce(addNoBidResponseSinon); - }); - - it('Test without nq param', function () { - let callEngineSinon = sinon.stub(nanoBidAdapter, 'callEngine'); - nanoBidAdapter.callBids(REQUEST(true, false, false)); - sinon.assert.calledOnce(callEngineSinon); - }); - - it('Test valid bid params', function () { - let callEngineSinon = sinon.stub(nanoBidAdapter, 'callEngine'); - nanoBidAdapter.callBids(REQUEST(true)); - sinon.assert.calledOnce(callEngineSinon); - }); - - it('Test name bid param', function () { - let getQueryParamSinon = sinon.stub(nanoBidAdapter, 'getQueryParam'); - nanoBidAdapter.callBids(REQUEST(false, true)); - sinon.assert.calledOnce(getQueryParamSinon); - }); - }); + let nanoBidAdapter = spec; describe('Methods', () => { - it('Test getQueryParam() with valid param', function () { - nanoBidAdapter.QUERY_PARAMS = ['testParam=TEST2', 'nq=TEST']; - expect(nanoBidAdapter.getQueryParam('nq')).to.equal('TEST') - }); - - it('Test getQueryParam() with invalid param', function () { - nanoBidAdapter.QUERY_PARAMS = ['nq=']; - expect(nanoBidAdapter.getQueryParam('nq')).to.equal(null) - }); - - it('Test getQueryParam() without params', function () { - nanoBidAdapter.QUERY_PARAMS = []; - expect(nanoBidAdapter.getQueryParam('nq')).to.equal(null) - }); - - it('Test getEndpoint() without category', function () { - const endpoint = 'https://www.audiencemanager.de/ad?type=js' + - '&sec=sec1' + - '&dpid=dpid1' + - '&pid=pid1' + - '&size[]=300x250' + - '&size[]=728x90' + - '&nq[]=auto' + - '&alg=r' + - '&hb=true' + - '&hbid=testBidId' + - '&dirCall=1'; - expect(nanoBidAdapter.getEndpoint('sec1', 'dpid1', 'pid1', 'auto', 'r', undefined, ['300x250', '728x90'], 'testBidId')).to.equal(endpoint) - }); - - it('Test getEndpoint() with category', function () { - const endpoint = 'https://www.audiencemanager.de/ad?type=js' + - '&sec=sec1' + - '&dpid=dpid1' + - '&pid=pid1' + - '&size[]=300x250' + - '&size[]=728x90' + - '&nq[]=auto' + - '&alg=r' + - '&nq=AUTO' + - '&hb=true' + - '&hbid=testBidId' + - '&dirCall=1'; - expect(nanoBidAdapter.getEndpoint('sec1', 'dpid1', 'pid1', 'auto', 'r', 'AUTO', ['300x250', '728x90'], 'testBidId')).to.equal(endpoint) - }); - - it('Test formatSizes()', function () { - const sizes = ['300x250', '728x90']; - const sizesFormatted = '&size[]=300x250&size[]=728x90'; - expect(nanoBidAdapter.formatSizes(sizes)).to.equal(sizesFormatted) - }); - - it('Test successCallback() with valid response', function () { - let handleEngineResponseSinon = sinon.stub(nanoBidAdapter, 'handleEngineResponse'); - nanoBidAdapter.successCallback(REQUEST(true).bids[0], JSON.stringify(VALID_RESPONSE)); - sinon.assert.calledOnce(handleEngineResponseSinon); - }); - - it('Test successCallback() with invalid response', function () { - let handleEngineResponseErrorSinon = sinon.stub(nanoBidAdapter, 'handleEngineResponseError'); - nanoBidAdapter.successCallback(REQUEST(true).bids[0], null); - sinon.assert.calledOnce(handleEngineResponseErrorSinon); - }); - - it('Test handleEngineResponse() with valid response', function () { - let addBidResponseSinon = sinon.stub(nanoBidAdapter, 'addBidResponse'); - nanoBidAdapter.handleEngineResponse(REQUEST(true).bids[0], VALID_RESPONSE); - sinon.assert.calledOnce(addBidResponseSinon); - }); - - it('Test handleEngineResponse() with invalid response', function () { - let addNoBidResponseSinon = sinon.stub(nanoBidAdapter, 'addNoBidResponse'); - nanoBidAdapter.handleEngineResponse(REQUEST(true).bids[0], INVALID_RESPONSE); - sinon.assert.calledOnce(addNoBidResponseSinon); - }); - - it('Test handleEngineResponseError()', function () { - let addNoBidResponseSinon = sinon.stub(nanoBidAdapter, 'addNoBidResponse'); - let logErrorSinon = sinon.stub(utils, 'logError'); - nanoBidAdapter.handleEngineResponseError(REQUEST(true).bids[0], 'Error'); - sinon.assert.calledOnce(addNoBidResponseSinon); - sinon.assert.calledOnce(logErrorSinon); - }); - - it('Test isEngineResponseValid() with valid response', function () { - expect(nanoBidAdapter.isEngineResponseValid(VALID_RESPONSE)).to.equal(true); - }); - - it('Test isEngineResponseValid() with invalid response', function () { - expect(nanoBidAdapter.isEngineResponseValid(INVALID_RESPONSE)).to.equal(false); - }); - - it('Test addBidResponse()', function () { - nanoBidAdapter.addBidResponse(REQUEST(true).bids[0], VALID_RESPONSE); - let arg = addBidResponse.firstCall.args[1]; - expect(arg.bidderCode).to.equal(BIDDER_CODE); - expect(arg.width).to.equal(WIDTH); - expect(arg.height).to.equal(HEIGHT); - expect(arg.cpm).to.equal(CPM); - expect(arg.ad).to.equal(AD); - expect(arg.getStatusCode()).to.equal(CONSTANTS.STATUS.GOOD); - }); - - it('Test addNoBidResponse()', function () { - nanoBidAdapter.addNoBidResponse(REQUEST(true).bids[0]); - sinon.assert.calledOnce(addBidResponse); - }); - }); - - describe('Ajax success request', () => { - it('Test success Ajax call', function () { - let stubAjaxSuccess = createAjaxSuccessStub(VALID_RESPONSE); - nanoBidAdapter.callBids(REQUEST(true)); - sinon.assert.calledOnce(stubAjaxSuccess); - stubAjaxSuccess.restore(); - - let arg = addBidResponse.firstCall.args[1]; - expect(arg.bidderCode).to.equal(BIDDER_CODE); - expect(arg.width).to.equal(WIDTH); - expect(arg.height).to.equal(HEIGHT); - expect(arg.cpm).to.equal(CPM); - expect(arg.ad).to.equal(AD); - expect(arg.getStatusCode()).to.equal(CONSTANTS.STATUS.GOOD); - }); - }); - - describe('Ajax error request', () => { - it('Test error Ajax call', function () { - let stubAjaxError = createAjaxErrorStub(); - nanoBidAdapter.callBids(REQUEST(true)); - sinon.assert.calledOnce(stubAjaxError); - stubAjaxError.restore(); - - let arg = addBidResponse.firstCall.args[1]; - expect(arg.getStatusCode()).to.equal(CONSTANTS.STATUS.NO_BID); - }); - }); - - describe('Bid timeout', () => { - it('Test timeout response', function () { - nanoBidAdapter.timeoutResponse(REQUEST(true).bids[0], 0); - setTimeout(() => { - let addNoBidResponseSinon = sinon.stub(nanoBidAdapter, 'addNoBidResponse'); - sinon.assert.calledOnce(addNoBidResponseSinon); - }) + it('Test isBidRequestValid() with valid param', function () { + expect(nanoBidAdapter.isBidRequestValid(getBid(true))).to.equal(true); + }); + it('Test isBidRequestValid() with invalid param', function () { + expect(nanoBidAdapter.isBidRequestValid(getBid(false))).to.equal(false); + }); + it('Test buildRequests()', function () { + let request = nanoBidAdapter.buildRequests([getBid(true)]); + expect(request.method).to.equal('POST'); + expect(request.url).to.equal(ENGINE_BASE_URL); + expect(request.data).to.equal(JSON.stringify([SINGlE_BID_REQUEST])); + }); + it('Test interpretResponse() length', function () { + let bids = nanoBidAdapter.interpretResponse([getSingleBidResponse(true), getSingleBidResponse(false)]); + expect(bids.length).to.equal(1); + }); + it('Test interpretResponse() bids', function () { + let bid = nanoBidAdapter.interpretResponse([getSingleBidResponse(true), getSingleBidResponse(false)])[0]; + expect(bid.requestId).to.equal(VALID_BID.requestId); + expect(bid.bidderCode).to.equal(VALID_BID.bidderCode); + expect(bid.cpm).to.equal(VALID_BID.cpm); + expect(bid.width).to.equal(VALID_BID.width); + expect(bid.height).to.equal(VALID_BID.height); + expect(bid.ad).to.equal(VALID_BID.ad); + expect(bid.ttl).to.equal(VALID_BID.ttl); + expect(bid.creativeId).to.equal(VALID_BID.creativeId); + expect(bid.currency).to.equal(VALID_BID.currency); }); }); }); From acf178fc51ffe3bb92a874a03f68554021f71599 Mon Sep 17 00:00:00 2001 From: Rade Popovic Date: Wed, 25 Oct 2017 15:50:57 +0200 Subject: [PATCH 03/12] - using utils.getParameterByName instead of utils.getTopWindowLocation().href - bidderCode is removed - Default ALG changed to 'ihr' - added protocol to 'cors' param --- modules/nanointeractiveBidAdapter.js | 19 +++---------------- .../modules/nanointeractiveBidAdapter_spec.js | 7 ++----- 2 files changed, 5 insertions(+), 21 deletions(-) diff --git a/modules/nanointeractiveBidAdapter.js b/modules/nanointeractiveBidAdapter.js index f5bae83875c..eed463c4706 100644 --- a/modules/nanointeractiveBidAdapter.js +++ b/modules/nanointeractiveBidAdapter.js @@ -13,7 +13,7 @@ export const NQ = 'nq'; export const NQ_NAME = 'name'; export const CATEGORY = 'category'; -const DEFAULT_ALG = 'ih'; +const DEFAULT_ALG = 'ihr'; export const spec = { @@ -55,14 +55,13 @@ function createSingleBidRequest(bid) { [NQ]: [createNqParam(bid), createCategoryParam(bid)], sizes: bid.sizes.map(value => value[0] + 'x' + value[1]), bidId: bid.bidId, - cors: document.domain.includes('localhost') ? null : document.domain + cors: document.domain.includes('localhost') ? null : location.origin }; } function createSingleBidResponse(serverBid) { return { requestId: serverBid.id, - bidderCode: serverBid.bidderCode, cpm: serverBid.cpm, width: serverBid.width, height: serverBid.height, @@ -75,25 +74,13 @@ function createSingleBidResponse(serverBid) { } function createNqParam(bid) { - return bid.params[NQ_NAME] ? getQueryParam(bid.params[NQ_NAME]) : bid.params[NQ] || null; + return bid.params[NQ_NAME] ? utils.getParameterByName(bid.params[NQ_NAME]) : bid.params[NQ] || null; } function createCategoryParam(bid) { return bid.params[CATEGORY] || null; } -function getQueryParam(nq) { - const queryString = utils.getTopWindowLocation().href.split('?'); - const queryParams = queryString.length > 1 ? queryString[1].split('&') : []; - for (let i = 0; i < queryParams.length; i++) { - const pair = queryParams[i].split('='); - if (pair[0] === nq) { - return decodeURIComponent(pair[1]) || null; - } - } - return null; -} - function isEngineResponseValid(response) { return !!response.cpm && !!response.ad; } diff --git a/test/spec/modules/nanointeractiveBidAdapter_spec.js b/test/spec/modules/nanointeractiveBidAdapter_spec.js index 59ddcc08b5d..9e9a5c10c64 100644 --- a/test/spec/modules/nanointeractiveBidAdapter_spec.js +++ b/test/spec/modules/nanointeractiveBidAdapter_spec.js @@ -21,7 +21,7 @@ describe('nanointeractive adapter tests', function () { [SECURITY]: isValid === true ? 'sec1' : null, [DATA_PARTNER_ID]: 'dpid1', [DATA_PARTNER_PIXEL_ID]: 'pid1', - [ALG]: 'ih', + [ALG]: 'ihr', [NQ]: SEARCH_QUERY, [NQ_NAME]: null, [CATEGORY]: null, @@ -40,7 +40,7 @@ describe('nanointeractive adapter tests', function () { [SECURITY]: 'sec1', [DATA_PARTNER_ID]: 'dpid1', [DATA_PARTNER_PIXEL_ID]: 'pid1', - [ALG]: 'ih', + [ALG]: 'ihr', [NQ]: [SEARCH_QUERY, null], sizes: [WIDTH + 'x' + HEIGHT], bidId: '24a1c9ec270973', @@ -50,7 +50,6 @@ describe('nanointeractive adapter tests', function () { function getSingleBidResponse(isValid) { return { id: '24a1c9ec270973', - bidderCode: spec.code, cpm: isValid === true ? CPM : null, width: WIDTH, height: HEIGHT, @@ -64,7 +63,6 @@ describe('nanointeractive adapter tests', function () { const VALID_BID = { requestId: '24a1c9ec270973', - bidderCode: spec.code, cpm: CPM, width: WIDTH, height: HEIGHT, @@ -98,7 +96,6 @@ describe('nanointeractive adapter tests', function () { it('Test interpretResponse() bids', function () { let bid = nanoBidAdapter.interpretResponse([getSingleBidResponse(true), getSingleBidResponse(false)])[0]; expect(bid.requestId).to.equal(VALID_BID.requestId); - expect(bid.bidderCode).to.equal(VALID_BID.bidderCode); expect(bid.cpm).to.equal(VALID_BID.cpm); expect(bid.width).to.equal(VALID_BID.width); expect(bid.height).to.equal(VALID_BID.height); From 9f2c50f9df1ed4d91db2135230483e1dff6aa0f4 Mon Sep 17 00:00:00 2001 From: Rade Popovic Date: Wed, 25 Oct 2017 17:32:58 +0200 Subject: [PATCH 04/12] markdown file --- modules/nanointeractiveBidAdapter.md | 69 ++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 modules/nanointeractiveBidAdapter.md diff --git a/modules/nanointeractiveBidAdapter.md b/modules/nanointeractiveBidAdapter.md new file mode 100644 index 00000000000..0159353750a --- /dev/null +++ b/modules/nanointeractiveBidAdapter.md @@ -0,0 +1,69 @@ +# Overview + +``` +Module Name: NanoInteractive Bid Adapter +Module Type: Bidder Adapter +Maintainer: rade@nanointeractive.com +``` + +# Description + +Connects to NanoInteractive search retargeting Ad Server for bids. + +Besides standard params, please provide, if exist, user search params. + +Three examples calling the Ad Server. + +**First** is basic + +**Second** is with hardcoded nq (user search) params + +**Third** is with the search query param name of the current url + + +# Test Parameters +``` +var adUnits = [ + // Basic call + { + code: 'basic-div', + sizes: [[300, 250], [300,600]], + bids: [{ + bidder: 'nanointeractive', + params: { + sec: '04a0cb7fb9ac02840f7f33d68a883780', + dpid: '58bfec94eb0a1916fa380162', + pid: '58bfec94eb0a1916fa380163' + } + }] + }, + // Hardcoded user search + { + code: 'nq-div', + sizes: [[300, 250], [300,600]], + bids: [{ + bidder: 'nanointeractive', + params: { + sec: '04a0cb7fb9ac02840f7f33d68a883780', + dpid: '58bfec94eb0a1916fa380162', + pid: '58bfec94eb0a1916fa380163', + nq: 'user search' + } + }] + }, + // URL user search + { + code: 'url-div', + sizes: [[300, 250], [300,600]], + bids: [{ + bidder: 'nanointeractive', + params: { + sec: '04a0cb7fb9ac02840f7f33d68a883780', + dpid: '58bfec94eb0a1916fa380162', + pid: '58bfec94eb0a1916fa380163', + name: 'search' + } + }] + } +]; +``` From 1cbdb9704a93a18d8b7d2826c6a0d213d03b642c Mon Sep 17 00:00:00 2001 From: Rade Popovic Date: Wed, 25 Oct 2017 22:45:05 +0200 Subject: [PATCH 05/12] enabling localhost for bid requests --- modules/nanointeractiveBidAdapter.js | 2 +- test/spec/modules/nanointeractiveBidAdapter_spec.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/nanointeractiveBidAdapter.js b/modules/nanointeractiveBidAdapter.js index eed463c4706..9781e36edb6 100644 --- a/modules/nanointeractiveBidAdapter.js +++ b/modules/nanointeractiveBidAdapter.js @@ -55,7 +55,7 @@ function createSingleBidRequest(bid) { [NQ]: [createNqParam(bid), createCategoryParam(bid)], sizes: bid.sizes.map(value => value[0] + 'x' + value[1]), bidId: bid.bidId, - cors: document.domain.includes('localhost') ? null : location.origin + cors: location.origin }; } diff --git a/test/spec/modules/nanointeractiveBidAdapter_spec.js b/test/spec/modules/nanointeractiveBidAdapter_spec.js index 9e9a5c10c64..b9b9207aca2 100644 --- a/test/spec/modules/nanointeractiveBidAdapter_spec.js +++ b/test/spec/modules/nanointeractiveBidAdapter_spec.js @@ -44,7 +44,7 @@ describe('nanointeractive adapter tests', function () { [NQ]: [SEARCH_QUERY, null], sizes: [WIDTH + 'x' + HEIGHT], bidId: '24a1c9ec270973', - cors: null + cors: 'http://localhost:9876' }; function getSingleBidResponse(isValid) { From d181668c3b20beeac1a3940888bd4c96405dd2d5 Mon Sep 17 00:00:00 2001 From: nanointeractive Date: Tue, 30 Jan 2018 16:10:52 +0100 Subject: [PATCH 06/12] Bugfix interpretResponse - added body; Removed unnecessary parameters; Adjusted tests; --- modules/nanointeractiveBidAdapter.js | 14 ++------------ modules/nanointeractiveBidAdapter.md | 6 ------ .../modules/nanointeractiveBidAdapter_spec.js | 19 ++++++------------- 3 files changed, 8 insertions(+), 31 deletions(-) diff --git a/modules/nanointeractiveBidAdapter.js b/modules/nanointeractiveBidAdapter.js index 05aca3065c9..225859a4360 100644 --- a/modules/nanointeractiveBidAdapter.js +++ b/modules/nanointeractiveBidAdapter.js @@ -5,26 +5,19 @@ import { BANNER } from '../src/mediaTypes'; export const BIDDER_CODE = 'nanointeractive'; export const ENGINE_BASE_URL = 'https://www.audiencemanager.de/hb'; -export const SECURITY = 'sec'; -export const DATA_PARTNER_ID = 'dpid'; export const DATA_PARTNER_PIXEL_ID = 'pid'; -export const ALG = 'alg'; export const NQ = 'nq'; export const NQ_NAME = 'name'; export const CATEGORY = 'category'; -const DEFAULT_ALG = 'ihr'; - export const spec = { code: BIDDER_CODE, supportedMediaTypes: [BANNER], isBidRequestValid(bid) { - const sec = bid.params[SECURITY]; - const dpid = bid.params[DATA_PARTNER_ID]; const pid = bid.params[DATA_PARTNER_PIXEL_ID]; - return !!(sec && dpid && pid); + return !!(pid); }, buildRequests(bidRequests) { let payload = []; @@ -37,7 +30,7 @@ export const spec = { }, interpretResponse(serverResponse) { const bids = []; - serverResponse.forEach(serverBid => { + serverResponse.body.forEach(serverBid => { if (isEngineResponseValid(serverBid)) { bids.push(createSingleBidResponse(serverBid)); } @@ -48,10 +41,7 @@ export const spec = { function createSingleBidRequest(bid) { return { - [SECURITY]: bid.params[SECURITY], - [DATA_PARTNER_ID]: bid.params[DATA_PARTNER_ID], [DATA_PARTNER_PIXEL_ID]: bid.params[DATA_PARTNER_PIXEL_ID], - [ALG]: bid.params[ALG] || DEFAULT_ALG, [NQ]: [createNqParam(bid), createCategoryParam(bid)], sizes: bid.sizes.map(value => value[0] + 'x' + value[1]), bidId: bid.bidId, diff --git a/modules/nanointeractiveBidAdapter.md b/modules/nanointeractiveBidAdapter.md index 0159353750a..0df49999492 100644 --- a/modules/nanointeractiveBidAdapter.md +++ b/modules/nanointeractiveBidAdapter.md @@ -31,8 +31,6 @@ var adUnits = [ bids: [{ bidder: 'nanointeractive', params: { - sec: '04a0cb7fb9ac02840f7f33d68a883780', - dpid: '58bfec94eb0a1916fa380162', pid: '58bfec94eb0a1916fa380163' } }] @@ -44,8 +42,6 @@ var adUnits = [ bids: [{ bidder: 'nanointeractive', params: { - sec: '04a0cb7fb9ac02840f7f33d68a883780', - dpid: '58bfec94eb0a1916fa380162', pid: '58bfec94eb0a1916fa380163', nq: 'user search' } @@ -58,8 +54,6 @@ var adUnits = [ bids: [{ bidder: 'nanointeractive', params: { - sec: '04a0cb7fb9ac02840f7f33d68a883780', - dpid: '58bfec94eb0a1916fa380162', pid: '58bfec94eb0a1916fa380163', name: 'search' } diff --git a/test/spec/modules/nanointeractiveBidAdapter_spec.js b/test/spec/modules/nanointeractiveBidAdapter_spec.js index 4b498c88982..14927d929d3 100644 --- a/test/spec/modules/nanointeractiveBidAdapter_spec.js +++ b/test/spec/modules/nanointeractiveBidAdapter_spec.js @@ -2,8 +2,7 @@ import { expect } from 'chai'; import * as utils from 'src/utils'; import { - ALG, - BIDDER_CODE, CATEGORY, DATA_PARTNER_ID, DATA_PARTNER_PIXEL_ID, ENGINE_BASE_URL, NQ, NQ_NAME, SECURITY, + BIDDER_CODE, CATEGORY, DATA_PARTNER_PIXEL_ID, ENGINE_BASE_URL, NQ, NQ_NAME, spec } from '../../../modules/nanointeractiveBidAdapter'; @@ -20,10 +19,7 @@ describe('nanointeractive adapter tests', function () { bidder: BIDDER_CODE, params: (function () { return { - [SECURITY]: isValid === true ? 'sec1' : null, - [DATA_PARTNER_ID]: 'dpid1', - [DATA_PARTNER_PIXEL_ID]: 'pid1', - [ALG]: 'ihr', + [DATA_PARTNER_PIXEL_ID]: isValid === true ? 'pid1' : null, [NQ]: SEARCH_QUERY, [NQ_NAME]: null, [CATEGORY]: null, @@ -38,11 +34,8 @@ describe('nanointeractive adapter tests', function () { } } - const SINGlE_BID_REQUEST = { - [SECURITY]: 'sec1', - [DATA_PARTNER_ID]: 'dpid1', + const SINGLE_BID_REQUEST = { [DATA_PARTNER_PIXEL_ID]: 'pid1', - [ALG]: 'ihr', [NQ]: [SEARCH_QUERY, null], sizes: [WIDTH + 'x' + HEIGHT], bidId: '24a1c9ec270973', @@ -91,16 +84,16 @@ describe('nanointeractive adapter tests', function () { let request = nanoBidAdapter.buildRequests([getBid(true)]); expect(request.method).to.equal('POST'); expect(request.url).to.equal(ENGINE_BASE_URL); - expect(request.data).to.equal(JSON.stringify([SINGlE_BID_REQUEST])); + expect(request.data).to.equal(JSON.stringify([SINGLE_BID_REQUEST])); stub.restore(); }); it('Test interpretResponse() length', function () { - let bids = nanoBidAdapter.interpretResponse([getSingleBidResponse(true), getSingleBidResponse(false)]); + let bids = nanoBidAdapter.interpretResponse({body: [getSingleBidResponse(true), getSingleBidResponse(false)]}); expect(bids.length).to.equal(1); }); it('Test interpretResponse() bids', function () { - let bid = nanoBidAdapter.interpretResponse([getSingleBidResponse(true), getSingleBidResponse(false)])[0]; + let bid = nanoBidAdapter.interpretResponse({body: [getSingleBidResponse(true), getSingleBidResponse(false)]})[0]; expect(bid.requestId).to.equal(VALID_BID.requestId); expect(bid.cpm).to.equal(VALID_BID.cpm); expect(bid.width).to.equal(VALID_BID.width); From 180fa1b085ec68a4cd17494f563a028ced0c8cd8 Mon Sep 17 00:00:00 2001 From: nanointeractive Date: Fri, 4 May 2018 15:47:41 +0200 Subject: [PATCH 07/12] New feature - subId --- modules/nanointeractiveBidAdapter.js | 7 +++++ modules/nanointeractiveBidAdapter.md | 26 +++++++++++++++---- .../modules/nanointeractiveBidAdapter_spec.js | 4 ++- 3 files changed, 31 insertions(+), 6 deletions(-) diff --git a/modules/nanointeractiveBidAdapter.js b/modules/nanointeractiveBidAdapter.js index 225859a4360..67840ccf3ea 100644 --- a/modules/nanointeractiveBidAdapter.js +++ b/modules/nanointeractiveBidAdapter.js @@ -9,6 +9,7 @@ export const DATA_PARTNER_PIXEL_ID = 'pid'; export const NQ = 'nq'; export const NQ_NAME = 'name'; export const CATEGORY = 'category'; +export const SUB_ID = 'subId'; export const spec = { @@ -43,6 +44,7 @@ function createSingleBidRequest(bid) { return { [DATA_PARTNER_PIXEL_ID]: bid.params[DATA_PARTNER_PIXEL_ID], [NQ]: [createNqParam(bid), createCategoryParam(bid)], + [SUB_ID]: createSubIdParam(bid), sizes: bid.sizes.map(value => value[0] + 'x' + value[1]), bidId: bid.bidId, cors: utils.getOrigin() @@ -71,6 +73,11 @@ function createCategoryParam(bid) { return bid.params[CATEGORY] || null; } +function createSubIdParam(bid) { + return bid.params[SUB_ID] || null; +} + + function isEngineResponseValid(response) { return !!response.cpm && !!response.ad; } diff --git a/modules/nanointeractiveBidAdapter.md b/modules/nanointeractiveBidAdapter.md index 0df49999492..0813a461493 100644 --- a/modules/nanointeractiveBidAdapter.md +++ b/modules/nanointeractiveBidAdapter.md @@ -8,7 +8,7 @@ Maintainer: rade@nanointeractive.com # Description -Connects to NanoInteractive search retargeting Ad Server for bids. +Connects to Nano Interactive search retargeting Ad Server for bids. Besides standard params, please provide, if exist, user search params. @@ -20,7 +20,6 @@ Three examples calling the Ad Server. **Third** is with the search query param name of the current url - # Test Parameters ``` var adUnits = [ @@ -31,7 +30,11 @@ var adUnits = [ bids: [{ bidder: 'nanointeractive', params: { - pid: '58bfec94eb0a1916fa380163' + // required + pid: '58bfec94eb0a1916fa380163', + // optional parameters + category: 'some category', + subId: '123' } }] }, @@ -42,8 +45,12 @@ var adUnits = [ bids: [{ bidder: 'nanointeractive', params: { + // required pid: '58bfec94eb0a1916fa380163', - nq: 'user search' + // optional parameters + nq: 'user search', + category: 'some category', + subId: '123' } }] }, @@ -54,10 +61,19 @@ var adUnits = [ bids: [{ bidder: 'nanointeractive', params: { + // required pid: '58bfec94eb0a1916fa380163', - name: 'search' + // optional parameters + name: 'search', + category: 'some category', + subId: '123' } }] } ]; ``` + +### Requirements: +To be able to get identification key (`pid`), you must register at
+`https://audiencemanager.de/public/data-partners-register`
+and follow further instructions. \ No newline at end of file diff --git a/test/spec/modules/nanointeractiveBidAdapter_spec.js b/test/spec/modules/nanointeractiveBidAdapter_spec.js index cafe7bf2799..92b6fe8d797 100644 --- a/test/spec/modules/nanointeractiveBidAdapter_spec.js +++ b/test/spec/modules/nanointeractiveBidAdapter_spec.js @@ -2,7 +2,7 @@ import { expect } from 'chai'; import * as utils from 'src/utils'; import { - BIDDER_CODE, CATEGORY, DATA_PARTNER_PIXEL_ID, ENGINE_BASE_URL, NQ, NQ_NAME, + BIDDER_CODE, CATEGORY, DATA_PARTNER_PIXEL_ID, ENGINE_BASE_URL, NQ, NQ_NAME, SUB_ID, spec } from '../../../modules/nanointeractiveBidAdapter'; @@ -23,6 +23,7 @@ describe('nanointeractive adapter tests', function () { [NQ]: SEARCH_QUERY, [NQ_NAME]: null, [CATEGORY]: null, + [SUB_ID]: null, } })(), placementCode: 'div-gpt-ad-1460505748561-0', @@ -37,6 +38,7 @@ describe('nanointeractive adapter tests', function () { const SINGLE_BID_REQUEST = { [DATA_PARTNER_PIXEL_ID]: 'pid1', [NQ]: [SEARCH_QUERY, null], + [SUB_ID]: null, sizes: [WIDTH + 'x' + HEIGHT], bidId: '24a1c9ec270973', cors: 'http://localhost' From 82047340bf239342f22d414de6adb799c0516e03 Mon Sep 17 00:00:00 2001 From: nanointeractive Date: Mon, 7 May 2018 10:54:54 +0200 Subject: [PATCH 08/12] Fixed lint errors --- modules/nanointeractiveBidAdapter.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/modules/nanointeractiveBidAdapter.js b/modules/nanointeractiveBidAdapter.js index 67840ccf3ea..549695369c8 100644 --- a/modules/nanointeractiveBidAdapter.js +++ b/modules/nanointeractiveBidAdapter.js @@ -74,10 +74,9 @@ function createCategoryParam(bid) { } function createSubIdParam(bid) { - return bid.params[SUB_ID] || null; + return bid.params[SUB_ID] || null; } - function isEngineResponseValid(response) { return !!response.cpm && !!response.ad; } From dff758dd02b243e60be7e16cd17ec022c3436772 Mon Sep 17 00:00:00 2001 From: nanointeractive Date: Mon, 4 Jun 2018 15:56:38 +0200 Subject: [PATCH 09/12] Nano Interactive Bid Adapter New Bid params: - categoryName - name Getting referrer information --- modules/nanointeractiveBidAdapter.js | 32 +- modules/nanointeractiveBidAdapter.md | 201 +++-- .../modules/nanointeractiveBidAdapter_spec.js | 830 ++++++++++++++++-- 3 files changed, 914 insertions(+), 149 deletions(-) diff --git a/modules/nanointeractiveBidAdapter.js b/modules/nanointeractiveBidAdapter.js index 549695369c8..afcfef1f5b6 100644 --- a/modules/nanointeractiveBidAdapter.js +++ b/modules/nanointeractiveBidAdapter.js @@ -9,18 +9,20 @@ export const DATA_PARTNER_PIXEL_ID = 'pid'; export const NQ = 'nq'; export const NQ_NAME = 'name'; export const CATEGORY = 'category'; +export const CATEGORY_NAME = 'categoryName'; export const SUB_ID = 'subId'; +export const REF = 'ref'; export const spec = { code: BIDDER_CODE, supportedMediaTypes: [BANNER], - isBidRequestValid(bid) { + isBidRequestValid (bid) { const pid = bid.params[DATA_PARTNER_PIXEL_ID]; return !!(pid); }, - buildRequests(bidRequests) { + buildRequests (bidRequests) { let payload = []; bidRequests.forEach(bid => payload.push(createSingleBidRequest(bid))); return { @@ -29,7 +31,7 @@ export const spec = { data: JSON.stringify(payload) }; }, - interpretResponse(serverResponse) { + interpretResponse (serverResponse) { const bids = []; serverResponse.body.forEach(serverBid => { if (isEngineResponseValid(serverBid)) { @@ -40,18 +42,20 @@ export const spec = { } }; -function createSingleBidRequest(bid) { +function createSingleBidRequest (bid) { return { [DATA_PARTNER_PIXEL_ID]: bid.params[DATA_PARTNER_PIXEL_ID], - [NQ]: [createNqParam(bid), createCategoryParam(bid)], + [NQ]: [createNqParam(bid)], + [CATEGORY]: [createCategoryParam(bid)], [SUB_ID]: createSubIdParam(bid), + [REF]: createRefParam(bid), sizes: bid.sizes.map(value => value[0] + 'x' + value[1]), bidId: bid.bidId, - cors: utils.getOrigin() + cors: utils.getOrigin(), }; } -function createSingleBidResponse(serverBid) { +function createSingleBidResponse (serverBid) { return { requestId: serverBid.id, cpm: serverBid.cpm, @@ -65,19 +69,23 @@ function createSingleBidResponse(serverBid) { }; } -function createNqParam(bid) { +function createNqParam (bid) { return bid.params[NQ_NAME] ? utils.getParameterByName(bid.params[NQ_NAME]) : bid.params[NQ] || null; } -function createCategoryParam(bid) { - return bid.params[CATEGORY] || null; +function createCategoryParam (bid) { + return bid.params[CATEGORY_NAME] ? utils.getParameterByName(bid.params[CATEGORY_NAME]) : bid.params[CATEGORY] || null; } -function createSubIdParam(bid) { +function createSubIdParam (bid) { return bid.params[SUB_ID] || null; } -function isEngineResponseValid(response) { +function createRefParam (bid) { + return bid.params[REF] ? null : utils.getTopWindowReferrer() || null; +} + +function isEngineResponseValid (response) { return !!response.cpm && !!response.ad; } diff --git a/modules/nanointeractiveBidAdapter.md b/modules/nanointeractiveBidAdapter.md index 0813a461493..7dbbe043fb6 100644 --- a/modules/nanointeractiveBidAdapter.md +++ b/modules/nanointeractiveBidAdapter.md @@ -1,7 +1,7 @@ # Overview ``` -Module Name: NanoInteractive Bid Adapter +Module Name: Nano Interactive Bid Adapter Module Type: Bidder Adapter Maintainer: rade@nanointeractive.com ``` @@ -10,70 +10,147 @@ Maintainer: rade@nanointeractive.com Connects to Nano Interactive search retargeting Ad Server for bids. -Besides standard params, please provide, if exist, user search params. -Three examples calling the Ad Server. -**First** is basic -**Second** is with hardcoded nq (user search) params +
+### Requirements: +To be able to get identification key (`pid`), please contact us at
+`https://www.nanointeractive.com/publishers`
+


-**Third** is with the search query param name of the current url +#### Send All Bids Ad Server Keys: +(truncated to 20 chars due to [DFP limit](https://support.google.com/dfp_premium/answer/1628457?hl=en#Key-values)) -# Test Parameters -``` -var adUnits = [ - // Basic call - { - code: 'basic-div', - sizes: [[300, 250], [300,600]], - bids: [{ - bidder: 'nanointeractive', - params: { - // required - pid: '58bfec94eb0a1916fa380163', - // optional parameters - category: 'some category', - subId: '123' - } - }] - }, - // Hardcoded user search - { - code: 'nq-div', - sizes: [[300, 250], [300,600]], - bids: [{ - bidder: 'nanointeractive', - params: { - // required - pid: '58bfec94eb0a1916fa380163', - // optional parameters - nq: 'user search', - category: 'some category', - subId: '123' - } - }] - }, - // URL user search - { - code: 'url-div', - sizes: [[300, 250], [300,600]], - bids: [{ - bidder: 'nanointeractive', - params: { - // required - pid: '58bfec94eb0a1916fa380163', - // optional parameters - name: 'search', - category: 'some category', - subId: '123' - } - }] - } -]; -``` +`hb_adid_nanointeract` +`hb_bidder_nanointera` +`hb_pb_nanointeractiv` +`hb_format_nanointera` +`hb_size_nanointeract` +`hb_source_nanointera` -### Requirements: -To be able to get identification key (`pid`), you must register at
-`https://audiencemanager.de/public/data-partners-register`
-and follow further instructions. \ No newline at end of file +#### Default Deal ID Keys: +`hb_deal_nanointeract` + +### bid params + +{: .table .table-bordered .table-striped } +| Name | Scope | Description | Example | +| :------------- | :------- | :----------------------------------------------- | :--------------------------- | +| `pid` | required | Identification key, provided by Nano Interactive | `'5afaa0280ae8996eb578de53'` | +| `category` | optional | Contextual taxonomy | `'automotive'` | +| `categoryName` | optional | Contextual taxonomy (from URL query param) | `'cat_name'` | +| `nq` | optional | User search query | `'automobile search query'` | +| `name` | optional | User search query (from URL query param) | `'search_param'` | +| `subId` | optional | Channel - used to separate traffic sources | `'123'` | + +#### Configuration +The `category` and `categoryName` are mutually exclusive. If you pass both, `categoryName` takes precedence. +
+The `nq` and `name` are mutually exclusive. If you pass both, `name` takes precedence. + +#### Example with only required field `pid` + var adUnits = [{ + code: 'nano-div', + sizes: [[300, 250], [300,600]], + bids: [{ + bidder: 'nanointeractive', + params: { + pid: '5afaa0280ae8996eb578de53' + } + }] + }]; + +#### Example with `category` + var adUnits = [{ + code: 'nano-div', + sizes: [[300, 250], [300,600]], + bids: [{ + bidder: 'nanointeractive', + params: { + pid: '5afaa0280ae8996eb578de53', + category: 'automotive', + subId: '123' + } + }] + }]; + +#### Example with `categoryName` + var adUnits = [{ + code: 'nano-div', + sizes: [[300, 250], [300,600]], + bids: [{ + bidder: 'nanointeractive', + params: { + pid: '5afaa0280ae8996eb578de53', + // Category "automotive" is in the URL like: + // https://www....?cat_name=automotive&... + categoryName: 'cat_name', + subId: '123' + } + }] + }]; + +#### Example with `nq` + var adUnits = [{ + code: 'nano-div', + sizes: [[300, 250], [300,600]], + bids: [{ + bidder: 'nanointeractive', + params: { + pid: '5afaa0280ae8996eb578de53', + category: 'automotive', + // User searched "automobile search query" (extracted from search text field) + nq: 'automobile search query', + subId: '123' + } + }] + }]; + +#### Example with `nqName` + var adUnits = [{ + code: 'nano-div', + sizes: [[300, 250], [300,600]], + bids: [{ + bidder: 'nanointeractive', + params: { + pid: '5afaa0280ae8996eb578de53', + category: 'automotive', + // User searched "automobile search query" and it is in the URL like: + // https://www....?search_param=automobile%20search%20query&... + nqName: 'search_param', + subId: '123' + } + }] + }]; + +#### Example with `category` and `nq` + var adUnits = [{ + code: 'nano-div', + sizes: [[300, 250], [300,600]], + bids: [{ + bidder: 'nanointeractive', + params: { + pid: '5afaa0280ae8996eb578de53', + category: 'automotive', + nq: 'automobile search query', + subId: '123' + } + }] + }]; + +#### Example with `categoryName` and `nqName` + var adUnits = [{ + code: 'nano-div', + sizes: [[300, 250], [300,600]], + bids: [{ + bidder: 'nanointeractive', + params: { + pid: '5afaa0280ae8996eb578de53', + category: 'automotive', + categoryName: 'cat_name', + nqName: 'search_param', + subId: '123' + } + }] + }]; \ No newline at end of file diff --git a/test/spec/modules/nanointeractiveBidAdapter_spec.js b/test/spec/modules/nanointeractiveBidAdapter_spec.js index 92b6fe8d797..f93cc546859 100644 --- a/test/spec/modules/nanointeractiveBidAdapter_spec.js +++ b/test/spec/modules/nanointeractiveBidAdapter_spec.js @@ -1,109 +1,789 @@ import { expect } from 'chai'; import * as utils from 'src/utils'; +import * as sinon from 'sinon'; import { - BIDDER_CODE, CATEGORY, DATA_PARTNER_PIXEL_ID, ENGINE_BASE_URL, NQ, NQ_NAME, SUB_ID, - spec + BIDDER_CODE, + CATEGORY, + CATEGORY_NAME, + DATA_PARTNER_PIXEL_ID, + ENGINE_BASE_URL, + NQ, + NQ_NAME, + REF, + spec, + SUB_ID } from '../../../modules/nanointeractiveBidAdapter'; describe('nanointeractive adapter tests', function () { - const SEARCH_QUERY = 'rumpelstiltskin'; - const WIDTH = 300; - const HEIGHT = 250; - const SIZES = [[WIDTH, HEIGHT]]; + const SIZES_PARAM = 'sizes'; + const BID_ID_PARAM = 'bidId'; + const BID_ID_VALUE = '24a1c9ec270973'; + const CORS_PARAM = 'cors'; + const DATA_PARTNER_PIXEL_ID_VALUE = 'pid1'; + const NQ_VALUE = 'rumpelstiltskin'; + const NQ_NAME_QUERY_PARAM = 'nqName'; + const CATEGORY_VALUE = 'some category'; + const CATEGORY_NAME_QUERY_PARAM = 'catName'; + const SUB_ID_VALUE = '123'; + const REF_NO_VALUE = 'none'; + const REF_OTHER_VALUE = 'other'; + const WIDTH1 = 300; + const HEIGHT1 = 250; + const WIDTH2 = 468; + const HEIGHT2 = 60; + const SIZES_VALUE = [[WIDTH1, HEIGHT1], [WIDTH2, HEIGHT2]]; const AD = ' '; const CPM = 1; - function getBid(isValid) { + function getBidResponse (pid, nq, category, subId, cors, ref) { + return { + [DATA_PARTNER_PIXEL_ID]: pid, + [NQ]: nq, + [CATEGORY]: category, + [SUB_ID]: subId, + [REF]: ref, + [SIZES_PARAM]: [WIDTH1 + 'x' + HEIGHT1, WIDTH2 + 'x' + HEIGHT2], + [BID_ID_PARAM]: BID_ID_VALUE, + [CORS_PARAM]: cors, + }; + } + function getBidRequest (params) { return { bidder: BIDDER_CODE, - params: (function () { - return { - [DATA_PARTNER_PIXEL_ID]: isValid === true ? 'pid1' : null, - [NQ]: SEARCH_QUERY, - [NQ_NAME]: null, - [CATEGORY]: null, - [SUB_ID]: null, - } - })(), + params: params, placementCode: 'div-gpt-ad-1460505748561-0', transactionId: 'ee335735-ddd3-41f2-b6c6-e8aa99f81c0f', - sizes: SIZES, - bidId: '24a1c9ec270973', + [SIZES_PARAM]: SIZES_VALUE, + [BID_ID_PARAM]: BID_ID_VALUE, bidderRequestId: '189135372acd55', auctionId: 'ac15bb68-4ef0-477f-93f4-de91c47f00a9' - } - } - - const SINGLE_BID_REQUEST = { - [DATA_PARTNER_PIXEL_ID]: 'pid1', - [NQ]: [SEARCH_QUERY, null], - [SUB_ID]: null, - sizes: [WIDTH + 'x' + HEIGHT], - bidId: '24a1c9ec270973', - cors: 'http://localhost' - }; - - function getSingleBidResponse(isValid) { - return { - id: '24a1c9ec270973', - cpm: isValid === true ? CPM : null, - width: WIDTH, - height: HEIGHT, - ad: AD, - ttl: 360, - creativeId: 'TEST_ID', - netRevenue: false, - currency: 'EUR', - } + }; } - const VALID_BID = { - requestId: '24a1c9ec270973', - cpm: CPM, - width: WIDTH, - height: HEIGHT, - ad: AD, - ttl: 360, - creativeId: 'TEST_ID', - netRevenue: false, - currency: 'EUR', - }; - describe('NanoAdapter', () => { let nanoBidAdapter = spec; describe('Methods', () => { - it('Test isBidRequestValid() with valid param', function () { - expect(nanoBidAdapter.isBidRequestValid(getBid(true))).to.equal(true); + it('Test isBidRequestValid() with valid param(s): pid', function () { + expect(nanoBidAdapter.isBidRequestValid(getBidRequest({ + [DATA_PARTNER_PIXEL_ID]: DATA_PARTNER_PIXEL_ID_VALUE, + }))).to.equal(true); }); - it('Test isBidRequestValid() with invalid param', function () { - expect(nanoBidAdapter.isBidRequestValid(getBid(false))).to.equal(false); + it('Test isBidRequestValid() with valid param(s): pid, nq', function () { + expect(nanoBidAdapter.isBidRequestValid(getBidRequest({ + [DATA_PARTNER_PIXEL_ID]: DATA_PARTNER_PIXEL_ID_VALUE, + [NQ]: NQ, + }))).to.equal(true); }); - it('Test buildRequests()', function () { - let stub = sinon.stub(utils, 'getOrigin').callsFake(() => 'http://localhost'); - - let request = nanoBidAdapter.buildRequests([getBid(true)]); + it('Test isBidRequestValid() with valid param(s): pid, nq, category', function () { + expect(nanoBidAdapter.isBidRequestValid(getBidRequest({ + [DATA_PARTNER_PIXEL_ID]: DATA_PARTNER_PIXEL_ID_VALUE, + [NQ]: NQ, + [CATEGORY]: CATEGORY_VALUE, + }))).to.equal(true); + }); + it('Test isBidRequestValid() with valid param(s): pid, nq, categoryName', function () { + expect(nanoBidAdapter.isBidRequestValid(getBidRequest({ + [DATA_PARTNER_PIXEL_ID]: DATA_PARTNER_PIXEL_ID_VALUE, + [NQ]: NQ, + [CATEGORY_NAME_QUERY_PARAM]: CATEGORY_NAME_QUERY_PARAM, + }))).to.equal(true); + }); + it('Test isBidRequestValid() with valid param(s): pid, nq, subId', function () { + expect(nanoBidAdapter.isBidRequestValid(getBidRequest({ + [DATA_PARTNER_PIXEL_ID]: DATA_PARTNER_PIXEL_ID_VALUE, + [NQ]: NQ, + [SUB_ID]: SUB_ID_VALUE, + }))).to.equal(true); + }); + it('Test isBidRequestValid() with valid param(s): pid, nqName', function () { + expect(nanoBidAdapter.isBidRequestValid(getBidRequest({ + [DATA_PARTNER_PIXEL_ID]: DATA_PARTNER_PIXEL_ID_VALUE, + [NQ_NAME]: NQ_NAME_QUERY_PARAM, + }))).to.equal(true); + }); + it('Test isBidRequestValid() with valid param(s): pid, nqName, category', function () { + expect(nanoBidAdapter.isBidRequestValid(getBidRequest({ + [DATA_PARTNER_PIXEL_ID]: DATA_PARTNER_PIXEL_ID_VALUE, + [NQ_NAME]: NQ_NAME_QUERY_PARAM, + [CATEGORY]: CATEGORY_VALUE, + }))).to.equal(true); + }); + it('Test isBidRequestValid() with valid param(s): pid, nqName, categoryName', function () { + expect(nanoBidAdapter.isBidRequestValid(getBidRequest({ + [DATA_PARTNER_PIXEL_ID]: DATA_PARTNER_PIXEL_ID_VALUE, + [NQ_NAME]: NQ_NAME_QUERY_PARAM, + [CATEGORY_NAME_QUERY_PARAM]: CATEGORY_NAME_QUERY_PARAM, + }))).to.equal(true); + }); + it('Test isBidRequestValid() with valid param(s): pid, nqName, subId', function () { + expect(nanoBidAdapter.isBidRequestValid(getBidRequest({ + [DATA_PARTNER_PIXEL_ID]: DATA_PARTNER_PIXEL_ID_VALUE, + [NQ_NAME]: NQ_NAME_QUERY_PARAM, + [SUB_ID]: SUB_ID_VALUE, + }))).to.equal(true); + }); + it('Test isBidRequestValid() with valid param(s): pid, category', function () { + expect(nanoBidAdapter.isBidRequestValid(getBidRequest({ + [DATA_PARTNER_PIXEL_ID]: DATA_PARTNER_PIXEL_ID_VALUE, + [CATEGORY]: CATEGORY_VALUE, + }))).to.equal(true); + }); + it('Test isBidRequestValid() with valid param(s): pid, category, subId', function () { + expect(nanoBidAdapter.isBidRequestValid(getBidRequest({ + [DATA_PARTNER_PIXEL_ID]: DATA_PARTNER_PIXEL_ID_VALUE, + [CATEGORY]: CATEGORY_VALUE, + [SUB_ID]: SUB_ID_VALUE, + }))).to.equal(true); + }); + it('Test isBidRequestValid() with valid param(s): pid, subId', function () { + expect(nanoBidAdapter.isBidRequestValid(getBidRequest({ + [DATA_PARTNER_PIXEL_ID]: DATA_PARTNER_PIXEL_ID_VALUE, + [SUB_ID]: SUB_ID_VALUE, + }))).to.equal(true); + }); + it('Test isBidRequestValid() with valid param(s): pid, nq, category, subId', function () { + expect(nanoBidAdapter.isBidRequestValid(getBidRequest({ + [DATA_PARTNER_PIXEL_ID]: DATA_PARTNER_PIXEL_ID_VALUE, + [NQ]: NQ_VALUE, + [CATEGORY]: CATEGORY_VALUE, + [SUB_ID]: SUB_ID_VALUE, + }))).to.equal(true); + }); + it('Test isBidRequestValid() with valid param(s): pid, nqName, categoryName, subId', function () { + expect(nanoBidAdapter.isBidRequestValid(getBidRequest({ + [DATA_PARTNER_PIXEL_ID]: DATA_PARTNER_PIXEL_ID_VALUE, + [NQ_NAME]: NQ_NAME_QUERY_PARAM, + [CATEGORY_NAME]: CATEGORY_NAME_QUERY_PARAM, + [SUB_ID]: SUB_ID_VALUE, + }))).to.equal(true); + }); + it('Test isBidRequestValid() with valid param(s): pid, nq, category, subId, ref (value none)', function () { + expect(nanoBidAdapter.isBidRequestValid(getBidRequest({ + [DATA_PARTNER_PIXEL_ID]: DATA_PARTNER_PIXEL_ID_VALUE, + [NQ]: NQ_VALUE, + [CATEGORY]: CATEGORY_VALUE, + [SUB_ID]: SUB_ID_VALUE, + [REF]: REF_NO_VALUE, + }))).to.equal(true); + }); + it('Test isBidRequestValid() with valid param(s): pid, nq, category, subId, ref (value other)', function () { + expect(nanoBidAdapter.isBidRequestValid(getBidRequest({ + [DATA_PARTNER_PIXEL_ID]: DATA_PARTNER_PIXEL_ID_VALUE, + [NQ]: NQ_VALUE, + [CATEGORY]: CATEGORY_VALUE, + [SUB_ID]: SUB_ID_VALUE, + [REF]: REF_OTHER_VALUE, + }))).to.equal(true); + }); + it('Test isBidRequestValid() with invalid param(s): empty', function () { + expect(nanoBidAdapter.isBidRequestValid(getBidRequest({}))).to.equal(false); + }); + it('Test isBidRequestValid() with invalid param(s): pid missing', function () { + expect(nanoBidAdapter.isBidRequestValid(getBidRequest({ + [NQ]: NQ_VALUE, + [CATEGORY]: CATEGORY_VALUE, + [SUB_ID]: SUB_ID_VALUE, + }))).to.equal(false); + }); + it('Test buildRequest() - pid', function () { + let mockOriginAddress = 'http://localhost'; + let mockRefAddress = 'http://some-ref.test'; + let sandbox = sinon.sandbox.create(); + sandbox.stub(utils, 'getOrigin').callsFake(() => mockOriginAddress); + sandbox.stub(utils, 'getTopWindowReferrer').callsFake(() => mockRefAddress); + sandbox.stub(utils, 'getParameterByName').callsFake((arg) => { + switch (arg) { + case CATEGORY_NAME_QUERY_PARAM: + return CATEGORY_VALUE; + case NQ_NAME_QUERY_PARAM: + return NQ_VALUE; + } + }); + let testInput = + { + requestParams: { + [DATA_PARTNER_PIXEL_ID]: DATA_PARTNER_PIXEL_ID_VALUE, + }, + expectedPid: DATA_PARTNER_PIXEL_ID_VALUE, + expectedNq: [null], + expectedCategory: [null], + expectedSubId: null, + expectedCors: mockOriginAddress, + expectedRef: mockRefAddress, + }; + let request = nanoBidAdapter.buildRequests([ + getBidRequest(testInput.requestParams)]); expect(request.method).to.equal('POST'); expect(request.url).to.equal(ENGINE_BASE_URL); - expect(request.data).to.equal(JSON.stringify([SINGLE_BID_REQUEST])); - - stub.restore(); + expect(request.data).to.equal(JSON.stringify([ + getBidResponse( + testInput.expectedPid, + testInput.expectedNq, + testInput.expectedCategory, + testInput.expectedSubId, + testInput.expectedCors, + testInput.expectedRef + ), + ])); + sandbox.restore(); + }); + it('Test buildRequest() - pid, nq', function () { + let mockOriginAddress = 'http://localhost'; + let mockRefAddress = 'http://some-ref.test'; + let sandbox = sinon.sandbox.create(); + sandbox.stub(utils, 'getOrigin').callsFake(() => mockOriginAddress); + sandbox.stub(utils, 'getTopWindowReferrer').callsFake(() => mockRefAddress); + sandbox.stub(utils, 'getParameterByName').callsFake((arg) => { + switch (arg) { + case CATEGORY_NAME_QUERY_PARAM: + return CATEGORY_VALUE; + case NQ_NAME_QUERY_PARAM: + return NQ_VALUE; + } + }); + let testInput = + { + requestParams: { + [DATA_PARTNER_PIXEL_ID]: DATA_PARTNER_PIXEL_ID_VALUE, + [NQ]: NQ_VALUE, + }, + expectedPid: DATA_PARTNER_PIXEL_ID_VALUE, + expectedNq: [NQ_VALUE], + expectedCategory: [null], + expectedSubId: null, + expectedCors: mockOriginAddress, + expectedRef: mockRefAddress, + }; + let request = nanoBidAdapter.buildRequests([ + getBidRequest(testInput.requestParams)]); + expect(request.method).to.equal('POST'); + expect(request.url).to.equal(ENGINE_BASE_URL); + expect(request.data).to.equal(JSON.stringify([ + getBidResponse( + testInput.expectedPid, + testInput.expectedNq, + testInput.expectedCategory, + testInput.expectedSubId, + testInput.expectedCors, + testInput.expectedRef + ), + ])); + sandbox.restore(); + }); + it('Test buildRequest() - pid, nq, category', function () { + let mockOriginAddress = 'http://localhost'; + let mockRefAddress = 'http://some-ref.test'; + let sandbox = sinon.sandbox.create(); + sandbox.stub(utils, 'getOrigin').callsFake(() => mockOriginAddress); + sandbox.stub(utils, 'getTopWindowReferrer').callsFake(() => mockRefAddress); + sandbox.stub(utils, 'getParameterByName').callsFake((arg) => { + switch (arg) { + case CATEGORY_NAME_QUERY_PARAM: + return CATEGORY_VALUE; + case NQ_NAME_QUERY_PARAM: + return NQ_VALUE; + } + }); + let testInput = + { + requestParams: { + [DATA_PARTNER_PIXEL_ID]: DATA_PARTNER_PIXEL_ID_VALUE, + [NQ]: NQ_VALUE, + [CATEGORY]: CATEGORY_VALUE, + }, + expectedPid: DATA_PARTNER_PIXEL_ID_VALUE, + expectedNq: [NQ_VALUE], + expectedCategory: [CATEGORY_VALUE], + expectedSubId: null, + expectedCors: mockOriginAddress, + expectedRef: mockRefAddress, + }; + let request = nanoBidAdapter.buildRequests([ + getBidRequest(testInput.requestParams)]); + expect(request.method).to.equal('POST'); + expect(request.url).to.equal(ENGINE_BASE_URL); + expect(request.data).to.equal(JSON.stringify([ + getBidResponse( + testInput.expectedPid, + testInput.expectedNq, + testInput.expectedCategory, + testInput.expectedSubId, + testInput.expectedCors, + testInput.expectedRef + ), + ])); + sandbox.restore(); + }); + it('Test buildRequest() - pid, nq, categoryName', function () { + let mockOriginAddress = 'http://localhost'; + let mockRefAddress = 'http://some-ref.test'; + let sandbox = sinon.sandbox.create(); + sandbox.stub(utils, 'getOrigin').callsFake(() => mockOriginAddress); + sandbox.stub(utils, 'getTopWindowReferrer').callsFake(() => mockRefAddress); + sandbox.stub(utils, 'getParameterByName').callsFake((arg) => { + switch (arg) { + case CATEGORY_NAME_QUERY_PARAM: + return CATEGORY_VALUE; + case NQ_NAME_QUERY_PARAM: + return NQ_VALUE; + } + }); + let testInput = + { + requestParams: { + [DATA_PARTNER_PIXEL_ID]: DATA_PARTNER_PIXEL_ID_VALUE, + [NQ]: NQ_VALUE, + [CATEGORY_NAME]: CATEGORY_NAME_QUERY_PARAM, + }, + expectedPid: DATA_PARTNER_PIXEL_ID_VALUE, + expectedNq: [NQ_VALUE], + expectedCategory: [CATEGORY_VALUE], + expectedSubId: null, + expectedCors: mockOriginAddress, + expectedRef: mockRefAddress, + }; + let request = nanoBidAdapter.buildRequests([ + getBidRequest(testInput.requestParams)]); + expect(request.method).to.equal('POST'); + expect(request.url).to.equal(ENGINE_BASE_URL); + expect(request.data).to.equal(JSON.stringify([ + getBidResponse( + testInput.expectedPid, + testInput.expectedNq, + testInput.expectedCategory, + testInput.expectedSubId, + testInput.expectedCors, + testInput.expectedRef + ), + ])); + sandbox.restore(); + }); + it('Test buildRequest() - pid, nq, subId', function () { + let mockOriginAddress = 'http://localhost'; + let mockRefAddress = 'http://some-ref.test'; + let sandbox = sinon.sandbox.create(); + sandbox.stub(utils, 'getOrigin').callsFake(() => mockOriginAddress); + sandbox.stub(utils, 'getTopWindowReferrer').callsFake(() => mockRefAddress); + sandbox.stub(utils, 'getParameterByName').callsFake((arg) => { + switch (arg) { + case CATEGORY_NAME_QUERY_PARAM: + return CATEGORY_VALUE; + case NQ_NAME_QUERY_PARAM: + return NQ_VALUE; + } + }); + let testInput = + { + requestParams: { + [DATA_PARTNER_PIXEL_ID]: DATA_PARTNER_PIXEL_ID_VALUE, + [NQ]: NQ_VALUE, + [SUB_ID]: SUB_ID_VALUE, + }, + expectedPid: DATA_PARTNER_PIXEL_ID_VALUE, + expectedNq: [NQ_VALUE], + expectedCategory: [null], + expectedSubId: SUB_ID_VALUE, + expectedCors: mockOriginAddress, + expectedRef: mockRefAddress, + }; + let request = nanoBidAdapter.buildRequests([ + getBidRequest(testInput.requestParams)]); + expect(request.method).to.equal('POST'); + expect(request.url).to.equal(ENGINE_BASE_URL); + expect(request.data).to.equal(JSON.stringify([ + getBidResponse( + testInput.expectedPid, + testInput.expectedNq, + testInput.expectedCategory, + testInput.expectedSubId, + testInput.expectedCors, + testInput.expectedRef + ), + ])); + sandbox.restore(); + }); + it('Test buildRequest() - pid, category', function () { + let mockOriginAddress = 'http://localhost'; + let mockRefAddress = 'http://some-ref.test'; + let sandbox = sinon.sandbox.create(); + sandbox.stub(utils, 'getOrigin').callsFake(() => mockOriginAddress); + sandbox.stub(utils, 'getTopWindowReferrer').callsFake(() => mockRefAddress); + sandbox.stub(utils, 'getParameterByName').callsFake((arg) => { + switch (arg) { + case CATEGORY_NAME_QUERY_PARAM: + return CATEGORY_VALUE; + case NQ_NAME_QUERY_PARAM: + return NQ_VALUE; + } + }); + let testInput = + { + requestParams: { + [DATA_PARTNER_PIXEL_ID]: DATA_PARTNER_PIXEL_ID_VALUE, + [CATEGORY]: CATEGORY_VALUE, + }, + expectedPid: DATA_PARTNER_PIXEL_ID_VALUE, + expectedNq: [null], + expectedCategory: [CATEGORY_VALUE], + expectedSubId: null, + expectedCors: mockOriginAddress, + expectedRef: mockRefAddress, + }; + let request = nanoBidAdapter.buildRequests([ + getBidRequest(testInput.requestParams)]); + expect(request.method).to.equal('POST'); + expect(request.url).to.equal(ENGINE_BASE_URL); + expect(request.data).to.equal(JSON.stringify([ + getBidResponse( + testInput.expectedPid, + testInput.expectedNq, + testInput.expectedCategory, + testInput.expectedSubId, + testInput.expectedCors, + testInput.expectedRef + ), + ])); + sandbox.restore(); + }); + it('Test buildRequest() - pid, category, subId', function () { + let mockOriginAddress = 'http://localhost'; + let mockRefAddress = 'http://some-ref.test'; + let sandbox = sinon.sandbox.create(); + sandbox.stub(utils, 'getOrigin').callsFake(() => mockOriginAddress); + sandbox.stub(utils, 'getTopWindowReferrer').callsFake(() => mockRefAddress); + sandbox.stub(utils, 'getParameterByName').callsFake((arg) => { + switch (arg) { + case CATEGORY_NAME_QUERY_PARAM: + return CATEGORY_VALUE; + case NQ_NAME_QUERY_PARAM: + return NQ_VALUE; + } + }); + let testInput = + { + requestParams: { + [DATA_PARTNER_PIXEL_ID]: DATA_PARTNER_PIXEL_ID_VALUE, + [CATEGORY]: CATEGORY_VALUE, + [SUB_ID]: SUB_ID_VALUE, + }, + expectedPid: DATA_PARTNER_PIXEL_ID_VALUE, + expectedNq: [null], + expectedCategory: [CATEGORY_VALUE], + expectedSubId: SUB_ID_VALUE, + expectedCors: mockOriginAddress, + expectedRef: mockRefAddress, + }; + let request = nanoBidAdapter.buildRequests([ + getBidRequest(testInput.requestParams)]); + expect(request.method).to.equal('POST'); + expect(request.url).to.equal(ENGINE_BASE_URL); + expect(request.data).to.equal(JSON.stringify([ + getBidResponse( + testInput.expectedPid, + testInput.expectedNq, + testInput.expectedCategory, + testInput.expectedSubId, + testInput.expectedCors, + testInput.expectedRef + ), + ])); + sandbox.restore(); + }); + it('Test buildRequest() - pid, subId', function () { + let mockOriginAddress = 'http://localhost'; + let mockRefAddress = 'http://some-ref.test'; + let sandbox = sinon.sandbox.create(); + sandbox.stub(utils, 'getOrigin').callsFake(() => mockOriginAddress); + sandbox.stub(utils, 'getTopWindowReferrer').callsFake(() => mockRefAddress); + sandbox.stub(utils, 'getParameterByName').callsFake((arg) => { + switch (arg) { + case CATEGORY_NAME_QUERY_PARAM: + return CATEGORY_VALUE; + case NQ_NAME_QUERY_PARAM: + return NQ_VALUE; + } + }); + let testInput = + { + requestParams: { + [DATA_PARTNER_PIXEL_ID]: DATA_PARTNER_PIXEL_ID_VALUE, + [SUB_ID]: SUB_ID_VALUE, + }, + expectedPid: DATA_PARTNER_PIXEL_ID_VALUE, + expectedNq: [null], + expectedCategory: [null], + expectedSubId: SUB_ID_VALUE, + expectedCors: mockOriginAddress, + expectedRef: mockRefAddress, + }; + let request = nanoBidAdapter.buildRequests([ + getBidRequest(testInput.requestParams)]); + expect(request.method).to.equal('POST'); + expect(request.url).to.equal(ENGINE_BASE_URL); + expect(request.data).to.equal(JSON.stringify([ + getBidResponse( + testInput.expectedPid, + testInput.expectedNq, + testInput.expectedCategory, + testInput.expectedSubId, + testInput.expectedCors, + testInput.expectedRef + ), + ])); + sandbox.restore(); + }); + it('Test buildRequest() - pid, nq, category, subId', function () { + let mockOriginAddress = 'http://localhost'; + let mockRefAddress = 'http://some-ref.test'; + let sandbox = sinon.sandbox.create(); + sandbox.stub(utils, 'getOrigin').callsFake(() => mockOriginAddress); + sandbox.stub(utils, 'getTopWindowReferrer').callsFake(() => mockRefAddress); + sandbox.stub(utils, 'getParameterByName').callsFake((arg) => { + switch (arg) { + case CATEGORY_NAME_QUERY_PARAM: + return CATEGORY_VALUE; + case NQ_NAME_QUERY_PARAM: + return NQ_VALUE; + } + }); + let testInput = + { + requestParams: { + [DATA_PARTNER_PIXEL_ID]: DATA_PARTNER_PIXEL_ID_VALUE, + [NQ]: NQ_VALUE, + [CATEGORY]: CATEGORY_VALUE, + [SUB_ID]: SUB_ID_VALUE, + }, + expectedPid: DATA_PARTNER_PIXEL_ID_VALUE, + expectedNq: [NQ_VALUE], + expectedCategory: [CATEGORY_VALUE], + expectedSubId: SUB_ID_VALUE, + expectedCors: mockOriginAddress, + expectedRef: mockRefAddress, + }; + let request = nanoBidAdapter.buildRequests([ + getBidRequest(testInput.requestParams)]); + expect(request.method).to.equal('POST'); + expect(request.url).to.equal(ENGINE_BASE_URL); + expect(request.data).to.equal(JSON.stringify([ + getBidResponse( + testInput.expectedPid, + testInput.expectedNq, + testInput.expectedCategory, + testInput.expectedSubId, + testInput.expectedCors, + testInput.expectedRef + ), + ])); + sandbox.restore(); + }); + it('Test buildRequest() - pid, nqName, categoryName, subId', function () { + let mockOriginAddress = 'http://localhost'; + let mockRefAddress = 'http://some-ref.test'; + let sandbox = sinon.sandbox.create(); + sandbox.stub(utils, 'getOrigin').callsFake(() => mockOriginAddress); + sandbox.stub(utils, 'getTopWindowReferrer').callsFake(() => mockRefAddress); + sandbox.stub(utils, 'getParameterByName').callsFake((arg) => { + switch (arg) { + case CATEGORY_NAME_QUERY_PARAM: + return CATEGORY_VALUE; + case NQ_NAME_QUERY_PARAM: + return NQ_VALUE; + } + }); + let testInput = + { + requestParams: { + [DATA_PARTNER_PIXEL_ID]: DATA_PARTNER_PIXEL_ID_VALUE, + [NQ_NAME]: NQ_NAME_QUERY_PARAM, + [CATEGORY_NAME]: CATEGORY_NAME_QUERY_PARAM, + [SUB_ID]: SUB_ID_VALUE, + }, + expectedPid: DATA_PARTNER_PIXEL_ID_VALUE, + expectedNq: [NQ_VALUE], + expectedCategory: [CATEGORY_VALUE], + expectedSubId: SUB_ID_VALUE, + expectedCors: mockOriginAddress, + expectedRef: mockRefAddress, + }; + let request = nanoBidAdapter.buildRequests([ + getBidRequest(testInput.requestParams)]); + expect(request.method).to.equal('POST'); + expect(request.url).to.equal(ENGINE_BASE_URL); + expect(request.data).to.equal(JSON.stringify([ + getBidResponse( + testInput.expectedPid, + testInput.expectedNq, + testInput.expectedCategory, + testInput.expectedSubId, + testInput.expectedCors, + testInput.expectedRef + ), + ])); + sandbox.restore(); + }); + it('Test buildRequest() - pid, nq, category, subId, ref (value none)', function () { + let mockOriginAddress = 'http://localhost'; + let mockRefAddress = 'http://some-ref.test'; + let sandbox = sinon.sandbox.create(); + sandbox.stub(utils, 'getOrigin').callsFake(() => mockOriginAddress); + sandbox.stub(utils, 'getTopWindowReferrer').callsFake(() => mockRefAddress); + sandbox.stub(utils, 'getParameterByName').callsFake((arg) => { + switch (arg) { + case CATEGORY_NAME_QUERY_PARAM: + return CATEGORY_VALUE; + case NQ_NAME_QUERY_PARAM: + return NQ_VALUE; + } + }); + let testInput = + { + requestParams: { + [DATA_PARTNER_PIXEL_ID]: DATA_PARTNER_PIXEL_ID_VALUE, + [NQ]: NQ_VALUE, + [CATEGORY]: CATEGORY_VALUE, + [SUB_ID]: SUB_ID_VALUE, + [REF]: REF_NO_VALUE, + }, + expectedPid: DATA_PARTNER_PIXEL_ID_VALUE, + expectedNq: [NQ_VALUE], + expectedCategory: [CATEGORY_VALUE], + expectedSubId: SUB_ID_VALUE, + expectedCors: mockOriginAddress, + expectedRef: null, + }; + let request = nanoBidAdapter.buildRequests([ + getBidRequest(testInput.requestParams)]); + expect(request.method).to.equal('POST'); + expect(request.url).to.equal(ENGINE_BASE_URL); + expect(request.data).to.equal(JSON.stringify([ + getBidResponse( + testInput.expectedPid, + testInput.expectedNq, + testInput.expectedCategory, + testInput.expectedSubId, + testInput.expectedCors, + testInput.expectedRef + ), + ])); + sandbox.restore(); + }); + it('Test buildRequest() - pid, nq, category, subId, ref (value other)', function () { + let mockOriginAddress = 'http://localhost'; + let mockRefAddress = 'http://some-ref.test'; + let sandbox = sinon.sandbox.create(); + sandbox.stub(utils, 'getOrigin').callsFake(() => mockOriginAddress); + sandbox.stub(utils, 'getTopWindowReferrer').callsFake(() => mockRefAddress); + sandbox.stub(utils, 'getParameterByName').callsFake((arg) => { + switch (arg) { + case CATEGORY_NAME_QUERY_PARAM: + return CATEGORY_VALUE; + case NQ_NAME_QUERY_PARAM: + return NQ_VALUE; + } + }); + let testInput = + { + requestParams: { + [DATA_PARTNER_PIXEL_ID]: DATA_PARTNER_PIXEL_ID_VALUE, + [NQ]: NQ_VALUE, + [CATEGORY]: CATEGORY_VALUE, + [SUB_ID]: SUB_ID_VALUE, + [REF]: REF_OTHER_VALUE, + }, + expectedPid: DATA_PARTNER_PIXEL_ID_VALUE, + expectedNq: [NQ_VALUE], + expectedCategory: [CATEGORY_VALUE], + expectedSubId: SUB_ID_VALUE, + expectedCors: mockOriginAddress, + expectedRef: null, + }; + let request = nanoBidAdapter.buildRequests([ + getBidRequest(testInput.requestParams)]); + expect(request.method).to.equal('POST'); + expect(request.url).to.equal(ENGINE_BASE_URL); + expect(request.data).to.equal(JSON.stringify([ + getBidResponse( + testInput.expectedPid, + testInput.expectedNq, + testInput.expectedCategory, + testInput.expectedSubId, + testInput.expectedCors, + testInput.expectedRef + ), + ])); + sandbox.restore(); }); it('Test interpretResponse() length', function () { - let bids = nanoBidAdapter.interpretResponse({body: [getSingleBidResponse(true), getSingleBidResponse(false)]}); + let bids = nanoBidAdapter.interpretResponse({ + body: [ + // valid + { + id: '24a1c9ec270973', + cpm: CPM, + width: WIDTH1, + height: HEIGHT1, + ad: AD, + ttl: 360, + creativeId: 'TEST_ID', + netRevenue: false, + currency: 'EUR', + }, + // invalid + { + id: '24a1c9ec270973', + cpm: null, + width: WIDTH1, + height: HEIGHT1, + ad: AD, + ttl: 360, + creativeId: 'TEST_ID', + netRevenue: false, + currency: 'EUR', + } + ] + }); expect(bids.length).to.equal(1); }); it('Test interpretResponse() bids', function () { - let bid = nanoBidAdapter.interpretResponse({body: [getSingleBidResponse(true), getSingleBidResponse(false)]})[0]; - expect(bid.requestId).to.equal(VALID_BID.requestId); - expect(bid.cpm).to.equal(VALID_BID.cpm); - expect(bid.width).to.equal(VALID_BID.width); - expect(bid.height).to.equal(VALID_BID.height); - expect(bid.ad).to.equal(VALID_BID.ad); - expect(bid.ttl).to.equal(VALID_BID.ttl); - expect(bid.creativeId).to.equal(VALID_BID.creativeId); - expect(bid.currency).to.equal(VALID_BID.currency); + let bid = nanoBidAdapter.interpretResponse({ + body: [ + // valid + { + id: '24a1c9ec270973', + cpm: CPM, + width: WIDTH1, + height: HEIGHT1, + ad: AD, + ttl: 360, + creativeId: 'TEST_ID', + netRevenue: false, + currency: 'EUR', + }, + // invalid + { + id: '24a1c9ec270973', + cpm: null, + width: WIDTH1, + height: HEIGHT1, + ad: AD, + ttl: 360, + creativeId: 'TEST_ID', + netRevenue: false, + currency: 'EUR', + } + ] + })[0]; + expect(bid.requestId).to.equal('24a1c9ec270973'); + expect(bid.cpm).to.equal(CPM); + expect(bid.width).to.equal(WIDTH1); + expect(bid.height).to.equal(HEIGHT1); + expect(bid.ad).to.equal(AD); + expect(bid.ttl).to.equal(360); + expect(bid.creativeId).to.equal('TEST_ID'); + expect(bid.currency).to.equal('EUR'); }); }); }); From b3e260790274f415c4a90c83349ee69ec5244119 Mon Sep 17 00:00:00 2001 From: nanointeractive Date: Tue, 5 Jun 2018 09:18:40 +0200 Subject: [PATCH 10/12] Fixed documentation --- modules/nanointeractiveBidAdapter.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/modules/nanointeractiveBidAdapter.md b/modules/nanointeractiveBidAdapter.md index 7dbbe043fb6..eef95383451 100644 --- a/modules/nanointeractiveBidAdapter.md +++ b/modules/nanointeractiveBidAdapter.md @@ -107,7 +107,7 @@ The `nq` and `name` are mutually exclusive. If you pass both, `name` takes prece }] }]; -#### Example with `nqName` +#### Example with `name` var adUnits = [{ code: 'nano-div', sizes: [[300, 250], [300,600]], @@ -118,7 +118,7 @@ The `nq` and `name` are mutually exclusive. If you pass both, `name` takes prece category: 'automotive', // User searched "automobile search query" and it is in the URL like: // https://www....?search_param=automobile%20search%20query&... - nqName: 'search_param', + name: 'search_param', subId: '123' } }] @@ -139,7 +139,7 @@ The `nq` and `name` are mutually exclusive. If you pass both, `name` takes prece }] }]; -#### Example with `categoryName` and `nqName` +#### Example with `categoryName` and `name` var adUnits = [{ code: 'nano-div', sizes: [[300, 250], [300,600]], @@ -149,7 +149,7 @@ The `nq` and `name` are mutually exclusive. If you pass both, `name` takes prece pid: '5afaa0280ae8996eb578de53', category: 'automotive', categoryName: 'cat_name', - nqName: 'search_param', + name: 'search_param', subId: '123' } }] From d0c13302dc491d6b64566ce7be37690881619abd Mon Sep 17 00:00:00 2001 From: nanointeractive Date: Tue, 5 Jun 2018 09:23:02 +0200 Subject: [PATCH 11/12] Removed unnecessary parameter from documentation --- modules/nanointeractiveBidAdapter.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/modules/nanointeractiveBidAdapter.md b/modules/nanointeractiveBidAdapter.md index eef95383451..c72a424c9cd 100644 --- a/modules/nanointeractiveBidAdapter.md +++ b/modules/nanointeractiveBidAdapter.md @@ -12,7 +12,6 @@ Connects to Nano Interactive search retargeting Ad Server for bids. -
### Requirements: To be able to get identification key (`pid`), please contact us at
@@ -147,7 +146,6 @@ The `nq` and `name` are mutually exclusive. If you pass both, `name` takes prece bidder: 'nanointeractive', params: { pid: '5afaa0280ae8996eb578de53', - category: 'automotive', categoryName: 'cat_name', name: 'search_param', subId: '123' From 308442befd3d6ec383616a5987335ec52c13f174 Mon Sep 17 00:00:00 2001 From: nanointeractive Date: Thu, 7 Jun 2018 16:10:19 +0200 Subject: [PATCH 12/12] Cleaning up documentation --- modules/nanointeractiveBidAdapter.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/modules/nanointeractiveBidAdapter.md b/modules/nanointeractiveBidAdapter.md index c72a424c9cd..c1790ff6337 100644 --- a/modules/nanointeractiveBidAdapter.md +++ b/modules/nanointeractiveBidAdapter.md @@ -98,7 +98,6 @@ The `nq` and `name` are mutually exclusive. If you pass both, `name` takes prece bidder: 'nanointeractive', params: { pid: '5afaa0280ae8996eb578de53', - category: 'automotive', // User searched "automobile search query" (extracted from search text field) nq: 'automobile search query', subId: '123' @@ -114,7 +113,6 @@ The `nq` and `name` are mutually exclusive. If you pass both, `name` takes prece bidder: 'nanointeractive', params: { pid: '5afaa0280ae8996eb578de53', - category: 'automotive', // User searched "automobile search query" and it is in the URL like: // https://www....?search_param=automobile%20search%20query&... name: 'search_param',