mk9-prebid
Version:
Header Bidding Management Library
1,033 lines (936 loc) • 44 kB
JavaScript
import { expect } from 'chai';
import { ImproveDigitalAdServerJSClient, spec } from 'modules/improvedigitalBidAdapter.js';
import { config } from 'src/config.js';
import * as utils from 'src/utils.js';
describe('Improve Digital Adapter Tests', function () {
const idClient = new ImproveDigitalAdServerJSClient('hb');
const METHOD = 'GET';
const URL = 'https://ice.360yield.com/hb';
const PARAM_PREFIX = 'jsonp=';
const simpleBidRequest = {
bidder: 'improvedigital',
params: {
placementId: 1053688
},
adUnitCode: 'div-gpt-ad-1499748733608-0',
transactionId: 'f183e871-fbed-45f0-a427-c8a63c4c01eb',
bidId: '33e9500b21129f',
bidderRequestId: '2772c1e566670b',
auctionId: '192721e36a0239',
mediaTypes: {
banner: {
sizes: [[300, 250], [160, 600], ['blah', 150], [-1, 300], [300, -5]]
}
},
sizes: [[300, 250], [160, 600], ['blah', 150], [-1, 300], [300, -5]]
};
const videoParams = {
skip: 1,
skipmin: 5,
skipafter: 30
}
const instreamBidRequest = utils.deepClone(simpleBidRequest);
instreamBidRequest.mediaTypes = {
video: {
context: 'instream',
playerSize: [640, 480]
}
};
const outstreamBidRequest = utils.deepClone(simpleBidRequest);
outstreamBidRequest.mediaTypes = {
video: {
context: 'outstream',
playerSize: [640, 480]
}
};
const multiFormatBidRequest = utils.deepClone(simpleBidRequest);
multiFormatBidRequest.mediaTypes = {
banner: {
sizes: [[300, 250], [160, 600], ['blah', 150], [-1, 300], [300, -5]]
},
video: {
context: 'outstream',
playerSize: [640, 480]
}
};
const simpleSmartTagBidRequest = {
bidder: 'improvedigital',
bidId: '1a2b3c',
placementCode: 'placement1',
params: {
publisherId: 1032,
placementKey: 'data_team_test_hb_smoke_test'
}
};
const bidderRequest = {
bids: [simpleBidRequest]
};
const instreamBidderRequest = {
bids: [instreamBidRequest]
};
const outstreamBidderRequest = {
bids: [outstreamBidRequest]
};
const multiFormatBidderRequest = {
bids: [multiFormatBidRequest]
};
const bidderRequestGdpr = {
bids: [simpleBidRequest],
gdprConsent: {
consentString: 'BOJ/P2HOJ/P2HABABMAAAAAZ+A==',
vendorData: {},
gdprApplies: true
},
};
const bidderRequestReferrer = {
bids: [simpleBidRequest],
refererInfo: {
referer: 'https://blah.com/test.html',
},
};
describe('isBidRequestValid', function () {
it('should return false when no bid', function () {
expect(spec.isBidRequestValid()).to.equal(false);
});
it('should return false when no bid.params', function () {
const bid = {};
expect(spec.isBidRequestValid(bid)).to.equal(false);
});
it('should return false when both placementId and placementKey + publisherId are missing', function () {
const bid = { 'params': {} };
expect(spec.isBidRequestValid(bid)).to.equal(false);
});
it('should return false when only one of placementKey and publisherId is present', function () {
let bid = {
params: {
publisherId: 1234
}
};
expect(spec.isBidRequestValid(bid)).to.equal(false);
bid = {
params: {
placementKey: 'xyz'
}
};
expect(spec.isBidRequestValid(bid)).to.equal(false);
});
it('should return true when placementId is passed', function () {
expect(spec.isBidRequestValid(simpleBidRequest)).to.equal(true);
});
it('should return true when both placementKey and publisherId are passed', function () {
expect(spec.isBidRequestValid(simpleSmartTagBidRequest)).to.equal(true);
});
});
describe('buildRequests', function () {
it('should make a well-formed request objects', function () {
const requests = spec.buildRequests([simpleBidRequest], bidderRequest);
expect(requests).to.be.an('array');
expect(requests.length).to.equal(1);
const request = requests[0];
expect(request.method).to.equal(METHOD);
expect(request.url).to.equal(URL);
expect(request.bidderRequest).to.deep.equal(bidderRequest);
expect(request.data.substring(0, PARAM_PREFIX.length)).to.equal(PARAM_PREFIX);
const params = JSON.parse(decodeURIComponent(request.data.substring(PARAM_PREFIX.length)));
expect(params.bid_request).to.be.an('object');
expect(params.bid_request.id).to.be.a('string');
expect(params.bid_request.version).to.equal(`${spec.version}-${idClient.CONSTANTS.CLIENT_VERSION}`);
expect(params.bid_request.gdpr).to.not.exist;
expect(params.bid_request.us_privacy).to.not.exist;
expect(params.bid_request.schain).to.not.exist;
expect(params.bid_request.user).to.not.exist;
expect(params.bid_request.imp).to.deep.equal([
{
id: '33e9500b21129f',
pid: 1053688,
tid: 'f183e871-fbed-45f0-a427-c8a63c4c01eb',
banner: {}
}
]);
});
it('should make a well-formed request object for multi-format ad unit', function () {
const requests = spec.buildRequests([multiFormatBidRequest], multiFormatBidderRequest);
expect(requests).to.be.an('array');
expect(requests.length).to.equal(1);
const request = requests[0];
expect(request.method).to.equal(METHOD);
expect(request.url).to.equal(URL);
expect(request.bidderRequest).to.deep.equal(multiFormatBidderRequest);
expect(request.data.substring(0, PARAM_PREFIX.length)).to.equal(PARAM_PREFIX);
const params = JSON.parse(decodeURIComponent(request.data.substring(PARAM_PREFIX.length)));
expect(params.bid_request).to.be.an('object');
expect(params.bid_request.id).to.be.a('string');
expect(params.bid_request.version).to.equal(`${spec.version}-${idClient.CONSTANTS.CLIENT_VERSION}`);
expect(params.bid_request.gdpr).to.not.exist;
expect(params.bid_request.us_privacy).to.not.exist;
expect(params.bid_request.imp).to.deep.equal([
{
id: '33e9500b21129f',
pid: 1053688,
tid: 'f183e871-fbed-45f0-a427-c8a63c4c01eb',
banner: {}
}
]);
});
it('should set placementKey and publisherId for smart tags', function () {
const requests = spec.buildRequests([simpleSmartTagBidRequest], bidderRequest);
const params = JSON.parse(decodeURIComponent(requests[0].data.substring(PARAM_PREFIX.length)));
expect(params.bid_request.imp[0].pubid).to.equal(1032);
expect(params.bid_request.imp[0].pkey).to.equal('data_team_test_hb_smoke_test');
});
it('should add keyValues', function () {
const bidRequest = Object.assign({}, simpleBidRequest);
const keyValues = {
testKey: [
'testValue'
]
};
bidRequest.params.keyValues = keyValues;
const request = spec.buildRequests([bidRequest], bidderRequest)[0];
const params = JSON.parse(decodeURIComponent(request.data.substring(PARAM_PREFIX.length)));
expect(params.bid_request.imp[0].kvw).to.deep.equal(keyValues);
});
it('should add single size filter', function () {
const bidRequest = Object.assign({}, simpleBidRequest);
const size = {
w: 800,
h: 600
};
bidRequest.params.size = size;
const request = spec.buildRequests([bidRequest], bidderRequest)[0];
const params = JSON.parse(decodeURIComponent(request.data.substring(PARAM_PREFIX.length)));
expect(params.bid_request.imp[0].banner).to.deep.equal(size);
// When single size filter is set, format shouldn't be populated. This
// is to maintain backward compatibily
expect(params.bid_request.imp[0].banner.format).to.not.exist;
});
it('should add currency', function () {
const bidRequest = Object.assign({}, simpleBidRequest);
const getConfigStub = sinon.stub(config, 'getConfig').returns('JPY');
const request = spec.buildRequests([bidRequest], bidderRequest)[0];
const params = JSON.parse(decodeURIComponent(request.data.substring(PARAM_PREFIX.length)));
expect(params.bid_request.imp[0].currency).to.equal('JPY');
getConfigStub.restore();
});
it('should add bid floor', function () {
const bidRequest = Object.assign({}, simpleBidRequest);
let request = spec.buildRequests([bidRequest], bidderRequest)[0];
let params = JSON.parse(decodeURIComponent(request.data.substring(PARAM_PREFIX.length)));
// Floor price currency shouldn't be populated without a floor price
expect(params.bid_request.imp[0].bidfloorcur).to.not.exist;
// Default floor price currency
bidRequest.params.bidFloor = 0.05;
request = spec.buildRequests([bidRequest], bidderRequest)[0];
params = JSON.parse(decodeURIComponent(request.data.substring(PARAM_PREFIX.length)));
expect(params.bid_request.imp[0].bidfloor).to.equal(0.05);
expect(params.bid_request.imp[0].bidfloorcur).to.equal('USD');
// Floor price currency
bidRequest.params.bidFloorCur = 'eUR';
request = spec.buildRequests([bidRequest])[0];
params = JSON.parse(decodeURIComponent(request.data.substring(PARAM_PREFIX.length)));
expect(params.bid_request.imp[0].bidfloor).to.equal(0.05);
expect(params.bid_request.imp[0].bidfloorcur).to.equal('EUR');
// getFloor defined -> use it over bidFloor
let getFloorResponse = { currency: 'USD', floor: 3 };
bidRequest.getFloor = () => getFloorResponse;
request = spec.buildRequests([bidRequest])[0];
params = JSON.parse(decodeURIComponent(request.data.substring(PARAM_PREFIX.length)));
expect(params.bid_request.imp[0].bidfloor).to.equal(3);
expect(params.bid_request.imp[0].bidfloorcur).to.equal('USD');
});
it('should add GDPR consent string', function () {
const bidRequest = Object.assign({}, simpleBidRequest);
const request = spec.buildRequests([bidRequest], bidderRequestGdpr)[0];
const params = JSON.parse(decodeURIComponent(request.data.substring(PARAM_PREFIX.length)));
expect(params.bid_request.gdpr).to.equal('BOJ/P2HOJ/P2HABABMAAAAAZ+A==');
});
it('should add CCPA consent string', function () {
const bidRequest = Object.assign({}, simpleBidRequest);
const request = spec.buildRequests([bidRequest], { uspConsent: '1YYY' })[0];
const params = JSON.parse(decodeURIComponent(request.data.substring(PARAM_PREFIX.length)));
expect(params.bid_request.us_privacy).to.equal('1YYY');
});
it('should add referrer', function () {
const bidRequest = Object.assign({}, simpleBidRequest);
const request = spec.buildRequests([bidRequest], bidderRequestReferrer)[0];
const params = JSON.parse(decodeURIComponent(request.data.substring(PARAM_PREFIX.length)));
expect(params.bid_request.referrer).to.equal('https://blah.com/test.html');
});
it('should not add video params for banner', function () {
const bidRequest = JSON.parse(JSON.stringify(simpleBidRequest));
bidRequest.params.video = videoParams;
const request = spec.buildRequests([bidRequest], bidderRequest)[0];
const params = JSON.parse(decodeURIComponent(request.data.substring(PARAM_PREFIX.length)));
expect(params.bid_request.imp[0].video).to.not.exist;
});
it('should add ad type for instream video', function () {
let bidRequest = JSON.parse(JSON.stringify(simpleBidRequest));
bidRequest.mediaType = 'video';
let request = spec.buildRequests([bidRequest], bidderRequest)[0];
let params = JSON.parse(decodeURIComponent(request.data.substring(PARAM_PREFIX.length)));
expect(params.bid_request.imp[0].ad_types).to.deep.equal(['video']);
expect(params.bid_request.imp[0].video).to.not.exist;
bidRequest = JSON.parse(JSON.stringify(simpleBidRequest));
bidRequest.mediaTypes = {
video: {
context: 'instream',
playerSize: [640, 480]
}
};
request = spec.buildRequests([bidRequest], bidderRequest)[0];
params = JSON.parse(decodeURIComponent(request.data.substring(PARAM_PREFIX.length)));
expect(params.bid_request.imp[0].ad_types).to.deep.equal(['video']);
expect(params.bid_request.imp[0].video).to.not.exist;
});
it('should not set ad type for outstream video', function() {
const request = spec.buildRequests([outstreamBidRequest])[0];
const params = JSON.parse(decodeURIComponent(request.data.substring(PARAM_PREFIX.length)));
expect(params.bid_request.imp[0].ad_types).to.not.exist;
expect(params.bid_request.imp[0].video).to.not.exist;
});
it('should not set ad type for multi-format bids', function() {
const request = spec.buildRequests([multiFormatBidRequest], bidderRequest)[0];
const params = JSON.parse(decodeURIComponent(request.data.substring(PARAM_PREFIX.length)));
expect(params.bid_request.imp[0].ad_types).to.not.exist;
expect(params.bid_request.imp[0].video).to.not.exist;
});
it('should set video params for instream', function() {
const bidRequest = JSON.parse(JSON.stringify(instreamBidRequest));
bidRequest.params.video = videoParams;
const request = spec.buildRequests([bidRequest])[0];
const params = JSON.parse(decodeURIComponent(request.data.substring(PARAM_PREFIX.length)));
expect(params.bid_request.imp[0].video).to.deep.equal(videoParams);
});
it('should set skip params only if skip=1', function() {
const bidRequest = JSON.parse(JSON.stringify(instreamBidRequest));
// 1
const videoTest = {
skip: 1,
skipmin: 5,
skipafter: 30
}
bidRequest.params.video = videoTest;
let request = spec.buildRequests([bidRequest])[0];
let params = JSON.parse(decodeURIComponent(request.data.substring(PARAM_PREFIX.length)));
expect(params.bid_request.imp[0].video).to.deep.equal(videoTest);
// 0 - leave out skipmin and skipafter
videoTest.skip = 0;
bidRequest.params.video = videoTest;
request = spec.buildRequests([bidRequest])[0];
params = JSON.parse(decodeURIComponent(request.data.substring(PARAM_PREFIX.length)));
expect(params.bid_request.imp[0].video).to.deep.equal({ skip: 0 });
// other
videoTest.skip = 'blah';
bidRequest.params.video = videoTest;
request = spec.buildRequests([bidRequest])[0];
params = JSON.parse(decodeURIComponent(request.data.substring(PARAM_PREFIX.length)));
expect(params.bid_request.imp[0].video).to.not.exist;
});
it('should ignore invalid/unexpected video params', function() {
const bidRequest = JSON.parse(JSON.stringify(instreamBidRequest));
// 1
const videoTest = {
skip: 1,
skipmin: 5,
skipafter: 30
}
const videoTestInvParam = Object.assign({}, videoTest);
videoTestInvParam.blah = 1;
bidRequest.params.video = videoTestInvParam;
let request = spec.buildRequests([bidRequest])[0];
let params = JSON.parse(decodeURIComponent(request.data.substring(PARAM_PREFIX.length)));
expect(params.bid_request.imp[0].video).to.deep.equal(videoTest);
});
it('should set video params for outstream', function() {
const bidRequest = JSON.parse(JSON.stringify(outstreamBidRequest));
bidRequest.params.video = videoParams;
const request = spec.buildRequests([bidRequest])[0];
const params = JSON.parse(decodeURIComponent(request.data.substring(PARAM_PREFIX.length)));
expect(params.bid_request.imp[0].video).to.deep.equal(videoParams);
});
it('should set video params for multi-format', function() {
const bidRequest = JSON.parse(JSON.stringify(multiFormatBidRequest));
bidRequest.params.video = videoParams;
const request = spec.buildRequests([bidRequest])[0];
const params = JSON.parse(decodeURIComponent(request.data.substring(PARAM_PREFIX.length)));
expect(params.bid_request.imp[0].video).to.deep.equal(videoParams);
});
it('should not set Prebid sizes in bid request for instream video', function () {
const getConfigStub = sinon.stub(config, 'getConfig');
getConfigStub.withArgs('improvedigital.usePrebidSizes').returns(true);
const request = spec.buildRequests([instreamBidRequest], bidderRequest)[0];
const params = JSON.parse(decodeURIComponent(request.data.substring(PARAM_PREFIX.length)));
expect(params.bid_request.imp[0].banner.format).to.not.exist;
getConfigStub.restore();
});
it('should not set Prebid sizes in bid request for outstream video', function () {
const getConfigStub = sinon.stub(config, 'getConfig');
getConfigStub.withArgs('improvedigital.usePrebidSizes').returns(true);
const request = spec.buildRequests([outstreamBidRequest], bidderRequest)[0];
const params = JSON.parse(decodeURIComponent(request.data.substring(PARAM_PREFIX.length)));
expect(params.bid_request.imp[0].banner.format).to.not.exist;
getConfigStub.restore();
});
it('should not set Prebid sizes in multi-format bid request', function () {
const getConfigStub = sinon.stub(config, 'getConfig');
getConfigStub.withArgs('improvedigital.usePrebidSizes').returns(true);
const request = spec.buildRequests([multiFormatBidRequest], bidderRequest)[0];
const params = JSON.parse(decodeURIComponent(request.data.substring(PARAM_PREFIX.length)));
expect(params.bid_request.imp[0].banner.format).to.not.exist;
getConfigStub.restore();
});
it('should add schain', function () {
const schain = '{"ver":"1.0","complete":1,"nodes":[{"asi":"headerlift.com","sid":"xyz","hp":1}]}';
const bidRequest = Object.assign({}, simpleBidRequest);
bidRequest.schain = schain;
const request = spec.buildRequests([bidRequest], bidderRequestReferrer)[0];
const params = JSON.parse(decodeURIComponent(request.data.substring(PARAM_PREFIX.length)));
expect(params.bid_request.schain).to.equal(schain);
});
it('should add eids', function () {
const userId = { id5id: { uid: '1111' } };
const expectedUserObject = { ext: { eids: [{
source: 'id5-sync.com',
uids: [{
atype: 1,
id: '1111'
}]
}]}};
const bidRequest = Object.assign({}, simpleBidRequest);
bidRequest.userId = userId;
const request = spec.buildRequests([bidRequest], bidderRequestReferrer)[0];
const params = JSON.parse(decodeURIComponent(request.data.substring(PARAM_PREFIX.length)));
expect(params.bid_request.user).to.deep.equal(expectedUserObject);
});
it('should return 2 requests', function () {
const requests = spec.buildRequests([
simpleBidRequest,
simpleSmartTagBidRequest
], bidderRequest);
expect(requests).to.be.an('array');
expect(requests.length).to.equal(2);
expect(requests[0].bidderRequest).to.deep.equal(bidderRequest);
expect(requests[1].bidderRequest).to.deep.equal(bidderRequest);
});
it('should return one request in a single request mode', function () {
const getConfigStub = sinon.stub(config, 'getConfig');
getConfigStub.withArgs('improvedigital.singleRequest').returns(true);
const requests = spec.buildRequests([
simpleBidRequest,
simpleSmartTagBidRequest
], bidderRequest);
expect(requests).to.be.an('array');
expect(requests.length).to.equal(1);
getConfigStub.restore();
});
it('should set Prebid sizes in bid request', function () {
const getConfigStub = sinon.stub(config, 'getConfig');
getConfigStub.withArgs('improvedigital.usePrebidSizes').returns(true);
const request = spec.buildRequests([simpleBidRequest], bidderRequest)[0];
const params = JSON.parse(decodeURIComponent(request.data.substring(PARAM_PREFIX.length)));
expect(params.bid_request.imp[0].banner).to.deep.equal({
format: [
{ w: 300, h: 250 },
{ w: 160, h: 600 }
]
});
getConfigStub.restore();
});
it('should not add single size filter when using Prebid sizes', function () {
const getConfigStub = sinon.stub(config, 'getConfig');
getConfigStub.withArgs('improvedigital.usePrebidSizes').returns(true);
const bidRequest = Object.assign({}, simpleBidRequest);
const size = {
w: 800,
h: 600
};
bidRequest.params.size = size;
const request = spec.buildRequests([bidRequest], bidderRequest)[0];
const params = JSON.parse(decodeURIComponent(request.data.substring(PARAM_PREFIX.length)));
expect(params.bid_request.imp[0].banner).to.deep.equal({
format: [
{ w: 300, h: 250 },
{ w: 160, h: 600 }
]
});
getConfigStub.restore();
});
});
const serverResponse = {
'body': {
'id': '687a06c541d8d1',
'site_id': 191642,
'bid': [
{
'isNet': false,
'id': '33e9500b21129f',
'advid': '5279',
'price': 1.45888594164456,
'nurl': 'https://ice.360yield.com/imp_pixel?ic=wVmhKI07hCVyGC1sNdFp.6buOSiGYOw8jPyZLlcMY2RCwD4ek3Fy6.xUI7U002skGBs3objMBoNU-Frpvmb9js3NKIG0YZJgWaNdcpXY9gOXE9hY4-wxybCjVSNzhOQB-zic73hzcnJnKeoGgcfvt8fMy18-yD0aVdYWt4zbqdoITOkKNCPBEgbPFu1rcje-o7a64yZ7H3dKvtnIixXQYc1Ep86xGSBGXY6xW2KfUOMT6vnkemxO72divMkMdhR8cAuqIubbx-ZID8-xf5c9k7p6DseeBW0I8ionrlTHx.rGosgxhiFaMqtr7HiA7PBzKvPdeEYN0hQ8RYo8JzYL82hA91A3V2m9Ij6y0DfIJnnrKN8YORffhxmJ6DzwEl1zjrVFbD01bqB3Vdww8w8PQJSkKQkd313tr-atU8LS26fnBmOngEkVHwAr2WCKxuUvxHmuVBTA-Lgz7wKwMoOJCA3hFxMavVb0ZFB7CK0BUTVU6z0De92Q.FJKNCHLMbjX3vcAQ90=',
'h': 290,
'pid': 1053688,
'sync': [
'https://link1',
'https://link2'
],
'crid': '422031',
'w': 600,
'cid': '99006',
'adm': 'document.writeln(\"<a href=\\\"https:\\/\\/ice.360yield.com\\/click\\/wVmhKEKFeJufyP3hFfp7fv95ynoKe7vnG9V-j8EyAzklSoKRkownAclw4Zzcw-OcbJMg2KfjNiO8GoO9WP1jbNM8Q5GtmClbG9hZPBS4v6oBBiDi50AjRqHQsDAoBOJrIJtVyCfrnAIxvbysozCpLt20ov6jz2JPi6fe.D55HNeDLDyiLNgxVPa3y9jJZf65JBirCjOoZ-1Mj1BLB.57VdMaEhpGjjl5HnPgw0Pv7Hm1BO7PB9nCXJ9IwOH3IrKo.Wyy1iKDk6zeGwGOkQHSOMuQnCHyD35x6bhDQrpl5H6fTRTR8D2m5.-Zjh3fs8SKlo0i25EjKPw65iF.tvgcnq01U08OIh86EeSciamJgV0hNsk20TcTubfsoPN4are4nQ0y2gB-lz9tf3AjqHpSz5NoJWrpWtnrBHbjm.dS1XUQB1tzcLpIkA34nDe2eNxRZbZkZNSSs.Y8jQemfbjuLpttcemHqidFZo3xp37eSfUImw.HbyFdnK-wxFDYudgsIDxGJWI=\\/\\/https%3A%2F%2Fwww.improvedigital.com\\\" target=\\\"_blank\\\"><img style=\\\"border: 0;\\\" border=\\\"0\\\" width=\\\"600\\\" height=\\\"290\\\" src=\\\"https:\\/\\/creative.360yield.com\\/file\\/221728\\/ImproveDigital600x290.jpg\\\" alt=\\\"\\\"\\/><\\/a>\");document.writeln(\"<improvedigital_ad_output_information tp_id=\\\"\\\" buyer_id=\\\"0\\\" rtb_advertiser=\\\"\\\" campaign_id=\\\"99006\\\" line_item_id=\\\"268515\\\" creative_id=\\\"422031\\\" crid=\\\"0\\\" placement_id=\\\"1053688\\\"><\\/improvedigital_ad_output_information>\");'
}
],
'debug': ''
}
};
const serverResponseTwoBids = {
'body': {
'id': '687a06c541d8d1',
'site_id': 191642,
'bid': [
serverResponse.body.bid[0],
{
'isNet': true,
'id': '1234',
'advid': '5280',
'price': 1.23,
'nurl': 'https://link/imp_pixel?ic=wVmhKI07hCVyGC1sNdFp.6buOSiGYOw8jPyZLlcMY2RCwD4ek3Fy6.xUI7U002skGBs3objMBoNU-Frpvmb9js3NKIG0YZJgWaNdcpXY9gOXE9hY4-wxybCjVSNzhOQB-zic73hzcnJnKeoGgcfvt8fMy18-yD0aVdYWt4zbqdoITOkKNCPBEgbPFu1rcje-o7a64yZ7H3dKvtnIixXQYc1Ep86xGSBGXY6xW2KfUOMT6vnkemxO72divMkMdhR8cAuqIubbx-ZID8-xf5c9k7p6DseeBW0I8ionrlTHx.rGosgxhiFaMqtr7HiA7PBzKvPdeEYN0hQ8RYo8JzYL82hA91A3V2m9Ij6y0DfIJnnrKN8YORffhxmJ6DzwEl1zjrVFbD01bqB3Vdww8w8PQJSkKQkd313tr-atU8LS26fnBmOngEkVHwAr2WCKxuUvxHmuVBTA-Lgz7wKwMoOJCA3hFxMavVb0ZFB7CK0BUTVU6z0De92Q.FJKNCHLMbjX3vcAQ90=',
'h': 400,
'pid': 1053688,
'sync': [
'https://link3'
],
'crid': '422033',
'w': 700,
'cid': '99006',
'adm': 'document.writeln(\"<a href=\\\"https:\\/\\/ice.360yield.com\\/click\\/wVmhKEKFeJufyP3hFfp7fv95ynoKe7vnG9V-j8EyAzklSoKRkownAclw4Zzcw-OcbJMg2KfjNiO8GoO9WP1jbNM8Q5GtmClbG9hZPBS4v6oBBiDi50AjRqHQsDAoBOJrIJtVyCfrnAIxvbysozCpLt20ov6jz2JPi6fe.D55HNeDLDyiLNgxVPa3y9jJZf65JBirCjOoZ-1Mj1BLB.57VdMaEhpGjjl5HnPgw0Pv7Hm1BO7PB9nCXJ9IwOH3IrKo.Wyy1iKDk6zeGwGOkQHSOMuQnCHyD35x6bhDQrpl5H6fTRTR8D2m5.-Zjh3fs8SKlo0i25EjKPw65iF.tvgcnq01U08OIh86EeSciamJgV0hNsk20TcTubfsoPN4are4nQ0y2gB-lz9tf3AjqHpSz5NoJWrpWtnrBHbjm.dS1XUQB1tzcLpIkA34nDe2eNxRZbZkZNSSs.Y8jQemfbjuLpttcemHqidFZo3xp37eSfUImw.HbyFdnK-wxFDYudgsIDxGJWI=\\/\\/https%3A%2F%2Fwww.improvedigital.com\\\" target=\\\"_blank\\\"><img style=\\\"border: 0;\\\" border=\\\"0\\\" width=\\\"600\\\" height=\\\"290\\\" src=\\\"https:\\/\\/creative.360yield.com\\/file\\/221728\\/ImproveDigital600x290.jpg\\\" alt=\\\"\\\"\\/><\\/a>\");document.writeln(\"<improvedigital_ad_output_information tp_id=\\\"\\\" buyer_id=\\\"0\\\" rtb_advertiser=\\\"\\\" campaign_id=\\\"99006\\\" line_item_id=\\\"268515\\\" creative_id=\\\"422031\\\" crid=\\\"0\\\" placement_id=\\\"1053688\\\"><\\/improvedigital_ad_output_information>\");'
}
],
'debug': ''
}
};
const serverResponseNative = {
body: {
id: '687a06c541d8d1',
site_id: 191642,
bid: [
{
isNet: false,
id: '33e9500b21129f',
advid: '5279',
price: 1.45888594164456,
nurl: 'https://ice.360yield.com/imp_pixel?ic=wVm',
h: 290,
pid: 1053688,
sync: [
'https://link1',
'https://link2'
],
crid: '422031',
w: 600,
cid: '99006',
native: {
assets: [
{
title: {
text: 'Native title'
}
},
{
data: {
type: 1,
value: 'Improve Digital'
}
},
{
data: {
type: 2,
value: 'Native body'
}
},
{
data: {
type: 3,
value: '4' // rating
}
},
{
data: {
type: 4,
value: '10105' // likes
}
},
{
data: {
type: 5,
value: '150000' // downloads
}
},
{
data: {
type: 6,
value: '3.99' // price
}
},
{
data: {
type: 7,
value: '4.49' // salePrice
}
},
{
data: {
type: 8,
value: '(123) 456-7890' // phone
}
},
{
data: {
type: 9,
value: '123 Main Street, Anywhere USA' // address
}
},
{
data: {
type: 10,
value: 'body2'
}
},
{
data: {
type: 11,
value: 'https://myurl.com' // displayUrl
}
},
{
data: {
type: 12,
value: 'Do it' // cta
}
},
{
img: {
type: 1,
url: 'Should get ignored',
h: 300,
w: 400
}
},
{
img: {
type: 2,
url: 'https://blah.com/icon.jpg',
h: 30,
w: 40
}
},
{
img: {
type: 3,
url: 'https://blah.com/image.jpg',
h: 200,
w: 800
}
}
],
link: {
url: 'https://advertiser.com',
clicktrackers: [
'https://click.tracker.com/click?impid=123'
]
},
imptrackers: [
'https://imptrack1.com',
'https://imptrack2.com'
],
jstracker: '<script src=\"https://www.foobar.js\"></script>',
privacy: 'https://www.myprivacyurl.com'
}
}
],
debug: ''
}
};
const serverResponseVideo = {
'body': {
'id': '687a06c541d8d1',
'site_id': 191642,
'bid': [
{
'isNet': false,
'id': '33e9500b21129f',
'advid': '5279',
'price': 1.45888594164456,
'nurl': 'http://ice.360yield.com/imp_pixel?ic=wVmhKI07hCVyGC1sNdFp.6buOSiGYOw8jPyZLlcMY2RCwD4ek3Fy6.xUI7U002skGBs3objMBoNU-Frpvmb9js3NKIG0YZJgWaNdcpXY9gOXE9hY4-wxybCjVSNzhOQB-zic73hzcnJnKeoGgcfvt8fMy18-yD0aVdYWt4zbqdoITOkKNCPBEgbPFu1rcje-o7a64yZ7H3dKvtnIixXQYc1Ep86xGSBGXY6xW2KfUOMT6vnkemxO72divMkMdhR8cAuqIubbx-ZID8-xf5c9k7p6DseeBW0I8ionrlTHx.rGosgxhiFaMqtr7HiA7PBzKvPdeEYN0hQ8RYo8JzYL82hA91A3V2m9Ij6y0DfIJnnrKN8YORffhxmJ6DzwEl1zjrVFbD01bqB3Vdww8w8PQJSkKQkd313tr-atU8LS26fnBmOngEkVHwAr2WCKxuUvxHmuVBTA-Lgz7wKwMoOJCA3hFxMavVb0ZFB7CK0BUTVU6z0De92Q.FJKNCHLMbjX3vcAQ90=',
'h': 290,
'pid': 1053688,
'sync': [
'http://link1',
'http://link2'
],
'crid': '422031',
'w': 600,
'cid': '99006',
'adm': '<VAST></VAST>',
'ad_type': 'video'
}
],
'debug': ''
}
};
const nativeEventtrackers = [
{
event: 1,
method: 1,
url: 'https://www.mytracker.com/imptracker'
},
{
event: 1,
method: 2,
url: 'https://www.mytracker.com/tracker.js'
}
];
describe('interpretResponse', function () {
const expectedBid = [
{
'ad': '<img src=\"https://ice.360yield.com/imp_pixel?ic=wVmhKI07hCVyGC1sNdFp.6buOSiGYOw8jPyZLlcMY2RCwD4ek3Fy6.xUI7U002skGBs3objMBoNU-Frpvmb9js3NKIG0YZJgWaNdcpXY9gOXE9hY4-wxybCjVSNzhOQB-zic73hzcnJnKeoGgcfvt8fMy18-yD0aVdYWt4zbqdoITOkKNCPBEgbPFu1rcje-o7a64yZ7H3dKvtnIixXQYc1Ep86xGSBGXY6xW2KfUOMT6vnkemxO72divMkMdhR8cAuqIubbx-ZID8-xf5c9k7p6DseeBW0I8ionrlTHx.rGosgxhiFaMqtr7HiA7PBzKvPdeEYN0hQ8RYo8JzYL82hA91A3V2m9Ij6y0DfIJnnrKN8YORffhxmJ6DzwEl1zjrVFbD01bqB3Vdww8w8PQJSkKQkd313tr-atU8LS26fnBmOngEkVHwAr2WCKxuUvxHmuVBTA-Lgz7wKwMoOJCA3hFxMavVb0ZFB7CK0BUTVU6z0De92Q.FJKNCHLMbjX3vcAQ90=\" width=\"0\" height=\"0\" style=\"display:none\"><script>document.writeln(\"<a href=\\\"https:\\/\\/ice.360yield.com\\/click\\/wVmhKEKFeJufyP3hFfp7fv95ynoKe7vnG9V-j8EyAzklSoKRkownAclw4Zzcw-OcbJMg2KfjNiO8GoO9WP1jbNM8Q5GtmClbG9hZPBS4v6oBBiDi50AjRqHQsDAoBOJrIJtVyCfrnAIxvbysozCpLt20ov6jz2JPi6fe.D55HNeDLDyiLNgxVPa3y9jJZf65JBirCjOoZ-1Mj1BLB.57VdMaEhpGjjl5HnPgw0Pv7Hm1BO7PB9nCXJ9IwOH3IrKo.Wyy1iKDk6zeGwGOkQHSOMuQnCHyD35x6bhDQrpl5H6fTRTR8D2m5.-Zjh3fs8SKlo0i25EjKPw65iF.tvgcnq01U08OIh86EeSciamJgV0hNsk20TcTubfsoPN4are4nQ0y2gB-lz9tf3AjqHpSz5NoJWrpWtnrBHbjm.dS1XUQB1tzcLpIkA34nDe2eNxRZbZkZNSSs.Y8jQemfbjuLpttcemHqidFZo3xp37eSfUImw.HbyFdnK-wxFDYudgsIDxGJWI=\\/\\/https%3A%2F%2Fwww.improvedigital.com\\\" target=\\\"_blank\\\"><img style=\\\"border: 0;\\\" border=\\\"0\\\" width=\\\"600\\\" height=\\\"290\\\" src=\\\"https:\\/\\/creative.360yield.com\\/file\\/221728\\/ImproveDigital600x290.jpg\\\" alt=\\\"\\\"\\/><\\/a>\");document.writeln(\"<improvedigital_ad_output_information tp_id=\\\"\\\" buyer_id=\\\"0\\\" rtb_advertiser=\\\"\\\" campaign_id=\\\"99006\\\" line_item_id=\\\"268515\\\" creative_id=\\\"422031\\\" crid=\\\"0\\\" placement_id=\\\"1053688\\\"><\\/improvedigital_ad_output_information>\");</script>',
'creativeId': '422031',
'cpm': 1.45888594164456,
'currency': 'USD',
'height': 290,
'mediaType': 'banner',
'netRevenue': false,
'requestId': '33e9500b21129f',
'ttl': 300,
'width': 600
}
];
const expectedTwoBids = [
expectedBid[0],
{
'ad': '<img src=\"https://link/imp_pixel?ic=wVmhKI07hCVyGC1sNdFp.6buOSiGYOw8jPyZLlcMY2RCwD4ek3Fy6.xUI7U002skGBs3objMBoNU-Frpvmb9js3NKIG0YZJgWaNdcpXY9gOXE9hY4-wxybCjVSNzhOQB-zic73hzcnJnKeoGgcfvt8fMy18-yD0aVdYWt4zbqdoITOkKNCPBEgbPFu1rcje-o7a64yZ7H3dKvtnIixXQYc1Ep86xGSBGXY6xW2KfUOMT6vnkemxO72divMkMdhR8cAuqIubbx-ZID8-xf5c9k7p6DseeBW0I8ionrlTHx.rGosgxhiFaMqtr7HiA7PBzKvPdeEYN0hQ8RYo8JzYL82hA91A3V2m9Ij6y0DfIJnnrKN8YORffhxmJ6DzwEl1zjrVFbD01bqB3Vdww8w8PQJSkKQkd313tr-atU8LS26fnBmOngEkVHwAr2WCKxuUvxHmuVBTA-Lgz7wKwMoOJCA3hFxMavVb0ZFB7CK0BUTVU6z0De92Q.FJKNCHLMbjX3vcAQ90=\" width=\"0\" height=\"0\" style=\"display:none\"><script>document.writeln(\"<a href=\\\"https:\\/\\/ice.360yield.com\\/click\\/wVmhKEKFeJufyP3hFfp7fv95ynoKe7vnG9V-j8EyAzklSoKRkownAclw4Zzcw-OcbJMg2KfjNiO8GoO9WP1jbNM8Q5GtmClbG9hZPBS4v6oBBiDi50AjRqHQsDAoBOJrIJtVyCfrnAIxvbysozCpLt20ov6jz2JPi6fe.D55HNeDLDyiLNgxVPa3y9jJZf65JBirCjOoZ-1Mj1BLB.57VdMaEhpGjjl5HnPgw0Pv7Hm1BO7PB9nCXJ9IwOH3IrKo.Wyy1iKDk6zeGwGOkQHSOMuQnCHyD35x6bhDQrpl5H6fTRTR8D2m5.-Zjh3fs8SKlo0i25EjKPw65iF.tvgcnq01U08OIh86EeSciamJgV0hNsk20TcTubfsoPN4are4nQ0y2gB-lz9tf3AjqHpSz5NoJWrpWtnrBHbjm.dS1XUQB1tzcLpIkA34nDe2eNxRZbZkZNSSs.Y8jQemfbjuLpttcemHqidFZo3xp37eSfUImw.HbyFdnK-wxFDYudgsIDxGJWI=\\/\\/https%3A%2F%2Fwww.improvedigital.com\\\" target=\\\"_blank\\\"><img style=\\\"border: 0;\\\" border=\\\"0\\\" width=\\\"600\\\" height=\\\"290\\\" src=\\\"https:\\/\\/creative.360yield.com\\/file\\/221728\\/ImproveDigital600x290.jpg\\\" alt=\\\"\\\"\\/><\\/a>\");document.writeln(\"<improvedigital_ad_output_information tp_id=\\\"\\\" buyer_id=\\\"0\\\" rtb_advertiser=\\\"\\\" campaign_id=\\\"99006\\\" line_item_id=\\\"268515\\\" creative_id=\\\"422031\\\" crid=\\\"0\\\" placement_id=\\\"1053688\\\"><\\/improvedigital_ad_output_information>\");</script>',
'creativeId': '422033',
'cpm': 1.23,
'currency': 'USD',
'height': 400,
'mediaType': 'banner',
'netRevenue': true,
'requestId': '1234',
'ttl': 300,
'width': 700
}
];
const expectedBidNative = [
{
mediaType: 'native',
creativeId: '422031',
cpm: 1.45888594164456,
currency: 'USD',
height: 290,
netRevenue: false,
requestId: '33e9500b21129f',
ttl: 300,
width: 600,
native: {
title: 'Native title',
body: 'Native body',
body2: 'body2',
cta: 'Do it',
sponsoredBy: 'Improve Digital',
rating: '4',
likes: '10105',
downloads: '150000',
price: '3.99',
salePrice: '4.49',
phone: '(123) 456-7890',
address: '123 Main Street, Anywhere USA',
displayUrl: 'https://myurl.com',
icon: {
url: 'https://blah.com/icon.jpg',
height: 30,
width: 40
},
image: {
url: 'https://blah.com/image.jpg',
height: 200,
width: 800
},
clickUrl: 'https://advertiser.com',
clickTrackers: ['https://click.tracker.com/click?impid=123'],
impressionTrackers: [
'https://ice.360yield.com/imp_pixel?ic=wVm',
'https://imptrack1.com',
'https://imptrack2.com'
],
javascriptTrackers: '<script src=\"https://www.foobar.js\"></script>',
privacyLink: 'https://www.myprivacyurl.com'
}
}
];
const expectedBidInstreamVideo = [
{
'vastXml': '<VAST></VAST>',
'creativeId': '422031',
'cpm': 1.45888594164456,
'currency': 'USD',
'height': 290,
'mediaType': 'video',
'netRevenue': false,
'requestId': '33e9500b21129f',
'ttl': 300,
'width': 600
}
];
const expectedBidOutstreamVideo = utils.deepClone(expectedBidInstreamVideo);
expectedBidOutstreamVideo[0].adResponse = {
content: expectedBidOutstreamVideo[0].vastXml,
height: expectedBidOutstreamVideo[0].height,
width: expectedBidOutstreamVideo[0].width
};
it('should return a well-formed display bid', function () {
const bids = spec.interpretResponse(serverResponse, {bidderRequest});
expect(bids).to.deep.equal(expectedBid);
});
it('should return a well-formed display bid for multi-format ad unit', function () {
const bids = spec.interpretResponse(serverResponse, {bidderRequest: multiFormatBidderRequest});
expect(bids).to.deep.equal(expectedBid);
});
it('should return two bids', function () {
const bids = spec.interpretResponse(serverResponseTwoBids, {bidderRequest});
expect(bids).to.deep.equal(expectedTwoBids);
});
it('should set dealId correctly', function () {
const response = JSON.parse(JSON.stringify(serverResponse));
let bids;
delete response.body.bid[0].lid;
response.body.bid[0].buying_type = 'deal_id';
bids = spec.interpretResponse(response, {bidderRequest});
expect(bids[0].dealId).to.not.exist;
response.body.bid[0].lid = 268515;
delete response.body.bid[0].buying_type;
bids = spec.interpretResponse(response, {bidderRequest});
expect(bids[0].dealId).to.not.exist;
response.body.bid[0].lid = 268515;
response.body.bid[0].buying_type = 'rtb';
bids = spec.interpretResponse(response, {bidderRequest});
expect(bids[0].dealId).to.not.exist;
response.body.bid[0].lid = 268515;
response.body.bid[0].buying_type = 'classic';
bids = spec.interpretResponse(response, {bidderRequest});
expect(bids[0].dealId).to.equal(268515);
response.body.bid[0].lid = 268515;
response.body.bid[0].buying_type = 'deal_id';
bids = spec.interpretResponse(response, {bidderRequest});
expect(bids[0].dealId).to.equal(268515);
response.body.bid[0].lid = [ 268515, 12456, 34567 ];
response.body.bid[0].buying_type = 'deal_id';
bids = spec.interpretResponse(response, {bidderRequest});
expect(bids[0].dealId).to.not.exist;
response.body.bid[0].lid = [ 268515, 12456, 34567 ];
response.body.bid[0].buying_type = [ 'deal_id', 'classic' ];
bids = spec.interpretResponse(response, {bidderRequest});
expect(bids[0].dealId).to.not.exist;
response.body.bid[0].lid = [ 268515, 12456, 34567 ];
response.body.bid[0].buying_type = [ 'rtb', 'deal_id', 'deal_id' ];
bids = spec.interpretResponse(response, {bidderRequest});
expect(bids[0].dealId).to.equal(12456);
});
it('should set currency', function () {
const response = JSON.parse(JSON.stringify(serverResponse));
response.body.bid[0].currency = 'eur';
const bids = spec.interpretResponse(response, {bidderRequest});
expect(bids[0].currency).to.equal('EUR');
});
it('should return empty array for bad response or no price', function () {
let response = JSON.parse(JSON.stringify(serverResponse));
let bids;
// Price missing or 0
response.body.bid[0].price = 0;
bids = spec.interpretResponse(response, {bidderRequest});
expect(bids).to.deep.equal([]);
delete response.body.bid[0].price;
bids = spec.interpretResponse(response, {bidderRequest});
expect(bids).to.deep.equal([]);
response.body.bid[0].price = null;
bids = spec.interpretResponse(response, {bidderRequest});
expect(bids).to.deep.equal([]);
// errorCode present
response = JSON.parse(JSON.stringify(serverResponse));
response.body.bid[0].errorCode = undefined;
bids = spec.interpretResponse(response, {bidderRequest});
expect(bids).to.deep.equal([]);
// adm and native missing
response = JSON.parse(JSON.stringify(serverResponse));
delete response.body.bid[0].adm;
bids = spec.interpretResponse(response, {bidderRequest});
expect(bids).to.deep.equal([]);
response.body.bid[0].adm = null;
bids = spec.interpretResponse(response, {bidderRequest});
expect(bids).to.deep.equal([]);
});
it('should set netRevenue', function () {
const response = JSON.parse(JSON.stringify(serverResponse));
response.body.bid[0].isNet = true;
const bids = spec.interpretResponse(response, {bidderRequest});
expect(bids[0].netRevenue).to.equal(true);
});
it('should set advertiserDomains', function () {
const adomain = ['domain.com'];
const response = JSON.parse(JSON.stringify(serverResponse));
response.body.bid[0].adomain = adomain;
const bids = spec.interpretResponse(response, {bidderRequest});
expect(bids[0].meta.advertiserDomains).to.equal(adomain);
});
// Native ads
it('should return a well-formed native ad bid', function () {
let bids = spec.interpretResponse(serverResponseNative, {bidderRequest});
expect(bids[0].ortbNative).to.deep.equal(serverResponseNative.body.bid[0].native);
delete bids[0].ortbNative;
expect(bids).to.deep.equal(expectedBidNative);
// eventtrackers
const response = JSON.parse(JSON.stringify(serverResponseNative));
const expectedBids = JSON.parse(JSON.stringify(expectedBidNative));
response.body.bid[0].native.eventtrackers = nativeEventtrackers;
expectedBids[0].native.impressionTrackers = [
'https://ice.360yield.com/imp_pixel?ic=wVm',
'https://www.mytracker.com/imptracker'
];
expectedBids[0].native.javascriptTrackers = '<script src=\"https://www.mytracker.com/tracker.js\"></script>';
bids = spec.interpretResponse(response, {bidderRequest});
delete bids[0].ortbNative;
expect(bids).to.deep.equal(expectedBids);
});
// Video
it('should return a well-formed instream video bid', function () {
const bids = spec.interpretResponse(serverResponseVideo, {bidderRequest: instreamBidderRequest});
expect(bids).to.deep.equal(expectedBidInstreamVideo);
});
it('should return a well-formed outstream video bid', function () {
const bids = spec.interpretResponse(serverResponseVideo, {bidderRequest: outstreamBidderRequest});
expect(bids[0].renderer).to.exist;
delete (bids[0].renderer);
expect(bids).to.deep.equal(expectedBidOutstreamVideo);
});
it('should return a well-formed outstream video bid for multi-format ad unit', function () {
const bids = spec.interpretResponse(serverResponseVideo, {bidderRequest: multiFormatBidderRequest});
expect(bids[0].renderer).to.exist;
delete (bids[0].renderer);
expect(bids).to.deep.equal(expectedBidOutstreamVideo);
});
});
describe('getUserSyncs', function () {
const serverResponses = [ serverResponseTwoBids ];
it('should return no syncs when pixel syncing is disabled', function () {
const syncs = spec.getUserSyncs({ pixelEnabled: false }, serverResponses);
expect(syncs).to.deep.equal([]);
});
it('should return user syncs', function () {
const syncs = spec.getUserSyncs({ pixelEnabled: true }, serverResponses);
const expected = [
{ type: 'image', url: 'https://link1' },
{ type: 'image', url: 'https://link2' },
{ type: 'image', url: 'https://link3' }
];
expect(syncs).to.deep.equal(expected);
});
});
});