mk9-prebid
Version:
Header Bidding Management Library
1,477 lines (1,327 loc) • 76.4 kB
JavaScript
import {expect} from 'chai';
import {spec, USER_ID_CODE_TO_QUERY_ARG} from 'modules/openxBidAdapter.js';
import {newBidder} from 'src/adapters/bidderFactory.js';
import {BANNER, VIDEO} from 'src/mediaTypes.js';
import {userSync} from 'src/userSync.js';
import {config} from 'src/config.js';
import * as utils from 'src/utils.js';
const URLBASE = '/w/1.0/arj';
const URLBASEVIDEO = '/v/1.0/avjp';
describe('OpenxAdapter', function () {
const adapter = newBidder(spec);
/**
* Type Definitions
*/
/**
* @typedef {{
* impression: string,
* inview: string,
* click: string
* }}
*/
let OxArjTracking;
/**
* @typedef {{
* ads: {
* version: number,
* count: number,
* pixels: string,
* ad: Array<OxArjAdUnit>
* }
* }}
*/
let OxArjResponse;
/**
* @typedef {{
* adunitid: number,
* adid:number,
* type: string,
* htmlz: string,
* framed: number,
* is_fallback: number,
* ts: string,
* cpipc: number,
* pub_rev: string,
* tbd: ?string,
* adv_id: string,
* deal_id: string,
* auct_win_is_deal: number,
* brand_id: string,
* currency: string,
* idx: string,
* creative: Array<OxArjCreative>
* }}
*/
let OxArjAdUnit;
/**
* @typedef {{
* id: string,
* width: string,
* height: string,
* target: string,
* mime: string,
* media: string,
* tracking: OxArjTracking
* }}
*/
let OxArjCreative;
// HELPER METHODS
/**
* @type {OxArjCreative}
*/
const DEFAULT_TEST_ARJ_CREATIVE = {
id: '0',
width: 'test-width',
height: 'test-height',
target: 'test-target',
mime: 'test-mime',
media: 'test-media',
tracking: {
impression: 'test-impression',
inview: 'test-inview',
click: 'test-click'
}
};
/**
* @type {OxArjAdUnit}
*/
const DEFAULT_TEST_ARJ_AD_UNIT = {
adunitid: 0,
type: 'test-type',
html: 'test-html',
framed: 0,
is_fallback: 0,
ts: 'test-ts',
tbd: 'NaN',
deal_id: undefined,
auct_win_is_deal: undefined,
cpipc: 0,
pub_rev: 'test-pub_rev',
adv_id: 'test-adv_id',
brand_id: 'test-brand_id',
currency: 'test-currency',
idx: '0',
creative: [DEFAULT_TEST_ARJ_CREATIVE]
};
/**
* @type {OxArjResponse}
*/
const DEFAULT_ARJ_RESPONSE = {
ads: {
version: 0,
count: 1,
pixels: 'https://testpixels.net',
ad: [DEFAULT_TEST_ARJ_AD_UNIT]
}
};
// Sample bid requests
const BANNER_BID_REQUESTS_WITH_MEDIA_TYPES = [{
bidder: 'openx',
params: {
unit: '11',
delDomain: 'test-del-domain'
},
adUnitCode: '/adunit-code/test-path',
mediaTypes: {
banner: {
sizes: [[300, 250], [300, 600]]
}
},
bidId: 'test-bid-id-1',
bidderRequestId: 'test-bid-request-1',
auctionId: 'test-auction-1',
ortb2Imp: { ext: { data: { pbadslot: '/12345/my-gpt-tag-0' } } },
}, {
bidder: 'openx',
params: {
unit: '22',
delDomain: 'test-del-domain'
},
adUnitCode: 'adunit-code',
mediaTypes: {
banner: {
sizes: [[728, 90]]
}
},
bidId: 'test-bid-id-2',
bidderRequestId: 'test-bid-request-2',
auctionId: 'test-auction-2',
ortb2Imp: { ext: { data: { pbadslot: '/12345/my-gpt-tag-1' } } },
}];
const VIDEO_BID_REQUESTS_WITH_MEDIA_TYPES = [{
bidder: 'openx',
mediaTypes: {
video: {
playerSize: [640, 480]
}
},
params: {
unit: '12345678',
delDomain: 'test-del-domain'
},
adUnitCode: 'adunit-code',
bidId: '30b31c1838de1e',
bidderRequestId: '22edbae2733bf6',
auctionId: '1d1a030790a475',
transactionId: '4008d88a-8137-410b-aa35-fbfdabcb478e',
ortb2Imp: { ext: { data: { pbadslot: '/12345/my-gpt-tag-0' } } },
}];
const MULTI_FORMAT_BID_REQUESTS = [{
bidder: 'openx',
params: {
unit: '12345678',
delDomain: 'test-del-domain'
},
adUnitCode: 'adunit-code',
mediaTypes: {
banner: {
sizes: [[300, 250]]
},
video: {
playerSize: [300, 250]
}
},
bidId: '30b31c1838de1e',
bidderRequestId: '22edbae2733bf6',
auctionId: '1d1a030790a475',
transactionId: '4008d88a-8137-410b-aa35-fbfdabcb478e',
ortb2Imp: { ext: { data: { pbadslot: '/12345/my-gpt-tag-0' } } },
}];
describe('inherited functions', function () {
it('exists and is a function', function () {
expect(adapter.callBids).to.exist.and.to.be.a('function');
});
});
describe('isBidRequestValid', function () {
describe('when request is for a banner ad', function () {
let bannerBid;
beforeEach(function () {
bannerBid = {
bidder: 'openx',
params: {},
adUnitCode: 'adunit-code',
mediaTypes: {banner: {}},
sizes: [[300, 250], [300, 600]],
bidId: '30b31c1838de1e',
bidderRequestId: '22edbae2733bf6',
auctionId: '1d1a030790a475'
};
});
it('should return false when there is no delivery domain', function () {
bannerBid.params = {'unit': '12345678'};
expect(spec.isBidRequestValid(bannerBid)).to.equal(false);
});
describe('when there is a delivery domain', function () {
beforeEach(function () {
bannerBid.params = {delDomain: 'test-delivery-domain'}
});
it('should return false when there is no ad unit id and size', function () {
expect(spec.isBidRequestValid(bannerBid)).to.equal(false);
});
it('should return true if there is an adunit id ', function () {
bannerBid.params.unit = '12345678';
expect(spec.isBidRequestValid(bannerBid)).to.equal(true);
});
it('should return true if there is no adunit id and sizes are defined', function () {
bannerBid.mediaTypes.banner.sizes = [720, 90];
expect(spec.isBidRequestValid(bannerBid)).to.equal(true);
});
it('should return false if no sizes are defined ', function () {
expect(spec.isBidRequestValid(bannerBid)).to.equal(false);
});
it('should return false if sizes empty ', function () {
bannerBid.mediaTypes.banner.sizes = [];
expect(spec.isBidRequestValid(bannerBid)).to.equal(false);
});
});
});
describe('when request is for a multiformat ad', function () {
describe('and request config uses mediaTypes video and banner', () => {
it('should return true multisize when required params found', function () {
expect(spec.isBidRequestValid(MULTI_FORMAT_BID_REQUESTS[0])).to.equal(true);
});
});
});
describe('when request is for a video ad', function () {
describe('and request config uses mediaTypes', () => {
const videoBidWithMediaTypes = {
bidder: 'openx',
params: {
unit: '12345678',
delDomain: 'test-del-domain'
},
adUnitCode: 'adunit-code',
mediaTypes: {
video: {
playerSize: [640, 480]
}
},
bidId: '30b31c1838de1e',
bidderRequestId: '22edbae2733bf6',
auctionId: '1d1a030790a475',
transactionId: '4008d88a-8137-410b-aa35-fbfdabcb478e'
};
it('should return true when required params found', function () {
expect(spec.isBidRequestValid(videoBidWithMediaTypes)).to.equal(true);
});
it('should return false when required params are not passed', function () {
let videoBidWithMediaTypes = Object.assign({}, videoBidWithMediaTypes);
videoBidWithMediaTypes.params = {};
expect(spec.isBidRequestValid(videoBidWithMediaTypes)).to.equal(false);
});
});
describe('and request config uses both delDomain and platform', () => {
const videoBidWithDelDomainAndPlatform = {
bidder: 'openx',
params: {
unit: '12345678',
delDomain: 'test-del-domain',
platform: '1cabba9e-cafe-3665-beef-f00f00f00f00'
},
adUnitCode: 'adunit-code',
mediaTypes: {
video: {
playerSize: [640, 480]
}
},
bidId: '30b31c1838de1e',
bidderRequestId: '22edbae2733bf6',
auctionId: '1d1a030790a475',
transactionId: '4008d88a-8137-410b-aa35-fbfdabcb478e'
};
it('should return true when required params found', function () {
expect(spec.isBidRequestValid(videoBidWithDelDomainAndPlatform)).to.equal(true);
});
it('should return false when required params are not passed', function () {
let videoBidWithMediaTypes = Object.assign({}, videoBidWithDelDomainAndPlatform);
videoBidWithMediaTypes.params = {};
expect(spec.isBidRequestValid(videoBidWithMediaTypes)).to.equal(false);
});
});
describe('and request config uses mediaType', () => {
const videoBidWithMediaType = {
'bidder': 'openx',
'params': {
'unit': '12345678',
'delDomain': 'test-del-domain'
},
'adUnitCode': 'adunit-code',
'mediaType': 'video',
'sizes': [640, 480],
'bidId': '30b31c1838de1e',
'bidderRequestId': '22edbae2733bf6',
'auctionId': '1d1a030790a475',
'transactionId': '4008d88a-8137-410b-aa35-fbfdabcb478e'
};
it('should return true when required params found', function () {
expect(spec.isBidRequestValid(videoBidWithMediaType)).to.equal(true);
});
it('should return false when required params are not passed', function () {
let videoBidWithMediaType = Object.assign({}, videoBidWithMediaType);
delete videoBidWithMediaType.params;
videoBidWithMediaType.params = {};
expect(spec.isBidRequestValid(videoBidWithMediaType)).to.equal(false);
});
});
describe('and request config uses test', () => {
const videoBidWithTest = {
bidder: 'openx',
params: {
unit: '12345678',
delDomain: 'test-del-domain',
test: true
},
adUnitCode: 'adunit-code',
mediaTypes: {
video: {
playerSize: [640, 480]
}
},
bidId: '30b31c1838de1e',
bidderRequestId: '22edbae2733bf6',
auctionId: '1d1a030790a475',
transactionId: '4008d88a-8137-410b-aa35-fbfdabcb478e'
};
let mockBidderRequest = {refererInfo: {}};
it('should return true when required params found', function () {
expect(spec.isBidRequestValid(videoBidWithTest)).to.equal(true);
});
it('should send video bid request to openx url via GET, with vtest=1 video parameter', function () {
const request = spec.buildRequests([videoBidWithTest], mockBidderRequest);
expect(request[0].data.vtest).to.equal(1);
});
});
});
});
describe('buildRequests for banner ads', function () {
const bidRequestsWithMediaTypes = BANNER_BID_REQUESTS_WITH_MEDIA_TYPES;
const bidRequestsWithPlatform = [{
'bidder': 'openx',
'params': {
'unit': '11',
'platform': '1cabba9e-cafe-3665-beef-f00f00f00f00'
},
'adUnitCode': '/adunit-code/test-path',
mediaTypes: {
banner: {
sizes: [[300, 250], [300, 600]]
}
},
'bidId': 'test-bid-id-1',
'bidderRequestId': 'test-bid-request-1',
'auctionId': 'test-auction-1'
}, {
'bidder': 'openx',
'params': {
'unit': '11',
'platform': '1cabba9e-cafe-3665-beef-f00f00f00f00'
},
'adUnitCode': '/adunit-code/test-path',
mediaTypes: {
banner: {
sizes: [[300, 250], [300, 600]]
}
},
'bidId': 'test-bid-id-1',
'bidderRequestId': 'test-bid-request-1',
'auctionId': 'test-auction-1'
}];
const mockBidderRequest = {refererInfo: {}};
it('should send bid request to openx url via GET, with mediaTypes specified with banner type', function () {
const request = spec.buildRequests(bidRequestsWithMediaTypes, mockBidderRequest);
expect(request[0].url).to.equal('https://' + bidRequestsWithMediaTypes[0].params.delDomain + URLBASE);
expect(request[0].data.ph).to.be.undefined;
expect(request[0].method).to.equal('GET');
});
it('should send bid request to openx platform url via GET, if platform is present', function () {
const request = spec.buildRequests(bidRequestsWithPlatform, mockBidderRequest);
expect(request[0].url).to.equal(`https://u.openx.net${URLBASE}`);
expect(request[0].data.ph).to.equal(bidRequestsWithPlatform[0].params.platform);
expect(request[0].method).to.equal('GET');
});
it('should send bid request to openx platform url via GET, if both params present', function () {
const bidRequestsWithPlatformAndDelDomain = [{
'bidder': 'openx',
'params': {
'unit': '11',
'delDomain': 'test-del-domain',
'platform': '1cabba9e-cafe-3665-beef-f00f00f00f00'
},
'adUnitCode': '/adunit-code/test-path',
mediaTypes: {
banner: {
sizes: [[300, 250], [300, 600]]
}
},
'bidId': 'test-bid-id-1',
'bidderRequestId': 'test-bid-request-1',
'auctionId': 'test-auction-1'
}, {
'bidder': 'openx',
'params': {
'unit': '11',
'delDomain': 'test-del-domain',
'platform': '1cabba9e-cafe-3665-beef-f00f00f00f00'
},
'adUnitCode': '/adunit-code/test-path',
mediaTypes: {
banner: {
sizes: [[300, 250], [300, 600]]
}
},
'bidId': 'test-bid-id-1',
'bidderRequestId': 'test-bid-request-1',
'auctionId': 'test-auction-1'
}];
const request = spec.buildRequests(bidRequestsWithPlatformAndDelDomain, mockBidderRequest);
expect(request[0].url).to.equal(`https://u.openx.net${URLBASE}`);
expect(request[0].data.ph).to.equal(bidRequestsWithPlatform[0].params.platform);
expect(request[0].method).to.equal('GET');
});
it('should send the adunit codes', function () {
const request = spec.buildRequests(bidRequestsWithMediaTypes, mockBidderRequest);
expect(request[0].data.divids).to.equal(`${encodeURIComponent(bidRequestsWithMediaTypes[0].adUnitCode)},${encodeURIComponent(bidRequestsWithMediaTypes[1].adUnitCode)}`);
});
it('should send the gpids', function () {
const request = spec.buildRequests(bidRequestsWithMediaTypes, mockBidderRequest);
expect(request[0].data.aucs).to.equal(`${encodeURIComponent('/12345/my-gpt-tag-0')},${encodeURIComponent('/12345/my-gpt-tag-1')}`);
});
it('should send ad unit ids when any are defined', function () {
const bidRequestsWithUnitIds = [{
'bidder': 'openx',
'params': {
'delDomain': 'test-del-domain'
},
'adUnitCode': 'adunit-code',
mediaTypes: {
banner: {
sizes: [[300, 250], [300, 600]]
}
},
'bidId': 'test-bid-id-1',
'bidderRequestId': 'test-bid-request-1',
'auctionId': 'test-auction-1'
}, {
'bidder': 'openx',
'params': {
'unit': '22',
'delDomain': 'test-del-domain'
},
'adUnitCode': 'adunit-code',
mediaTypes: {
banner: {
sizes: [[728, 90]]
}
},
'bidId': 'test-bid-id-2',
'bidderRequestId': 'test-bid-request-2',
'auctionId': 'test-auction-2'
}];
const request = spec.buildRequests(bidRequestsWithUnitIds, mockBidderRequest);
expect(request[0].data.auid).to.equal(`,${bidRequestsWithUnitIds[1].params.unit}`);
});
it('should not send any ad unit ids when none are defined', function () {
const bidRequestsWithoutUnitIds = [{
'bidder': 'openx',
'params': {
'delDomain': 'test-del-domain'
},
'adUnitCode': 'adunit-code',
mediaTypes: {
banner: {
sizes: [[300, 250], [300, 600]]
}
},
'bidId': 'test-bid-id-1',
'bidderRequestId': 'test-bid-request-1',
'auctionId': 'test-auction-1'
}, {
'bidder': 'openx',
'params': {
'delDomain': 'test-del-domain'
},
'adUnitCode': 'adunit-code',
mediaTypes: {
banner: {
sizes: [[728, 90]]
}
},
'bidId': 'test-bid-id-2',
'bidderRequestId': 'test-bid-request-2',
'auctionId': 'test-auction-2'
}];
const request = spec.buildRequests(bidRequestsWithoutUnitIds, mockBidderRequest);
expect(request[0].data).to.not.have.any.keys('auid');
});
it('should send out custom params on bids that have customParams specified', function () {
const bidRequest = Object.assign({},
bidRequestsWithMediaTypes[0],
{
params: {
'unit': '12345678',
'delDomain': 'test-del-domain',
'customParams': {'Test1': 'testval1+', 'test2': ['testval2/', 'testval3']}
}
}
);
const request = spec.buildRequests([bidRequest], mockBidderRequest);
const dataParams = request[0].data;
expect(dataParams.tps).to.exist;
expect(dataParams.tps).to.equal(btoa('test1=testval1.&test2=testval2_,testval3'));
});
it('should send out custom bc parameter, if override is present', function () {
const bidRequest = Object.assign({},
bidRequestsWithMediaTypes[0],
{
params: {
'unit': '12345678',
'delDomain': 'test-del-domain',
'bc': 'hb_override'
}
}
);
const request = spec.buildRequests([bidRequest], mockBidderRequest);
const dataParams = request[0].data;
expect(dataParams.bc).to.exist;
expect(dataParams.bc).to.equal('hb_override');
});
it('should not send any consent management properties', function () {
const request = spec.buildRequests(bidRequestsWithMediaTypes, mockBidderRequest);
expect(request[0].data.gdpr).to.equal(undefined);
expect(request[0].data.gdpr_consent).to.equal(undefined);
expect(request[0].data.x_gdpr_f).to.equal(undefined);
});
describe('when there is a consent management framework', function () {
let bidRequests;
let mockConfig;
let bidderRequest;
const IAB_CONSENT_FRAMEWORK_CODE = 1;
beforeEach(function () {
bidRequests = [{
bidder: 'openx',
params: {
unit: '12345678-banner',
delDomain: 'test-del-domain'
},
adUnitCode: 'adunit-code',
mediaTypes: {
banner: {
sizes: [[300, 250], [300, 600]]
}
},
bidId: 'test-bid-id',
bidderRequestId: 'test-bidder-request-id',
auctionId: 'test-auction-id'
}, {
'bidder': 'openx',
'mediaTypes': {
video: {
playerSize: [640, 480]
}
},
'params': {
'unit': '12345678-video',
'delDomain': 'test-del-domain'
},
'adUnitCode': 'adunit-code',
bidId: 'test-bid-id',
bidderRequestId: 'test-bidder-request-id',
auctionId: 'test-auction-id',
transactionId: '4008d88a-8137-410b-aa35-fbfdabcb478e'
}];
});
afterEach(function () {
config.getConfig.restore();
});
describe('when us_privacy applies', function () {
beforeEach(function () {
bidderRequest = {
uspConsent: '1YYN',
refererInfo: {}
};
sinon.stub(config, 'getConfig').callsFake((key) => {
return utils.deepAccess(mockConfig, key);
});
});
it('should send a signal to specify that GDPR applies to this request', function () {
const request = spec.buildRequests(bidRequests, bidderRequest);
expect(request[0].data.us_privacy).to.equal('1YYN');
expect(request[1].data.us_privacy).to.equal('1YYN');
});
});
describe('when us_privacy does not applies', function () {
beforeEach(function () {
bidderRequest = {
refererInfo: {}
};
sinon.stub(config, 'getConfig').callsFake((key) => {
return utils.deepAccess(mockConfig, key);
});
});
it('should not send the consent string, when consent string is undefined', function () {
delete bidderRequest.uspConsent;
const request = spec.buildRequests(bidRequests, bidderRequest);
expect(request[0].data).to.not.have.property('us_privacy');
expect(request[1].data).to.not.have.property('us_privacy');
});
});
describe('when GDPR applies', function () {
beforeEach(function () {
bidderRequest = {
gdprConsent: {
consentString: 'test-gdpr-consent-string',
gdprApplies: true
},
refererInfo: {}
};
mockConfig = {
consentManagement: {
cmpApi: 'iab',
timeout: 1111,
allowAuctionWithoutConsent: 'cancel'
}
};
sinon.stub(config, 'getConfig').callsFake((key) => {
return utils.deepAccess(mockConfig, key);
});
});
it('should send a signal to specify that GDPR applies to this request', function () {
const request = spec.buildRequests(bidRequests, bidderRequest);
expect(request[0].data.gdpr).to.equal(1);
expect(request[1].data.gdpr).to.equal(1);
});
it('should send the consent string', function () {
const request = spec.buildRequests(bidRequests, bidderRequest);
expect(request[0].data.gdpr_consent).to.equal(bidderRequest.gdprConsent.consentString);
expect(request[1].data.gdpr_consent).to.equal(bidderRequest.gdprConsent.consentString);
});
it('should send the consent management framework code', function () {
const request = spec.buildRequests(bidRequests, bidderRequest);
expect(request[0].data.x_gdpr_f).to.equal(IAB_CONSENT_FRAMEWORK_CODE);
expect(request[1].data.x_gdpr_f).to.equal(IAB_CONSENT_FRAMEWORK_CODE);
});
});
describe('when GDPR does not apply', function () {
beforeEach(function () {
bidderRequest = {
gdprConsent: {
consentString: 'test-gdpr-consent-string',
gdprApplies: false
},
refererInfo: {}
};
mockConfig = {
consentManagement: {
cmpApi: 'iab',
timeout: 1111,
allowAuctionWithoutConsent: 'cancel'
}
};
sinon.stub(config, 'getConfig').callsFake((key) => {
return utils.deepAccess(mockConfig, key);
});
});
it('should not send a signal to specify that GDPR does not apply to this request', function () {
const request = spec.buildRequests(bidRequests, bidderRequest);
expect(request[0].data.gdpr).to.equal(0);
expect(request[1].data.gdpr).to.equal(0);
});
it('should send the consent string', function () {
const request = spec.buildRequests(bidRequests, bidderRequest);
expect(request[0].data.gdpr_consent).to.equal(bidderRequest.gdprConsent.consentString);
expect(request[1].data.gdpr_consent).to.equal(bidderRequest.gdprConsent.consentString);
});
it('should send the consent management framework code', function () {
const request = spec.buildRequests(bidRequests, bidderRequest);
expect(request[0].data.x_gdpr_f).to.equal(IAB_CONSENT_FRAMEWORK_CODE);
expect(request[1].data.x_gdpr_f).to.equal(IAB_CONSENT_FRAMEWORK_CODE);
});
});
describe('when GDPR consent has undefined data', function () {
beforeEach(function () {
bidderRequest = {
gdprConsent: {
consentString: 'test-gdpr-consent-string',
gdprApplies: true
},
refererInfo: {}
};
mockConfig = {
consentManagement: {
cmpApi: 'iab',
timeout: 1111,
allowAuctionWithoutConsent: 'cancel'
}
};
sinon.stub(config, 'getConfig').callsFake((key) => {
return utils.deepAccess(mockConfig, key);
});
});
it('should not send a signal to specify whether GDPR applies to this request, when GDPR application is undefined', function () {
delete bidderRequest.gdprConsent.gdprApplies;
const request = spec.buildRequests(bidRequests, bidderRequest);
expect(request[0].data).to.not.have.property('gdpr');
expect(request[1].data).to.not.have.property('gdpr');
});
it('should not send the consent string, when consent string is undefined', function () {
delete bidderRequest.gdprConsent.consentString;
const request = spec.buildRequests(bidRequests, bidderRequest);
expect(request[0].data).to.not.have.property('gdpr_consent');
expect(request[1].data).to.not.have.property('gdpr_consent');
});
it('should not send the consent management framework code, when format is undefined', function () {
delete mockConfig.consentManagement.cmpApi;
const request = spec.buildRequests(bidRequests, bidderRequest);
expect(request[0].data).to.not.have.property('x_gdpr_f');
expect(request[1].data).to.not.have.property('x_gdpr_f');
});
});
});
it('should not send a coppa query param when there are no coppa param settings in the bid requests', function () {
const bidRequestsWithoutCoppa = [{
bidder: 'openx',
params: {
unit: '11',
delDomain: 'test-del-domain',
coppa: false
},
adUnitCode: 'adunit-code',
mediaTypes: {
banner: {
sizes: [[300, 250], [300, 600]]
}
},
bidId: 'test-bid-id-1',
bidderRequestId: 'test-bid-request-1',
auctionId: 'test-auction-1'
}, {
bidder: 'openx',
params: {
unit: '22',
delDomain: 'test-del-domain'
},
adUnitCode: 'adunit-code',
mediaTypes: {
banner: {
sizes: [[728, 90]]
}
},
bidId: 'test-bid-id-2',
bidderRequestId: 'test-bid-request-2',
auctionId: 'test-auction-2'
}];
const request = spec.buildRequests(bidRequestsWithoutCoppa, mockBidderRequest);
expect(request[0].data).to.not.have.any.keys('tfcd');
});
it('should send a coppa flag there is when there is coppa param settings in the bid requests', function () {
const bidRequestsWithCoppa = [{
bidder: 'openx',
params: {
unit: '11',
delDomain: 'test-del-domain',
coppa: false
},
adUnitCode: 'adunit-code',
mediaTypes: {
banner: {
sizes: [[300, 250], [300, 600]]
}
},
bidId: 'test-bid-id-1',
bidderRequestId: 'test-bid-request-1',
auctionId: 'test-auction-1'
}, {
bidder: 'openx',
params: {
unit: '22',
delDomain: 'test-del-domain',
coppa: true
},
adUnitCode: 'adunit-code',
mediaTypes: {
banner: {
sizes: [[728, 90]]
}
},
bidId: 'test-bid-id-2',
bidderRequestId: 'test-bid-request-2',
auctionId: 'test-auction-2'
}];
const request = spec.buildRequests(bidRequestsWithCoppa, mockBidderRequest);
expect(request[0].data.tfcd).to.equal(1);
});
it('should not send a "no segmentation" flag there no DoNotTrack setting that is set to true', function () {
const bidRequestsWithoutDnt = [{
bidder: 'openx',
params: {
unit: '11',
delDomain: 'test-del-domain',
doNotTrack: false
},
adUnitCode: 'adunit-code',
mediaTypes: {
banner: {
sizes: [[300, 250], [300, 600]]
}
},
bidId: 'test-bid-id-1',
bidderRequestId: 'test-bid-request-1',
auctionId: 'test-auction-1'
}, {
bidder: 'openx',
params: {
unit: '22',
delDomain: 'test-del-domain'
},
adUnitCode: 'adunit-code',
mediaTypes: {
banner: {
sizes: [[728, 90]]
}
},
bidId: 'test-bid-id-2',
bidderRequestId: 'test-bid-request-2',
auctionId: 'test-auction-2'
}];
const request = spec.buildRequests(bidRequestsWithoutDnt, mockBidderRequest);
expect(request[0].data).to.not.have.any.keys('ns');
});
it('should send a "no segmentation" flag there is any DoNotTrack setting that is set to true', function () {
const bidRequestsWithDnt = [{
bidder: 'openx',
params: {
unit: '11',
delDomain: 'test-del-domain',
doNotTrack: false
},
adUnitCode: 'adunit-code',
mediaTypes: {
banner: {
sizes: [[300, 250], [300, 600]]
}
},
bidId: 'test-bid-id-1',
bidderRequestId: 'test-bid-request-1',
auctionId: 'test-auction-1'
}, {
bidder: 'openx',
params: {
unit: '22',
delDomain: 'test-del-domain',
doNotTrack: true
},
adUnitCode: 'adunit-code',
mediaTypes: {
banner: {
sizes: [[728, 90]]
}
},
bidId: 'test-bid-id-2',
bidderRequestId: 'test-bid-request-2',
auctionId: 'test-auction-2'
}];
const request = spec.buildRequests(bidRequestsWithDnt, mockBidderRequest);
expect(request[0].data.ns).to.equal(1);
});
describe('when schain is provided', function () {
let bidRequests;
let schainConfig;
const supplyChainNodePropertyOrder = ['asi', 'sid', 'hp', 'rid', 'name', 'domain'];
beforeEach(function () {
schainConfig = {
'ver': '1.0',
'complete': 1,
'nodes': [
{
'asi': 'exchange1.com',
'sid': '1234',
'hp': 1,
'rid': 'bid-request-1',
'name': 'publisher',
'domain': 'publisher.com'
// omitted ext
},
{
'asi': 'exchange2.com',
'sid': 'abcd',
'hp': 1,
'rid': 'bid-request-2',
// name field missing
'domain': 'intermediary.com'
},
{
'asi': 'exchange3.com',
'sid': '4321',
'hp': 1,
// request id
// name field missing
'domain': 'intermediary-2.com'
}
]
};
bidRequests = [{
'bidder': 'openx',
'params': {
'unit': '11',
'delDomain': 'test-del-domain'
},
'adUnitCode': '/adunit-code/test-path',
mediaTypes: {
banner: {
sizes: [[300, 250], [300, 600]]
}
},
'bidId': 'test-bid-id-1',
'bidderRequestId': 'test-bid-request-1',
'auctionId': 'test-auction-1',
'schain': schainConfig
}];
});
it('should send a schain parameter with the proper delimiter symbols', function () {
const request = spec.buildRequests(bidRequests, mockBidderRequest);
const dataParams = request[0].data;
const numNodes = schainConfig.nodes.length;
// each node will have a ! to denote beginning of a new node
expect(dataParams.schain.match(/!/g).length).to.equal(numNodes);
// 1 comma in the front for version
// 5 commas per node
expect(dataParams.schain.match(/,/g).length).to.equal(numNodes * 5 + 1);
});
it('should send a schain with the right version', function () {
const request = spec.buildRequests(bidRequests, mockBidderRequest);
const dataParams = request[0].data;
let serializedSupplyChain = dataParams.schain.split('!');
let version = serializedSupplyChain.shift().split(',')[0];
expect(version).to.equal(bidRequests[0].schain.ver);
});
it('should send a schain with the right complete value', function () {
const request = spec.buildRequests(bidRequests, mockBidderRequest);
const dataParams = request[0].data;
let serializedSupplyChain = dataParams.schain.split('!');
let isComplete = serializedSupplyChain.shift().split(',')[1];
expect(isComplete).to.equal(String(bidRequests[0].schain.complete));
});
it('should send all available params in the right order', function () {
const request = spec.buildRequests(bidRequests, mockBidderRequest);
const dataParams = request[0].data;
let serializedSupplyChain = dataParams.schain.split('!');
serializedSupplyChain.shift();
serializedSupplyChain.forEach((serializedNode, nodeIndex) => {
let nodeProperties = serializedNode.split(',');
nodeProperties.forEach((nodeProperty, propertyIndex) => {
let node = schainConfig.nodes[nodeIndex];
let key = supplyChainNodePropertyOrder[propertyIndex];
expect(nodeProperty).to.equal(node[key] ? String(node[key]) : '',
`expected node '${nodeIndex}' property '${nodeProperty}' to key '${key}' to be the same value`)
});
});
});
});
describe('when there are userid providers', function () {
const EXAMPLE_DATA_BY_ATTR = {
britepoolid: '1111-britepoolid',
criteoId: '1111-criteoId',
fabrickId: '1111-fabrickid',
haloId: '1111-haloid',
id5id: {uid: '1111-id5id'},
idl_env: '1111-idl_env',
IDP: '1111-zeotap-idplusid',
idxId: '1111-idxid',
intentIqId: '1111-intentiqid',
lipb: {lipbid: '1111-lipb'},
lotamePanoramaId: '1111-lotameid',
merkleId: '1111-merkleid',
netId: 'fH5A3n2O8_CZZyPoJVD-eabc6ECb7jhxCicsds7qSg',
parrableId: { eid: 'eidVersion.encryptionKeyReference.encryptedValue' },
pubcid: '1111-pubcid',
quantcastId: '1111-quantcastid',
tapadId: '111-tapadid',
tdid: '1111-tdid',
uid2: {id: '1111-uid2'},
flocId: {id: '12144', version: 'chrome.1.1'},
novatiq: {snowflake: '1111-novatiqid'},
admixerId: '1111-admixerid',
deepintentId: '1111-deepintentid',
dmdId: '111-dmdid',
nextrollId: '1111-nextrollid',
mwOpenLinkId: '1111-mwopenlinkid',
dapId: '1111-dapId',
amxId: '1111-amxid',
};
// generates the same set of tests for each id provider
utils._each(USER_ID_CODE_TO_QUERY_ARG, (userIdQueryArg, userIdProviderKey) => {
describe(`with userId attribute: ${userIdProviderKey}`, function () {
it(`should not send a ${userIdQueryArg} query param when there is no userId.${userIdProviderKey} defined in the bid requests`, function () {
const request = spec.buildRequests(bidRequestsWithMediaTypes, mockBidderRequest);
expect(request[0].data).to.not.have.any.keys(userIdQueryArg);
});
it(`should send a ${userIdQueryArg} query param when userId.${userIdProviderKey} is defined in the bid requests`, function () {
const bidRequestsWithUserId = [{
bidder: 'openx',
params: {
unit: '11',
delDomain: 'test-del-domain'
},
userId: {
},
adUnitCode: 'adunit-code',
mediaTypes: {
banner: {
sizes: [[300, 250], [300, 600]]
}
},
bidId: 'test-bid-id-1',
bidderRequestId: 'test-bid-request-1',
auctionId: 'test-auction-1'
}];
// enrich bid request with userId key/value
bidRequestsWithUserId[0].userId[userIdProviderKey] = EXAMPLE_DATA_BY_ATTR[userIdProviderKey];
const request = spec.buildRequests(bidRequestsWithUserId, mockBidderRequest);
let userIdValue;
// handle cases where userId key refers to an object
switch (userIdProviderKey) {
case 'flocId':
userIdValue = EXAMPLE_DATA_BY_ATTR.flocId.id;
break;
case 'uid2':
userIdValue = EXAMPLE_DATA_BY_ATTR.uid2.id;
break;
case 'lipb':
userIdValue = EXAMPLE_DATA_BY_ATTR.lipb.lipbid;
break;
case 'parrableId':
userIdValue = EXAMPLE_DATA_BY_ATTR.parrableId.eid;
break;
case 'id5id':
userIdValue = EXAMPLE_DATA_BY_ATTR.id5id.uid;
break;
case 'novatiq':
userIdValue = EXAMPLE_DATA_BY_ATTR.novatiq.snowflake;
break;
default:
userIdValue = EXAMPLE_DATA_BY_ATTR[userIdProviderKey];
}
expect(request[0].data[USER_ID_CODE_TO_QUERY_ARG[userIdProviderKey]]).to.equal(userIdValue);
});
});
});
});
describe('floors', function () {
it('should send out custom floors on bids that have customFloors specified', function () {
const bidRequest = Object.assign({},
bidRequestsWithMediaTypes[0],
{
params: {
'unit': '12345678',
'delDomain': 'test-del-domain',
'customFloor': 1.500001
}
}
);
const request = spec.buildRequests([bidRequest], mockBidderRequest);
const dataParams = request[0].data;
expect(dataParams.aumfs).to.exist;
expect(dataParams.aumfs).to.equal('1500');
});
context('with floors module', function () {
let adServerCurrencyStub;
beforeEach(function () {
adServerCurrencyStub = sinon
.stub(config, 'getConfig')
.withArgs('currency.adServerCurrency')
});
afterEach(function () {
config.getConfig.restore();
});
it('should send out floors on bids', function () {
const bidRequest1 = Object.assign({},
bidRequestsWithMediaTypes[0],
{
getFloor: () => {
return {
currency: 'AUS',
floor: 9.99
}
}
}
);
const bidRequest2 = Object.assign({},
bidRequestsWithMediaTypes[1],
{
getFloor: () => {
return {
currency: 'AUS',
floor: 18.881
}
}
}
);
const request = spec.buildRequests([bidRequest1, bidRequest2], mockBidderRequest);
const dataParams = request[0].data;
expect(dataParams.aumfs).to.exist;
expect(dataParams.aumfs).to.equal('9990,18881');
});
it('should send out floors on bids in the default currency', function () {
const bidRequest1 = Object.assign({},
bidRequestsWithMediaTypes[0],
{
getFloor: () => {
return {};
}
}
);
let getFloorSpy = sinon.spy(bidRequest1, 'getFloor');
spec.buildRequests([bidRequest1], mockBidderRequest);
expect(getFloorSpy.args[0][0].mediaType).to.equal(BANNER);
expect(getFloorSpy.args[0][0].currency).to.equal('USD');
});
it('should send out floors on bids in the ad server currency if defined', function () {
adServerCurrencyStub.returns('bitcoin');
const bidRequest1 = Object.assign({},
bidRequestsWithMediaTypes[0],
{
getFloor: () => {
return {};
}
}
);
let getFloorSpy = sinon.spy(bidRequest1, 'getFloor');
spec.buildRequests([bidRequest1], mockBidderRequest);
expect(getFloorSpy.args[0][0].mediaType).to.equal(BANNER);
expect(getFloorSpy.args[0][0].currency).to.equal('bitcoin');
});
})
})
});
describe('buildRequests for video', function () {
const bidRequestsWithMediaTypes = VIDEO_BID_REQUESTS_WITH_MEDIA_TYPES;
const mockBidderRequest = {refererInfo: {}};
it('should send bid request to openx url via GET, with mediaTypes having video parameter', function () {
const request = spec.buildRequests(bidRequestsWithMediaTypes, mockBidderRequest);
expect(request[0].url).to.equal('https://' + bidRequestsWithMediaTypes[0].params.delDomain + URLBASEVIDEO);
expect(request[0].method).to.equal('GET');
});
it('should have the correct parameters', function () {
const request = spec.buildRequests(bidRequestsWithMediaTypes, mockBidderRequest);
const dataParams = request[0].data;
expect(dataParams.auid).to.equal('12345678');
expect(dataParams.vht).to.equal(480);
expect(dataParams.vwd).to.equal(640);
expect(dataParams.aucs).to.equal(encodeURIComponent('/12345/my-gpt-tag-0'));
});
it('shouldn\'t have the test parameter', function () {
const request = spec.buildRequests(bidRequestsWithMediaTypes, mockBidderRequest);
expect(request[0].data.vtest).to.be.undefined;
});
it('should send a bc parameter', function () {
const request = spec.buildRequests(bidRequestsWithMediaTypes, mockBidderRequest);
const dataParams = request[0].data;
expect(dataParams.bc).to.have.string('hb_pb');
});
describe('when using the video param', function () {
let videoBidRequest;
let mockBidderRequest = {refererInfo: {}};
beforeEach(function () {
videoBidRequest = {
'bidder': 'openx',
'mediaTypes': {
video: {
context: 'instream',
playerSize: [640, 480]
}
},
'params': {
'unit': '12345678',
'delDomain': 'test-del-domain'
},
'adUnitCode': 'adunit-code',
'bidId': '30b31c1838de1e',
'bidderRequestId': '22edbae2733bf6',
'auctionId': '1d1a030790a475',
'transactionId': '4008d88a-8137-410b-aa35-fbfdabcb478e'
};
mockBidderRequest = {refererInfo: {}};
});
it('should not allow you to set a url', function () {
videoBidRequest.params.video = {
url: 'test-url'
};
const request = spec.buildRequests([videoBidRequest], mockBidderRequest);
expect(request[0].data.url).to.be.undefined;
});
it('should not allow you to override the javascript url', function () {
let myUrl = 'my-url';
videoBidRequest.params.video = {
ju: myUrl
};
const request = spec.buildRequests([videoBidRequest], mockBidderRequest);
expect(request[0].data.ju).to.not.equal(myUrl);
});
describe('when using the openrtb video params', function () {
it('should parse legacy params.video.openrtb', function () {
let myOpenRTBObject = {mimes: ['application/javascript']};
videoBidRequest.params.video = {
openrtb: myOpenRTBObject
};
const expected = {imp: [{video: {w: 640, h: 480, mimes: ['application/javascript']}}]}
const request = spec.buildRequests([videoBidRequest], mockBidderRequest);
expect(request[0].data.openrtb).to.equal(JSON.stringify(expected));
});
it('should parse legacy params.openrtb', function () {
let myOpenRTBObject = {mimes: ['application/javascript']};
videoBidRequest.params.openrtb = myOpenRTBObject;
const expected = {imp: [{video: {w: 640, h: 480, mimes: ['application/javascript']}}]}
const request = spec.buildRequests([videoBidRequest], mockBidderRequest);
expect(request[0].data.openrtb).to.equal(JSON.stringify(expected));
});
it('should parse legacy params.video', function () {
let myOpenRTBObject = {mimes: ['application/javascript']};
videoBidRequest.params.video = myOpenRTBObject;
const expected = {imp: [{video: {w: 640, h: 480, mimes: ['application/javascript']}}]}
const request = spec.buildRequests([videoBidRequest], mockBidderRequest);
expect(request[0].data.openrtb).to.equal(JSON.stringify(expected));
});
it('should parse legacy params.video as full openrtb', function () {
let myOpenRTBObject = {imp: [{video: {mimes: ['application/javascript']}}]};
videoBidRequest.params.video = myOpenRTBObject;
const expected = {imp: [{video: {w: 640, h: 480, mimes: ['application/javascript']}}]}
const request = spec.buildRequests([videoBidRequest], mockBidderRequest);
expect(request[0].data.openrtb).to.equal(JSON.stringify(expected));
});
it('should parse legacy video.openrtb', function () {
let myOpenRTBObject = {mimes: ['application/javascript']};
videoBidRequest.params.video = {
openrtb: myOpenRTBObject
};
const expected = {imp: [{video: {w: 640, h: 480, mimes: ['application/javascript']}}]}
const request = spec.buildRequests([videoBidRequest], mockBidderRequest);
expect(request[0].data.openrtb).to.equal(JSON.stringify(expected));
});
it('should omit filtered values for legacy', function () {
let myOpenRTBObject = {mimes: ['application/javascript'], dont: 'use'};
videoBidRequest.params.video = {
openrtb: myOpenRTBObject
};
const expected = {imp: [{video: {w: 640, h: 480, mimes: ['application/javascript']}}]}
const request = spec.buildRequests([videoBidRequest], mockBidderRequest);
expect(request[0].data.openrtb).to.equal(JSON.stringify(expected));
});
it('should parse mediatypes.video', function () {
videoBidRequest.mediaTypes.video.mimes = ['application/javascript']
videoBidRequest.mediaTypes.video.minduration = 15
const request = spec.buildRequests([videoBidRequest], mockBidderRequest);
const openRtbRequestParams = JSON.parse(request[0].data.openrtb);
expect(openRtbRequestParams.imp[0].video.mimes).to.eql(['application/javascript']);
expect(openRtbRequestParams.imp[0].video.minduration).to.equal(15);
});
it('should filter mediatypes.video', function () {
videoBidRequest.mediaTypes.video.mimes = ['application/javascript']
videoBidRequest.mediaTypes.video.minnothing = 15
const request = spec.buildRequests([videoBidRequest], mockBidderRequest);
const openRtbRequestParams = JSON.parse(request[0].data.openrtb);
expect(openRtbRequestParams.imp[0].video.mimes).to.eql(['application/javascript']);
expect(openRtbRequestParams.imp[0].video.minnothing).to.equal(undefined);
});
it("should use the bidRequest's playerSize", function () {
const width = 200;
const height = 100;
const myOpenRTBObject = {v: height, w: width};
videoBidRequest.params.video = {
openrtb: myOpenRTBObject
};
const request = spec.buildRequests([videoBidRequest], mockBidderRequest);
const openRtbRequestParams = JSON.parse(request[0].data.openrtb);
expect(openRtbRequestParams.imp[0].video.w).to.equal(640);
expect(openRtbRequestParams.imp[0].video.h).to.equal(480);
});
});
});
describe('floors', function () {
it('should send out custom floors on bids that have customFloors specified', function () {
const bidRequest = Object.assign({},
bidRequestsWithMediaTypes[0],
{
params: {
'unit': '12345678',
'delDomain': 'test-del-domain',
'customFloor': 1.500001
}
}
);
const request = spec.buildRequests([bidRequest], mockBidderRequest);
const dataParams = request[0].data;
expect(dataParams.aumfs).to.exist;
expect(dataParams.aumfs).to.equal('1500');
});
context('with floors module', function () {
let adServerCurrencyStub;
function makeBidWithFloorInfo(floorInfo) {
return Object.assign(utils.deepClone(bidRequestsWithMediaTypes[0]),
{
getFloor: () => {
return floorInfo;
}
});
}
beforeEach(function () {
a