mk9-prebid
Version:
Header Bidding Management Library
487 lines (458 loc) • 16.3 kB
JavaScript
import { expect } from 'chai';
import { spec } from 'modules/undertoneBidAdapter.js';
const URL = 'https://hb.undertone.com/hb';
const BIDDER_CODE = 'undertone';
const validBidReq = {
bidder: BIDDER_CODE,
params: {
placementId: '10433394',
publisherId: 12345
},
sizes: [[300, 250], [300, 600]],
bidId: '263be71e91dd9d',
auctionId: '9ad1fa8d-2297-4660-a018-b39945054747',
};
const invalidBidReq = {
bidder: BIDDER_CODE,
params: {
placementId: '123456789'
},
sizes: [[300, 250], [300, 600]],
bidId: '263be71e91dd9d',
auctionId: '9ad1fa8d-2297-4660-a018-b39945054746'
};
const videoBidReq = [{
adUnitCode: 'div-gpt-ad-1460505748561-0',
bidder: BIDDER_CODE,
params: {
placementId: '10433394',
publisherId: 12345,
video: {
id: 123,
skippable: true,
playbackMethod: 2,
maxDuration: 30
}
},
mediaTypes: {video: {
context: 'outstream',
playerSize: [640, 480]
}},
sizes: [[300, 250], [300, 600]],
bidId: '263be71e91dd9d',
auctionId: '9ad1fa8d-2297-4660-a018-b39945054746'
},
{
adUnitCode: 'div-gpt-ad-1460505748561-1',
bidder: BIDDER_CODE,
params: {
placementId: '10433395',
publisherId: 12345
},
mediaTypes: {video: {
context: 'outstream',
playerSize: [640, 480]
}},
sizes: [[300, 250], [300, 600]],
bidId: '263be71e91dd9d',
auctionId: '9ad1fa8d-2297-4660-a018-b39945054746'
}];
const bidReq = [{
adUnitCode: 'div-gpt-ad-1460505748561-0',
bidder: BIDDER_CODE,
params: {
placementId: '10433394',
publisherId: 12345,
},
sizes: [[300, 250], [300, 600]],
bidId: '263be71e91dd9d',
auctionId: '9ad1fa8d-2297-4660-a018-b39945054746'
},
{
adUnitCode: 'div-gpt-ad-1460505748561-0',
bidder: BIDDER_CODE,
params: {
publisherId: 12345
},
sizes: [[1, 1]],
bidId: '453cf42d72bb3c',
auctionId: '6c22f5a5-59df-4dc6-b92c-f433bcf0a874'
}];
const bidReqUserIds = [{
bidder: BIDDER_CODE,
params: {
placementId: '10433394',
publisherId: 12345
},
sizes: [[300, 250], [300, 600]],
bidId: '263be71e91dd9d',
auctionId: '9ad1fa8d-2297-4660-a018-b39945054746',
userId: {
idl_env: '1111',
tdid: '123456',
digitrustid: {data: {id: 'DTID', keyv: 4, privacy: {optout: false}, producer: 'ABC', version: 2}},
id5id: { uid: '1111' }
}
},
{
bidder: BIDDER_CODE,
params: {
publisherId: 12345
},
sizes: [[1, 1]],
bidId: '453cf42d72bb3c',
auctionId: '6c22f5a5-59df-4dc6-b92c-f433bcf0a874'
}];
const bidderReq = {
refererInfo: {
referer: 'http://prebid.org/dev-docs/bidder-adaptor.html'
}
};
const bidderReqGdpr = {
refererInfo: {
referer: 'http://prebid.org/dev-docs/bidder-adaptor.html'
},
gdprConsent: {
gdprApplies: true,
consentString: 'acdefgh'
}
};
const bidderReqCcpa = {
refererInfo: {
referer: 'http://prebid.org/dev-docs/bidder-adaptor.html'
},
uspConsent: 'NY12'
};
const bidderReqCcpaAndGdpr = {
refererInfo: {
referer: 'http://prebid.org/dev-docs/bidder-adaptor.html'
},
gdprConsent: {
gdprApplies: true,
consentString: 'acdefgh'
},
uspConsent: 'NY12'
};
const validBidRes = {
ad: '<div>Hello</div>',
publisherId: 12345,
bidRequestId: '263be71e91dd9d',
adId: 15,
cpm: 100,
nCampaignId: 2,
creativeId: '123abc',
currency: 'USD',
netRevenue: true,
width: 300,
height: 250,
ttl: 360
};
const bidResponse = [validBidRes];
const bidResArray = [
validBidRes,
{
ad: '',
bidRequestId: '263be71e91dd9d',
cpm: 100,
adId: '123abc',
currency: 'USD',
netRevenue: true,
width: 300,
height: 250,
ttl: 360
},
{
ad: '<div>Hello</div>',
bidRequestId: '',
cpm: 0,
adId: '123abc',
currency: 'USD',
netRevenue: true,
width: 300,
height: 250,
ttl: 360
}
];
const bidVideoResponse = [
{
ad: '<xml />',
bidRequestId: '263be71e91dd9d',
cpm: 100,
adId: '123abc',
currency: 'USD',
mediaType: 'video',
netRevenue: true,
width: 300,
height: 250,
ttl: 360
}
];
let element;
let sandbox;
let elementParent = {
offsetLeft: 100,
offsetTop: 100,
offsetHeight: 100,
getAttribute: function() {}
};
describe('Undertone Adapter', () => {
describe('request', () => {
it('should validate bid request', () => {
expect(spec.isBidRequestValid(validBidReq)).to.equal(true);
});
it('should not validate incorrect bid request', () => {
expect(spec.isBidRequestValid(invalidBidReq)).to.equal(undefined);
});
});
describe('build request', function () {
beforeEach(function() {
element = {
id: 'div-gpt-ad-1460505748561-0',
offsetLeft: 100,
offsetTop: 100,
offsetWidth: 300,
offsetHeight: 250
};
sandbox = sinon.sandbox.create();
sandbox.stub(document, 'getElementById').withArgs('div-gpt-ad-1460505748561-0').returns(element);
});
afterEach(function() {
sandbox.restore();
});
it('should send request to correct url via POST not in GDPR or CCPA', function () {
const request = spec.buildRequests(bidReq, bidderReq);
const domainStart = bidderReq.refererInfo.referer.indexOf('//');
const domainEnd = bidderReq.refererInfo.referer.indexOf('/', domainStart + 2);
const domain = bidderReq.refererInfo.referer.substring(domainStart + 2, domainEnd);
const REQ_URL = `${URL}?pid=${bidReq[0].params.publisherId}&domain=${domain}`;
expect(request.url).to.equal(REQ_URL);
expect(request.method).to.equal('POST');
});
it('should send request to correct url via POST when in GDPR', function () {
const request = spec.buildRequests(bidReq, bidderReqGdpr);
const domainStart = bidderReq.refererInfo.referer.indexOf('//');
const domainEnd = bidderReq.refererInfo.referer.indexOf('/', domainStart + 2);
const domain = bidderReq.refererInfo.referer.substring(domainStart + 2, domainEnd);
let gdpr = bidderReqGdpr.gdprConsent.gdprApplies ? 1 : 0;
const REQ_URL = `${URL}?pid=${bidReq[0].params.publisherId}&domain=${domain}&gdpr=${gdpr}&gdprstr=${bidderReqGdpr.gdprConsent.consentString}`;
expect(request.url).to.equal(REQ_URL);
expect(request.method).to.equal('POST');
});
it('should send request to correct url via POST when in CCPA', function () {
const request = spec.buildRequests(bidReq, bidderReqCcpa);
const domainStart = bidderReq.refererInfo.referer.indexOf('//');
const domainEnd = bidderReq.refererInfo.referer.indexOf('/', domainStart + 2);
const domain = bidderReq.refererInfo.referer.substring(domainStart + 2, domainEnd);
let ccpa = bidderReqCcpa.uspConsent;
const REQ_URL = `${URL}?pid=${bidReq[0].params.publisherId}&domain=${domain}&ccpa=${ccpa}`;
expect(request.url).to.equal(REQ_URL);
expect(request.method).to.equal('POST');
});
it('should send request to correct url via POST when in GDPR and CCPA', function () {
const request = spec.buildRequests(bidReq, bidderReqCcpaAndGdpr);
const domainStart = bidderReq.refererInfo.referer.indexOf('//');
const domainEnd = bidderReq.refererInfo.referer.indexOf('/', domainStart + 2);
const domain = bidderReq.refererInfo.referer.substring(domainStart + 2, domainEnd);
let ccpa = bidderReqCcpaAndGdpr.uspConsent;
let gdpr = bidderReqCcpaAndGdpr.gdprConsent.gdprApplies ? 1 : 0;
const REQ_URL = `${URL}?pid=${bidReq[0].params.publisherId}&domain=${domain}&gdpr=${gdpr}&gdprstr=${bidderReqGdpr.gdprConsent.consentString}&ccpa=${ccpa}`;
expect(request.url).to.equal(REQ_URL);
expect(request.method).to.equal('POST');
});
it('should have all relevant fields', function () {
const request = spec.buildRequests(bidReq, bidderReq);
const bid1 = JSON.parse(request.data)['x-ut-hb-params'][0];
expect(bid1.bidRequestId).to.equal('263be71e91dd9d');
expect(bid1.sizes.length).to.equal(2);
expect(bid1.placementId).to.equal('10433394');
expect(bid1.publisherId).to.equal(12345);
expect(bid1.coordinates).to.be.an('array');
expect(bid1.params).to.be.an('object');
const bid2 = JSON.parse(request.data)['x-ut-hb-params'][1];
expect(bid2.bidRequestId).to.equal('453cf42d72bb3c');
expect(bid2.sizes.length).to.equal(1);
expect(bid2.placementId === null).to.equal(true);
expect(bid2.publisherId).to.equal(12345);
expect(bid2.params).to.be.an('object');
});
it('should send video fields correctly', function () {
const request = spec.buildRequests(videoBidReq, bidderReq);
const bidVideo = JSON.parse(request.data)['x-ut-hb-params'][0];
const bidVideo2 = JSON.parse(request.data)['x-ut-hb-params'][1];
expect(bidVideo.mediaType).to.equal('video');
expect(bidVideo.video).to.be.an('object');
expect(bidVideo.video.playerSize).to.be.an('array');
expect(bidVideo.video.streamType).to.equal('outstream');
expect(bidVideo.video.playbackMethod).to.equal(2);
expect(bidVideo.video.maxDuration).to.equal(30);
expect(bidVideo.video.skippable).to.equal(true);
expect(bidVideo2.video.skippable).to.equal(null);
expect(bidVideo2.video.maxDuration).to.equal(null);
expect(bidVideo2.video.playbackMethod).to.equal(null);
});
it('should send all userIds data to server', function () {
const request = spec.buildRequests(bidReqUserIds, bidderReq);
const bidCommons = JSON.parse(request.data)['commons'];
expect(bidCommons).to.be.an('object');
expect(bidCommons.uids).to.be.an('object');
expect(bidCommons.uids.tdid).to.equal('123456');
expect(bidCommons.uids.idl_env).to.equal('1111');
expect(bidCommons.uids.digitrustid.data.id).to.equal('DTID');
expect(bidCommons.uids.id5id.uid).to.equal('1111');
});
it('should send page sizes sizes correctly', function () {
const request = spec.buildRequests(bidReqUserIds, bidderReq);
const bidCommons = JSON.parse(request.data)['commons'];
expect(bidCommons).to.be.an('object');
expect(bidCommons.pageSize).to.be.an('array');
expect(bidCommons.pageSize[0]).to.equal(window.innerWidth);
expect(bidCommons.pageSize[1]).to.equal(window.innerHeight);
});
it('should send banner coordinates', function() {
const request = spec.buildRequests(bidReq, bidderReq);
const bid1 = JSON.parse(request.data)['x-ut-hb-params'][0];
expect(bid1.coordinates).to.be.an('array');
expect(bid1.coordinates[0]).to.equal(100);
expect(bid1.coordinates[1]).to.equal(100);
});
it('should send banner coordinates plus parent', function() {
element.offsetParent = elementParent;
const request = spec.buildRequests(bidReq, bidderReq);
const bid1 = JSON.parse(request.data)['x-ut-hb-params'][0];
expect(bid1.coordinates).to.be.an('array');
expect(bid1.coordinates[0]).to.equal(200);
expect(bid1.coordinates[1]).to.equal(200);
});
});
describe('interpretResponse', () => {
it('should build bid array', () => {
let result = spec.interpretResponse({body: bidResponse});
expect(result.length).to.equal(1);
});
it('should have all relevant fields', () => {
const result = spec.interpretResponse({body: bidResponse});
const bid = result[0];
expect(bid.requestId).to.equal('263be71e91dd9d');
expect(bid.cpm).to.equal(100);
expect(bid.width).to.equal(300);
expect(bid.height).to.equal(250);
expect(bid.meta.advertiserDomains).to.deep.equal([]);
expect(bid.creativeId).to.equal(15);
expect(bid.currency).to.equal('USD');
expect(bid.netRevenue).to.equal(true);
expect(bid.ttl).to.equal(360);
});
it('should return empty array when response is incorrect', () => {
expect(spec.interpretResponse({body: {}}).length).to.equal(0);
expect(spec.interpretResponse({body: []}).length).to.equal(0);
});
it('should only use valid bid responses', () => {
expect(spec.interpretResponse({ body: bidResArray }).length).to.equal(1);
});
it('should detect video response', () => {
const videoResult = spec.interpretResponse({body: bidVideoResponse});
const vbid = videoResult[0];
expect(vbid.mediaType).to.equal('video');
});
});
describe('getUserSyncs', () => {
let testParams = [
{
name: 'with iframe and no gdpr or ccpa data',
arguments: [{ iframeEnabled: true, pixelEnabled: true }, {}, null],
expect: {
type: 'iframe',
pixels: ['https://cdn.undertone.com/js/usersync.html']
}
},
{
name: 'with iframe and gdpr on',
arguments: [{ iframeEnabled: true, pixelEnabled: true }, {}, {gdprApplies: true, consentString: '234234'}],
expect: {
type: 'iframe',
pixels: ['https://cdn.undertone.com/js/usersync.html?gdpr=1&gdprstr=234234']
}
},
{
name: 'with iframe and ccpa on',
arguments: [{ iframeEnabled: true, pixelEnabled: true }, {}, null, 'YN12'],
expect: {
type: 'iframe',
pixels: ['https://cdn.undertone.com/js/usersync.html?ccpa=YN12']
}
},
{
name: 'with iframe and no gdpr off or ccpa',
arguments: [{ iframeEnabled: true, pixelEnabled: true }, {}, {gdprApplies: false}],
expect: {
type: 'iframe',
pixels: ['https://cdn.undertone.com/js/usersync.html?gdpr=0&gdprstr=']
}
},
{
name: 'with iframe and gdpr and ccpa',
arguments: [{ iframeEnabled: true, pixelEnabled: true }, {}, {gdprApplies: true, consentString: '234234'}, 'YN12'],
expect: {
type: 'iframe',
pixels: ['https://cdn.undertone.com/js/usersync.html?gdpr=1&gdprstr=234234&ccpa=YN12']
}
},
{
name: 'with pixels and no gdpr or ccpa data',
arguments: [{ pixelEnabled: true }, {}, null],
expect: {
type: 'image',
pixels: ['https://usr.undertone.com/userPixel/syncOne?id=1&of=2',
'https://usr.undertone.com/userPixel/syncOne?id=2&of=2']
}
},
{
name: 'with pixels and gdpr on',
arguments: [{ pixelEnabled: true }, {}, {gdprApplies: true, consentString: '234234'}],
expect: {
type: 'image',
pixels: ['https://usr.undertone.com/userPixel/syncOne?id=1&of=2&gdpr=1&gdprstr=234234',
'https://usr.undertone.com/userPixel/syncOne?id=2&of=2&gdpr=1&gdprstr=234234']
}
},
{
name: 'with pixels and ccpa on',
arguments: [{ pixelEnabled: true }, {}, null, 'YN12'],
expect: {
type: 'image',
pixels: ['https://usr.undertone.com/userPixel/syncOne?id=1&of=2&ccpa=YN12',
'https://usr.undertone.com/userPixel/syncOne?id=2&of=2&ccpa=YN12']
}
},
{
name: 'with pixels and gdpr off',
arguments: [{ pixelEnabled: true }, {}, {gdprApplies: false}],
expect: {
type: 'image',
pixels: ['https://usr.undertone.com/userPixel/syncOne?id=1&of=2&gdpr=0&gdprstr=',
'https://usr.undertone.com/userPixel/syncOne?id=2&of=2&gdpr=0&gdprstr=']
}
},
{
name: 'with pixels and gdpr and ccpa on',
arguments: [{ pixelEnabled: true }, {}, {gdprApplies: true, consentString: '234234'}, 'YN12'],
expect: {
type: 'image',
pixels: ['https://usr.undertone.com/userPixel/syncOne?id=1&of=2&gdpr=1&gdprstr=234234&ccpa=YN12',
'https://usr.undertone.com/userPixel/syncOne?id=2&of=2&gdpr=1&gdprstr=234234&ccpa=YN12']
}
}
];
for (let i = 0; i < testParams.length; i++) {
let currParams = testParams[i];
it(currParams.name, function () {
const result = spec.getUserSyncs.apply(this, currParams.arguments);
expect(result).to.have.lengthOf(currParams.expect.pixels.length);
for (let ix = 0; ix < currParams.expect.pixels.length; ix++) {
expect(result[ix].url).to.equal(currParams.expect.pixels[ix]);
expect(result[ix].type).to.equal(currParams.expect.type);
}
});
}
});
});