diff --git a/modules/adkernelBidAdapter.js b/modules/adkernelBidAdapter.js
index 800c58225f4..a47faec961e 100644
--- a/modules/adkernelBidAdapter.js
+++ b/modules/adkernelBidAdapter.js
@@ -29,6 +29,7 @@ import { getBidFloor } from '../libraries/adkernelUtils/adkernelUtils.js';
* @typedef {import('../src/adapters/bidderFactory.js').Bid} Bid
* @typedef {import('../src/adapters/bidderFactory.js').ServerRequest} ServerRequest
* @typedef {import('../src/adapters/bidderFactory.js').UserSync} UserSync
+ * @typedef {import('../src/types/ortb/ext/dsa.d.ts').DSARequest} DSARequest
*/
const VIDEO_PARAMS = ['pos', 'context', 'placement', 'plcmt', 'api', 'mimes', 'protocols', 'playbackmethod', 'minduration', 'maxduration',
@@ -124,9 +125,10 @@ export const spec = {
'zoneId' in bidRequest.params &&
!isNaN(Number(bidRequest.params.zoneId)) &&
bidRequest.params.zoneId > 0 &&
- bidRequest.mediaTypes &&
- (bidRequest.mediaTypes.banner || bidRequest.mediaTypes.video ||
- (bidRequest.mediaTypes.native && validateNativeAdUnit(bidRequest.mediaTypes.native))
+ (
+ isPlainObject(bidRequest?.mediaTypes?.banner) ||
+ isPlainObject(bidRequest?.mediaTypes?.video) ||
+ (isPlainObject(bidRequest?.mediaTypes?.native) && validateNativeAdUnit(bidRequest.mediaTypes.native))
);
},
@@ -224,6 +226,9 @@ export const spec = {
if (isStr(rtbBid.ext.agency_name)) {
deepSetValue(prBid, 'meta.agencyName', rtbBid.ext.agency_name);
}
+ if (isPlainObject(rtbBid.ext.dsa)) {
+ deepSetValue(prBid, 'meta.dsa', rtbBid.ext.dsa);
+ }
}
return prBid;
@@ -521,6 +526,42 @@ function makeSyncInfo(bidderRequest) {
}
}
+/**
+ * Initialize DSA request
+ * @param fpd {Object}
+ */
+function makeDSARequest(fpd) {
+ /**
+ * @type {DSARequest}
+ */
+ const pubDsa = fpd?.regs?.ext?.dsa;
+ if (!isPlainObject(pubDsa)) {
+ return;
+ }
+ const dsaObj = {};
+ ['dsarequired', 'pubrender', 'datatopub'].forEach((dsaKey) => {
+ if (isNumber(pubDsa[dsaKey])) {
+ dsaObj[dsaKey] = pubDsa[dsaKey];
+ }
+ });
+ if (isArray(pubDsa.transparency) && pubDsa.transparency.every((v) => isPlainObject(v))) {
+ const tpData = [];
+ pubDsa.transparency.forEach((tpObj) => {
+ if (isStr(tpObj.domain) && tpObj.domain !== '' && isArray(tpObj.dsaparams) && tpObj.dsaparams.every((v) => isNumber(v))) {
+ tpData.push(tpObj);
+ }
+ });
+ if (tpData.length > 0) {
+ dsaObj.transparency = tpData;
+ }
+ }
+ if (!isEmpty(dsaObj)) {
+ let res = {};
+ deepSetValue(res, 'regs.ext.dsa', dsaObj);
+ return res;
+ }
+}
+
/**
* Builds complete rtb request
* @param imps {Object} Collection of rtb impressions
@@ -537,7 +578,8 @@ function buildRtbRequest(imps, bidderRequest, schain) {
makeSiteOrApp(bidderRequest, fpd),
makeUser(bidderRequest, fpd),
makeRegulations(bidderRequest),
- makeSyncInfo(bidderRequest)
+ makeSyncInfo(bidderRequest),
+ makeDSARequest(fpd)
);
if (schain) {
deepSetValue(req, 'source.ext.schain', schain);
diff --git a/test/spec/modules/adkernelBidAdapter_spec.js b/test/spec/modules/adkernelBidAdapter_spec.js
index 00679447a95..7688af8b615 100644
--- a/test/spec/modules/adkernelBidAdapter_spec.js
+++ b/test/spec/modules/adkernelBidAdapter_spec.js
@@ -4,327 +4,188 @@ import * as utils from 'src/utils';
import { NATIVE, BANNER, VIDEO } from 'src/mediaTypes';
import { config } from 'src/config';
import { parseDomain } from '../../../src/refererDetection.js';
-
-describe('Adkernel adapter', function () {
- const bid1_zone1 = {
- bidder: 'adkernel',
- params: { zoneId: 1, host: 'rtb.adkernel.com' },
- adUnitCode: 'ad-unit-1',
- bidId: 'Bid_01',
- bidderRequestId: 'req-001',
- auctionId: 'auc-001',
- mediaTypes: {
- banner: {
- sizes: [[300, 250], [300, 200]],
- pos: 1
- }
- },
- ortb2Imp: {
- battr: [6, 7, 9],
- pos: 2
- }
- }; const bid2_zone2 = {
- bidder: 'adkernel',
- params: { zoneId: 2, host: 'rtb.adkernel.com' },
- adUnitCode: 'ad-unit-2',
- bidId: 'Bid_02',
- bidderRequestId: 'req-001',
- auctionId: 'auc-001',
- mediaTypes: {
- banner: {
- sizes: [[728, 90]]
- }
- },
- userIdAsEids: [
- {
- source: 'crwdcntrl.net',
- uids: [
- { atype: 1, id: '97d09fbba28542b7acbb6317c9534945a702b74c5993c352f332cfe83f40cdd9' }
- ]
- }
- ]
- }; const bid3_host2 = {
- bidder: 'adkernel',
- params: { zoneId: 1, host: 'rtb-private.adkernel.com' },
- adUnitCode: 'ad-unit-2',
- bidId: 'Bid_02',
- bidderRequestId: 'req-001',
- auctionId: 'auc-001',
- mediaTypes: {
- banner: {
- sizes: [[728, 90]]
- }
- }
- }; const bid_without_zone = {
- bidder: 'adkernel',
- params: { host: 'rtb-private.adkernel.com' },
- adUnitCode: 'ad-unit-1',
- bidId: 'Bid_W',
- bidderRequestId: 'req-002',
- auctionId: 'auc-002',
- mediaTypes: {
- banner: {
- sizes: [[728, 90]]
- }
+import { mergeDeep } from "src/utils";
+
+const UNIT_BANNER = {
+ bidder: 'adkernel',
+ params: { zoneId: 1, host: 'rtb.adkernel.com' },
+ adUnitCode: 'ad-unit-1',
+ bidId: 'Bid_01',
+ bidderRequestId: 'req-001',
+ auctionId: 'auc-001',
+ mediaTypes: {
+ banner: {
+ sizes: [[300, 250], [300, 200]],
+ pos: 1
}
- }; const bid_without_host = {
- bidder: 'adkernel',
- params: { zoneId: 1 },
- adUnitCode: 'ad-unit-1',
- bidId: 'Bid_W',
- bidderRequestId: 'req-002',
- auctionId: 'auc-002',
- mediaTypes: {
- banner: {
- sizes: [[728, 90]]
- }
+ }
+};
+const UNIT_VIDEO = {
+ bidder: 'adkernel',
+ transactionId: 'transaction-id',
+ bidId: 'Bid_01',
+ bidderRequestId: 'req-001',
+ auctionId: 'auc-001',
+ params: { zoneId: 1, host: 'rtb.adkernel.com' },
+ mediaTypes: {
+ video: {
+ context: 'instream',
+ playerSize: [[640, 480]],
+ api: [1, 2],
+ placement: 1,
+ plcmt: 1,
+ skip: 1,
+ pos: 1
}
- }; const bid_with_wrong_zoneId = {
- bidder: 'adkernel',
- params: { zoneId: 'wrong id', host: 'rtb.adkernel.com' },
- adUnitCode: 'ad-unit-2',
- bidId: 'Bid_02',
- bidderRequestId: 'req-002',
- auctionId: 'auc-002',
- mediaTypes: {
- banner: {
- sizes: [[728, 90]]
+ },
+ adUnitCode: 'ad-unit-1'
+};
+const UNIT_MULTIFORMAT = merge(UNIT_BANNER, UNIT_VIDEO);
+const UNIT_NATIVE = {
+ bidder: 'adkernel',
+ params: { zoneId: 1, host: 'rtb.adkernel.com' },
+ mediaTypes: {
+ native: {
+ title: {
+ required: true,
+ len: 80
+ },
+ body: {
+ required: true
+ },
+ body2: {
+ required: true
+ },
+ icon: {
+ required: true,
+ aspect_ratios: [{ min_width: 50, min_height: 50 }]
+ },
+ image: {
+ required: true,
+ sizes: [300, 200]
+ },
+ clickUrl: {
+ required: true
+ },
+ rating: {
+ required: false
+ },
+ price: {
+ required: false
+ },
+ privacyLink: {
+ required: false
+ },
+ cta: {
+ required: false
+ },
+ sponsoredBy: {
+ required: false
+ },
+ displayUrl: {
+ required: false
}
}
- }; const bid_video = {
- bidder: 'adkernel',
- transactionId: '866394b8-5d37-4d49-803e-f1bdb595f73e',
- bidId: 'Bid_Video',
- bidderRequestId: '18b2a61ea5d9a7',
- auctionId: 'de45acf1-9109-4e52-8013-f2b7cf5f6766',
- params: {
- zoneId: 1,
- host: 'rtb.adkernel.com',
- },
- mediaTypes: {
- video: {
- context: 'instream',
- playerSize: [[640, 480]],
- api: [1, 2],
- placement: 1,
- plcmt: 1,
- skip: 1,
- pos: 1
- }
- },
- adUnitCode: 'ad-unit-1'
- }; const bid_multiformat = {
- bidder: 'adkernel',
- params: { zoneId: 1, host: 'rtb.adkernel.com' },
- mediaTypes: {
- banner: { sizes: [[300, 250], [300, 200]] },
- video: { context: 'instream', playerSize: [[640, 480]] }
- },
- adUnitCode: 'ad-unit-1',
- transactionId: 'f82c64b8-c602-42a4-9791-4a268f6559ed',
- bidId: 'Bid_01',
- bidderRequestId: 'req-001',
- auctionId: 'auc-001'
- };
- const bid_native = {
- bidder: 'adkernel',
- params: { zoneId: 1, host: 'rtb.adkernel.com' },
- mediaTypes: {
- native: {
- title: {
- required: true,
- len: 80
- },
- body: {
- required: true
- },
- body2: {
- required: true
- },
- icon: {
- required: true,
- aspect_ratios: [{ min_width: 50, min_height: 50 }]
- },
- image: {
- required: true,
- sizes: [300, 200]
- },
- clickUrl: {
- required: true
- },
- rating: {
- required: false
- },
- price: {
- required: false
- },
- privacyLink: {
- required: false
- },
- cta: {
- required: false
- },
- sponsoredBy: {
- required: false
- },
- displayUrl: {
- required: false
- }
+ },
+ nativeOrtbRequest: {
+ ver: '1.2',
+ assets: [
+ {
+ id: 0, required: 1, title: { len: 80 }
+ }, { id: 1, required: 1, data: { type: 2 } },
+ {
+ id: 2, required: 1, data: { type: 10 }
+ }, {
+ id: 3, required: 1, img: { type: 1, wmin: 50, hmin: 50 }
+ }, {
+ id: 4, required: 1, img: { type: 3, w: 300, h: 200 }
+ }, {
+ id: 5, required: 0, data: { type: 3 }
+ }, {
+ id: 6, required: 0, data: { type: 6 }
+ }, {
+ id: 7, required: 0, data: { type: 12 }
+ }, {
+ id: 8, required: 0, data: { type: 1 }
+ }, {
+ id: 9, required: 0, data: { type: 11 }
}
- },
- nativeOrtbRequest: {
- ver: '1.2',
+ ],
+ privacy: 1
+ },
+ adUnitCode: 'ad-unit-1',
+ transactionId: 'transaction-id',
+ bidId: 'Bid_01',
+ bidderRequestId: 'req-001',
+ auctionId: 'auc-001'
+};
+const BID_BANNER = {
+ id: '1',
+ impid: 'Bid_01',
+ crid: '100_001',
+ price: 3.01,
+ nurl: 'https://rtb.com/win?i=ZjKoPYSFI3Y_0',
+ adm: '',
+ w: 300,
+ h: 250,
+ dealid: 'deal',
+ mtype: 1
+};
+const BID_VIDEO_NURL = {
+ id: 'sZSYq5zYMxo_0',
+ impid: 'Bid_01',
+ crid: '100_003',
+ price: 0.00145,
+ adid: '158801',
+ nurl: 'https://rtb.com/win?i=sZSYq5zYMxo_0&f=nurl',
+ cid: '16855',
+ mtype: 2
+};
+const BID_VIDEO_ADM = {
+ id: 'sZSYq5zYMxo_0',
+ impid: 'Bid_01',
+ crid: '100_003',
+ price: 0.00145,
+ adid: '158801',
+ adm: '',
+ nurl: 'https://rtb.com/win?i=sZSYq5zYMxo_0',
+ cid: '16855',
+ mtype: 2
+};
+const BID_USER_SYNC_ONLY = {
+ id: 'nobid1',
+ ext: {
+ adk_usersync: [{ type: 2, url: 'https://adk.sync.com/sync' }]
+ }
+};
+const BID_NATIVE = {
+ id: 'someid_01',
+ impid: 'Bid_01',
+ price: 2.25,
+ adid: '4',
+ adm: JSON.stringify({
+ native: {
assets: [
- {
- id: 0, required: 1, title: { len: 80 }
- }, { id: 1, required: 1, data: { type: 2 } },
- {
- id: 2, required: 1, data: { type: 10 }
- }, {
- id: 3, required: 1, img: { type: 1, wmin: 50, hmin: 50 }
- }, {
- id: 4, required: 1, img: { type: 3, w: 300, h: 200 }
- }, {
- id: 5, required: 0, data: { type: 3 }
- }, {
- id: 6, required: 0, data: { type: 6 }
- }, {
- id: 7, required: 0, data: { type: 12 }
- }, {
- id: 8, required: 0, data: { type: 1 }
- }, {
- id: 9, required: 0, data: { type: 11 }
- }
+ { id: 0, title: { text: 'Title' } },
+ { id: 3, data: { value: 'Description' } },
+ { id: 4, data: { value: 'Additional description' } },
+ { id: 1, img: { url: 'http://rtb.com/thumbnail?i=pTuOlf5KHUo_0&imgt=icon', w: 50, h: 50 } },
+ { id: 2, img: { url: 'http://rtb.com/thumbnail?i=pTuOlf5KHUo_0', w: 300, h: 200 } },
+ { id: 5, data: { value: 'Sponsor.com' } },
+ { id: 14, data: { value: 'displayurl.com' } }
],
- privacy: 1
- },
- adUnitCode: 'ad-unit-1',
- transactionId: 'f82c64b8-c602-42a4-9791-4a268f6559ed',
- bidId: 'Bid_01',
- bidderRequestId: 'req-001',
- auctionId: 'auc-001'
- };
-
- const bannerBidResponse = {
- id: 'bid1',
- seatbid: [{
- bid: [{
- id: '1',
- impid: 'Bid_01',
- crid: '100_001',
- price: 3.01,
- nurl: 'https://rtb.com/win?i=ZjKoPYSFI3Y_0',
- adm: '',
- w: 300,
- h: 250,
- dealid: 'deal',
- mtype: 1
- }]
- }],
- ext: {
- adk_usersync: [{ type: 1, url: 'https://adk.sync.com/sync' }]
- }
- }; const videoBidResponse = {
- id: '47ce4badcf7482',
- seatbid: [{
- bid: [{
- id: 'sZSYq5zYMxo_0',
- impid: 'Bid_Video',
- crid: '100_003',
- price: 0.00145,
- adid: '158801',
- nurl: 'https://rtb.com/win?i=sZSYq5zYMxo_0&f=nurl',
- cid: '16855',
- mtype: 2
- }]
- }],
- }; const videoBidResponseWithAdm = {
- id: '47ce4badcf7482',
- seatbid: [{
- bid: [{
- id: 'sZSYq5zYMxo_0',
- impid: 'Bid_Video',
- crid: '100_003',
- price: 0.00145,
- adid: '158801',
- adm: '',
- nurl: 'https://rtb.com/win?i=sZSYq5zYMxo_0',
- cid: '16855',
- mtype: 2
- }]
- }],
- };
- const usersyncOnlyResponse = {
- id: 'nobid1',
- ext: {
- adk_usersync: [{ type: 2, url: 'https://adk.sync.com/sync' }]
+ link: { url: 'http://rtb.com/click?i=pTuOlf5KHUo_0' },
+ imptrackers: ['http://rtb.com/win?i=pTuOlf5KHUo_0&f=imp']
}
- }; const nativeResponse = {
- id: '56fbc713-b737-4651-9050-13376aed9818',
- seatbid: [{
- bid: [{
- id: 'someid_01',
- impid: 'Bid_01',
- price: 2.25,
- adid: '4',
- adm: JSON.stringify({
- native: {
- assets: [
- { id: 0, title: { text: 'Title' } },
- { id: 3, data: { value: 'Description' } },
- { id: 4, data: { value: 'Additional description' } },
- { id: 1, img: { url: 'http://rtb.com/thumbnail?i=pTuOlf5KHUo_0&imgt=icon', w: 50, h: 50 } },
- { id: 2, img: { url: 'http://rtb.com/thumbnail?i=pTuOlf5KHUo_0', w: 300, h: 200 } },
- { id: 5, data: { value: 'Sponsor.com' } },
- { id: 14, data: { value: 'displayurl.com' } }
- ],
- link: { url: 'http://rtb.com/click?i=pTuOlf5KHUo_0' },
- imptrackers: ['http://rtb.com/win?i=pTuOlf5KHUo_0&f=imp']
- }
- }),
- adomain: ['displayurl.com'],
- cat: ['IAB1-4', 'IAB8-16', 'IAB25-5'],
- cid: '1',
- crid: '4',
- mtype: 4,
- ext: {
- 'advertiser_id': 777,
- 'advertiser_name': 'advertiser',
- 'agency_name': 'agency'
- }
- }]
- }],
- bidid: 'pTuOlf5KHUo',
- cur: 'EUR'
- };
- const multiformat_response = {
- id: '47ce4badcf7482',
- seatbid: [{
- bid: [{
- id: 'sZSYq5zYMxo_0',
- impid: 'Bid_01b__mf',
- crid: '100_003',
- price: 0.00145,
- adid: '158801',
- adm: '',
- nurl: 'https://rtb.com/win?i=sZSYq5zYMxo_0&f=nurl',
- cid: '16855',
- mtype: 1
- }, {
- id: 'sZSYq5zYMxo_1',
- impid: 'Bid_01v__mf',
- crid: '100_003',
- price: 0.25,
- adid: '158801',
- nurl: 'https://rtb.com/win?i=sZSYq5zYMxo_1&f=nurl',
- cid: '16855',
- mtype: 2
- }]
- }],
- bidid: 'pTuOlf5KHUo',
- cur: 'USD'
- };
+ }),
+ adomain: ['displayurl.com'],
+ mtype: 4,
+ cid: '1',
+ crid: '4'
+};
+const DEFAULT_BIDDER_REQUEST = buildBidderRequest();
+describe('Adkernel adapter', function () {
var sandbox;
beforeEach(function () {
sandbox = sinon.createSandbox();
@@ -335,19 +196,21 @@ describe('Adkernel adapter', function () {
config.resetConfig();
});
- function buildBidderRequest(url = 'https://example.com/index.html', params = {}) {
- return Object.assign({}, params, { refererInfo: { page: url, domain: parseDomain(url), reachedTop: true }, timeout: 3000, bidderCode: 'adkernel' });
- }
- const DEFAULT_BIDDER_REQUEST = buildBidderRequest();
-
- function buildRequest(bidRequests, bidderRequest = DEFAULT_BIDDER_REQUEST) {
- bidderRequest.bids = bidRequests;
- const pbRequests = spec.buildRequests(bidRequests, bidderRequest);
- const rtbRequests = pbRequests.map(r => JSON.parse(r.data));
- return [pbRequests, rtbRequests];
- }
-
describe('input parameters validation', function () {
+ const BASE_ADUNIT = {
+ bidder: 'adkernel',
+ params: {},
+ adUnitCode: 'ad-unit-1',
+ bidId: 'Bid_W',
+ bidderRequestId: 'req-002',
+ auctionId: 'auc-002',
+ mediaTypes: {
+ banner: {
+ sizes: [[728, 90]]
+ }
+ }
+ };
+
it('empty request shouldn\'t generate exception', function () {
expect(spec.isBidRequestValid({
bidderCode: 'adkernel'
@@ -355,19 +218,29 @@ describe('Adkernel adapter', function () {
});
it('request without zone shouldn\'t issue a request', function () {
- expect(spec.isBidRequestValid(bid_without_zone)).to.be.equal(false);
+ expect(
+ spec.isBidRequestValid(
+ merge(BASE_ADUNIT, { params: { host: 'rtb-private.adkernel.com' } })
+ )
+ ).to.be.equal(false);
});
it('request without host shouldn\'t issue a request', function () {
- expect(spec.isBidRequestValid(bid_without_host)).to.be.equal(false);
+ expect(spec.isBidRequestValid(
+ merge(BASE_ADUNIT, { params: { zoneId: 1 } })
+ )).to.be.equal(false);
});
it('empty request shouldn\'t generate exception', function () {
- expect(spec.isBidRequestValid(bid_with_wrong_zoneId)).to.be.equal(false);
+ expect(spec.isBidRequestValid(
+ merge(BASE_ADUNIT, { params: { zoneId: 'wrong id', host: 'rtb.adkernel.com' } })
+ )).to.be.equal(false);
});
- it('valid native requests should pass', () => {
- expect(spec.isBidRequestValid(bid_native)).to.be.equal(true);
+ it('valid requests should pass', () => {
+ expect(spec.isBidRequestValid(
+ merge(BASE_ADUNIT, { params: { zoneId: 10, host: 'rtb.adkernel.com' } })
+ )).to.be.true;
});
});
@@ -375,7 +248,14 @@ describe('Adkernel adapter', function () {
let bidRequest, bidRequests;
before(function () {
- [, bidRequests] = buildRequest([bid1_zone1]);
+ [, bidRequests] = buildRequest([
+ merge(UNIT_BANNER, {
+ ortb2Imp: {
+ battr: [6, 7, 9],
+ pos: 2
+ }
+ })
+ ]);
bidRequest = bidRequests[0];
});
@@ -428,13 +308,13 @@ describe('Adkernel adapter', function () {
});
it('shouldn\'t contain gdpr nor ccpa information for default request', function () {
- const [, bidRequests] = buildRequest([bid1_zone1]);
+ const [, bidRequests] = buildRequest([UNIT_BANNER]);
expect(bidRequests[0]).to.not.have.property('regs');
expect(bidRequests[0]).to.not.have.property('user');
});
it('should contain gdpr-related information if consent is configured', function () {
- const [, bidRequests] = buildRequest([bid1_zone1],
+ const [, bidRequests] = buildRequest([UNIT_BANNER],
buildBidderRequest('https://example.com/index.html', {
gdprConsent: { gdprApplies: true, consentString: 'test-consent-string', vendorData: {} },
uspConsent: '1YNN',
@@ -452,14 +332,14 @@ describe('Adkernel adapter', function () {
it('should contain coppa if configured', function () {
config.setConfig({ coppa: true });
- const [, bidRequests] = buildRequest([bid1_zone1]);
+ const [, bidRequests] = buildRequest([UNIT_BANNER]);
const bidRequest = bidRequests[0];
expect(bidRequest).to.have.property('regs');
expect(bidRequest.regs).to.have.property('coppa', 1);
});
it('should\'t contain consent string if gdpr isn\'t applied', function () {
- const [, bidRequests] = buildRequest([bid1_zone1], buildBidderRequest('https://example.com/index.html', { gdprConsent: { gdprApplies: false } }));
+ const [, bidRequests] = buildRequest([UNIT_BANNER], buildBidderRequest('https://example.com/index.html', { gdprConsent: { gdprApplies: false } }));
const bidRequest = bidRequests[0];
expect(bidRequest).to.have.property('regs');
expect(bidRequest.regs.ext).to.be.eql({ 'gdpr': 0 });
@@ -467,24 +347,30 @@ describe('Adkernel adapter', function () {
});
it('should forward default bidder timeout', function() {
- const [, bidRequests] = buildRequest([bid1_zone1]);
+ const [, bidRequests] = buildRequest([UNIT_BANNER]);
expect(bidRequests[0]).to.have.property('tmax', 3000);
});
it('should set bidfloor if configured', function() {
- const bid = Object.assign({}, bid1_zone1);
- bid.getFloor = function() {
- return {
- currency: 'USD',
- floor: 0.145
- };
- };
+ const bid = merge(UNIT_BANNER, {
+ getFloor: function() {
+ return {
+ currency: 'USD',
+ floor: 0.145
+ };
+ }
+ });
const [, bidRequests] = buildRequest([bid]);
expect(bidRequests[0].imp[0]).to.have.property('bidfloor', 0.145);
});
it('should forward user ids if available', function() {
- const bid = Object.assign({}, bid2_zone2);
+ const bid = merge(UNIT_BANNER, {
+ userIdAsEids: [{
+ source: 'crwdcntrl.net',
+ uids: [{ atype: 1, id: '97d09fbba28542b7acbb6317c9534945a702b74c5993c352f332cfe83f40cdd9' }]
+ }]
+ });
const [, bidRequests] = buildRequest([bid]);
expect(bidRequests[0]).to.have.property('user');
expect(bidRequests[0].user).to.have.property('ext');
@@ -498,7 +384,7 @@ describe('Adkernel adapter', function () {
describe('video request building', function () {
let bidRequests;
before(function () {
- [, bidRequests] = buildRequest([bid_video]);
+ [, bidRequests] = buildRequest([UNIT_VIDEO]);
});
it('should have video object', function () {
@@ -528,7 +414,7 @@ describe('Adkernel adapter', function () {
describe('multiformat request building', function () {
let pbRequests, bidRequests;
before(() => {
- [pbRequests, bidRequests] = buildRequest([bid_multiformat]);
+ [pbRequests, bidRequests] = buildRequest([UNIT_MULTIFORMAT]);
});
it('should contain single request', function () {
expect(bidRequests).to.have.length(1);
@@ -543,7 +429,13 @@ describe('Adkernel adapter', function () {
expect(bidRequests[0].imp[1].id).to.be.not.eql(bidRequests[0].imp[0].id);
});
it('should collect ads back to same requestId', function() {
- const bids = spec.interpretResponse({ body: multiformat_response }, pbRequests[0]);
+ const bids = spec.interpretResponse({
+ body: createRtbBidResponse(
+ [
+ merge(BID_BANNER, { impid: 'Bid_01b__mf' }),
+ merge(BID_VIDEO_NURL, { impid: 'Bid_01v__mf' })
+ ])
+ }, pbRequests[0]);
expect(bids).to.have.length(2);
expect(bids[0].requestId).to.be.eql('Bid_01');
expect(bids[0].mediaType).to.be.eql('banner');
@@ -553,18 +445,22 @@ describe('Adkernel adapter', function () {
});
describe('requests routing', function () {
+ // let banner_unit_otherzone = extend(banner_unit, {params: extend(banner_unit.params, {zone: 2})});
+
it('should issue a request for each host', function () {
- const [pbRequests] = buildRequest([bid1_zone1, bid3_host2]);
+ const banner_unit_otherhost = merge(UNIT_BANNER, { params: { host: 'otherhost.com' } });
+ const [pbRequests] = buildRequest([UNIT_BANNER, banner_unit_otherhost]);
expect(pbRequests).to.have.length(2);
- expect(pbRequests[0].url).to.have.string(`https://${bid1_zone1.params.host}/`);
- expect(pbRequests[1].url).to.have.string(`https://${bid3_host2.params.host}/`);
+ expect(pbRequests[0].url).to.have.string(`https://${UNIT_BANNER.params.host}/`);
+ expect(pbRequests[1].url).to.have.string(`https://${banner_unit_otherhost.params.host}/`);
});
it('should issue a request for each zone', function () {
- const [pbRequests] = buildRequest([bid1_zone1, bid2_zone2]);
+ const banner_unit_otherzone = merge(UNIT_BANNER, { params: { zoneId: 2 } });
+ const [pbRequests] = buildRequest([UNIT_BANNER, banner_unit_otherzone]);
expect(pbRequests).to.have.length(2);
- expect(pbRequests[0].url).to.include(`zone=${bid1_zone1.params.zoneId}`);
- expect(pbRequests[1].url).to.include(`zone=${bid2_zone2.params.zoneId}`);
+ expect(pbRequests[0].url).to.include(`zone=${UNIT_BANNER.params.zoneId}`);
+ expect(pbRequests[1].url).to.include(`zone=${banner_unit_otherzone.params.zoneId}`);
});
});
@@ -581,7 +477,7 @@ describe('Adkernel adapter', function () {
}
}
});
- const [, bidRequests] = buildRequest([bid1_zone1]);
+ const [, bidRequests] = buildRequest([UNIT_BANNER]);
expect(bidRequests).to.have.length(1);
expect(bidRequests[0]).to.not.have.property('ext');
});
@@ -598,7 +494,7 @@ describe('Adkernel adapter', function () {
}
}
});
- const [, bidRequests] = buildRequest([bid1_zone1]);
+ const [, bidRequests] = buildRequest([UNIT_BANNER]);
expect(bidRequests).to.have.length(1);
expect(bidRequests[0].ext).to.have.property('adk_usersync', 1);
});
@@ -619,7 +515,7 @@ describe('Adkernel adapter', function () {
}
}
});
- const [, bidRequests] = buildRequest([bid1_zone1]);
+ const [, bidRequests] = buildRequest([UNIT_BANNER]);
expect(bidRequests).to.have.length(1);
expect(bidRequests[0].ext).to.have.property('adk_usersync', 2);
});
@@ -640,7 +536,7 @@ describe('Adkernel adapter', function () {
}
}
});
- const [, bidRequests] = buildRequest([bid1_zone1]);
+ const [, bidRequests] = buildRequest([UNIT_BANNER]);
expect(bidRequests).to.have.length(1);
expect(bidRequests[0]).to.not.have.property('ext');
});
@@ -648,8 +544,8 @@ describe('Adkernel adapter', function () {
describe('responses processing', function () {
it('should return fully-initialized banner bid-response', function () {
- const [pbRequests] = buildRequest([bid1_zone1]);
- const resp = spec.interpretResponse({ body: bannerBidResponse }, pbRequests[0])[0];
+ const [pbRequests] = buildRequest([UNIT_BANNER]);
+ const resp = spec.interpretResponse({ body: createRtbBidResponse(BID_BANNER) }, pbRequests[0])[0];
expect(resp).to.have.property('requestId', 'Bid_01');
expect(resp).to.have.property('cpm', 3.01);
expect(resp).to.have.property('width', 300);
@@ -665,9 +561,9 @@ describe('Adkernel adapter', function () {
});
it('should return fully-initialized video bid-response', function () {
- const [pbRequests] = buildRequest([bid_video]);
- const resp = spec.interpretResponse({ body: videoBidResponse }, pbRequests[0])[0];
- expect(resp).to.have.property('requestId', 'Bid_Video');
+ const [pbRequests] = buildRequest([UNIT_VIDEO]);
+ const resp = spec.interpretResponse({ body: createRtbBidResponse(BID_VIDEO_NURL) }, pbRequests[0])[0];
+ expect(resp).to.have.property('requestId', 'Bid_01');
expect(resp.mediaType).to.equal(VIDEO);
expect(resp.cpm).to.equal(0.00145);
expect(resp.vastUrl).to.equal('https://rtb.com/win?i=sZSYq5zYMxo_0&f=nurl');
@@ -676,9 +572,9 @@ describe('Adkernel adapter', function () {
});
it('should support vast xml in adm', function () {
- const [pbRequests] = buildRequest([bid_video]);
- const resp = spec.interpretResponse({ body: videoBidResponseWithAdm }, pbRequests[0])[0];
- expect(resp).to.have.property('requestId', 'Bid_Video');
+ const [pbRequests] = buildRequest([UNIT_VIDEO]);
+ const resp = spec.interpretResponse({ body: createRtbBidResponse(BID_VIDEO_ADM) }, pbRequests[0])[0];
+ expect(resp).to.have.property('requestId', 'Bid_01');
expect(resp.mediaType).to.equal(VIDEO);
expect(resp.cpm).to.equal(0.00145);
expect(resp.vastXml).to.equal('');
@@ -687,29 +583,54 @@ describe('Adkernel adapter', function () {
expect(resp.height).to.equal(480);
});
+ it('should fill ad meta', () => {
+ const [pbRequests] = buildRequest([UNIT_BANNER]);
+ const resp = spec.interpretResponse({
+ body: createRtbBidResponse(BID_BANNER, {
+ adomain: ['displayurl.com'],
+ cat: ['IAB1-4', 'IAB8-16', 'IAB25-5'],
+ ext: {
+ advertiser_id: 777,
+ advertiser_name: 'advertiser',
+ agency_name: 'agency',
+ }
+ })
+ }, pbRequests[0])[0];
+ expect(resp.meta.advertiserId).to.be.eql(777);
+ expect(resp.meta.advertiserName).to.be.eql('advertiser');
+ expect(resp.meta.agencyName).to.be.eql('agency');
+ expect(resp.meta.advertiserDomains).to.be.eql(['displayurl.com']);
+ expect(resp.meta.secondaryCatIds).to.be.eql(['IAB1-4', 'IAB8-16', 'IAB25-5']);
+ });
+
it('should add nurl as pixel for banner response', function () {
- const [pbRequests] = buildRequest([bid1_zone1]);
- const resp = spec.interpretResponse({ body: bannerBidResponse }, pbRequests[0])[0];
- const expectedNurl = bannerBidResponse.seatbid[0].bid[0].nurl + '&px=1';
+ const [pbRequests] = buildRequest([UNIT_BANNER]);
+ const resp = spec.interpretResponse({ body: createRtbBidResponse(BID_BANNER) }, pbRequests[0])[0];
+ const expectedNurl = BID_BANNER.nurl + '&px=1';
expect(resp.ad).to.have.string(expectedNurl);
});
it('should handle bidresponse with user-sync only', function () {
- const [pbRequests] = buildRequest([bid1_zone1]);
- const resp = spec.interpretResponse({ body: usersyncOnlyResponse }, pbRequests[0]);
+ const [pbRequests] = buildRequest([UNIT_BANNER]);
+ const resp = spec.interpretResponse({ body: BID_USER_SYNC_ONLY }, pbRequests[0]);
expect(resp).to.have.length(0);
});
it('should perform usersync', function () {
+ let bidResp = createRtbBidResponse(BID_BANNER, undefined, {
+ ext: {
+ adk_usersync: [{ type: 1, url: 'https://adk.sync.com/sync' }]
+ }
+ });
let syncs = spec.getUserSyncs({ iframeEnabled: true, pixelEnabled: true }, []);
expect(syncs).to.have.length(0);
- syncs = spec.getUserSyncs({ iframeEnabled: false, pixelEnabled: false }, [{ body: bannerBidResponse }]);
+ syncs = spec.getUserSyncs({ iframeEnabled: false, pixelEnabled: false }, [{ body: bidResp }]);
expect(syncs).to.have.length(0);
- syncs = spec.getUserSyncs({ iframeEnabled: true, pixelEnabled: true }, [{ body: bannerBidResponse }]);
+ syncs = spec.getUserSyncs({ iframeEnabled: true, pixelEnabled: true }, [{ body: bidResp }]);
expect(syncs).to.have.length(1);
expect(syncs[0]).to.have.property('type', 'iframe');
expect(syncs[0]).to.have.property('url', 'https://adk.sync.com/sync');
- syncs = spec.getUserSyncs({ iframeEnabled: false, pixelEnabled: true }, [{ body: usersyncOnlyResponse }]);
+ syncs = spec.getUserSyncs({ iframeEnabled: false, pixelEnabled: true }, [{ body: BID_USER_SYNC_ONLY }]);
expect(syncs).to.have.length(1);
expect(syncs[0]).to.have.property('type', 'image');
expect(syncs[0]).to.have.property('url', 'https://adk.sync.com/sync');
@@ -725,7 +646,7 @@ describe('Adkernel adapter', function () {
describe('native support', () => {
let bidRequests;
before(function () {
- [, bidRequests] = buildRequest([bid_native]);
+ [, bidRequests] = buildRequest([UNIT_NATIVE]);
});
it('native request building', () => {
@@ -748,17 +669,12 @@ describe('Adkernel adapter', function () {
});
it('native response processing', () => {
- const [pbRequests] = buildRequest([bid_native]);
- const resp = spec.interpretResponse({ body: nativeResponse }, pbRequests[0])[0];
+ const [pbRequests] = buildRequest([UNIT_NATIVE]);
+ const resp = spec.interpretResponse({ body: createRtbBidResponse(BID_NATIVE, undefined, { cur: 'EUR' }) }, pbRequests[0])[0];
expect(resp).to.have.property('requestId', 'Bid_01');
expect(resp).to.have.property('cpm', 2.25);
expect(resp).to.have.property('currency', 'EUR');
expect(resp).to.have.property('meta');
- expect(resp.meta.advertiserId).to.be.eql(777);
- expect(resp.meta.advertiserName).to.be.eql('advertiser');
- expect(resp.meta.agencyName).to.be.eql('agency');
- expect(resp.meta.advertiserDomains).to.be.eql(['displayurl.com']);
- expect(resp.meta.secondaryCatIds).to.be.eql(['IAB1-4', 'IAB8-16', 'IAB25-5']);
expect(resp).to.have.property('mediaType', NATIVE);
expect(resp).to.have.property('native');
expect(resp.native).to.have.property('ortb');
@@ -787,10 +703,113 @@ describe('Adkernel adapter', function () {
utils.triggerPixel.restore();
});
it('should trigger pixel for nurl', () => {
- const [pbRequests] = buildRequest([bid_video]);
- const bid = spec.interpretResponse({ body: videoBidResponseWithAdm }, pbRequests[0])[0];
+ const [pbRequests] = buildRequest([UNIT_VIDEO]);
+ const bid = spec.interpretResponse({ body: createRtbBidResponse(BID_VIDEO_ADM) }, pbRequests[0])[0];
spec.onBidWon(bid);
expect(utils.triggerPixel.callCount).to.equal(1);
});
});
+
+ describe('DSA feature', () => {
+ it('should fill dsa pub info and parse advertiser info', () => {
+ const bid = merge(UNIT_BANNER);
+ const [pbRequests, rtbRequest] = buildRequest([bid],
+ buildBidderRequest('https://example.com/index.html',
+ {
+ ortb2: {
+ regs: {
+ ext: {
+ dsa: {
+ dsarequired: 1,
+ pubrender: 0,
+ datatopub: 1,
+ transparency: [
+ { domain: 'good-domain', dsaparams: [1, 2] },
+ { domain: 'bad-setup', dsaparams: ['1', 3] }
+ ]
+ }
+ }
+ }
+ }
+ }));
+ let dsa = rtbRequest[0].regs.ext.dsa;
+ expect(dsa).to.be.an('object');
+ expect(dsa.dsarequired).to.be.eql(1);
+ expect(dsa.pubrender).to.be.eql(0);
+ expect(dsa.datatopub).to.be.eql(1);
+ expect(dsa.transparency).to.be.an('array').with.lengthOf(1);
+ expect(dsa.transparency[0].domain).to.be.eql('good-domain');
+ expect(dsa.transparency[0].dsaparams).to.be.eql([1, 2]);
+
+ const resp = spec.interpretResponse({
+ body: createRtbBidResponse(BID_BANNER, {
+ ext: {
+ dsa: {
+ behalf: 'Advertiser',
+ paid: 'Advertiser',
+ adrender: 1,
+ transparency: [
+ { domain: 'dsp1domain.com', dsaparams: [1, 2] }
+ ]
+ }
+ }
+ })
+ }, pbRequests[0])[0];
+
+ dsa = resp.meta.dsa;
+ expect(dsa).to.be.an('object');
+ expect(dsa.behalf).to.be.eql('Advertiser');
+ expect(dsa.paid).to.be.eql('Advertiser');
+ expect(dsa.adrender).to.be.eql(1);
+ expect(dsa.transparency).to.be.an('array').with.lengthOf(1);
+ expect(dsa.transparency[0]).to.be.an('object');
+ expect(dsa.transparency[0].domain).to.be.eql('dsp1domain.com');
+ expect(dsa.transparency[0].dsaparams).to.be.eql([1, 2]);
+ });
+ });
});
+
+function merge(obj, ext = {}) {
+ return mergeDeep({}, obj, ext);
+}
+
+function buildBidderRequest(url = 'https://example.com/index.html', params = {}) {
+ return merge(params, {
+ refererInfo: { page: url, domain: parseDomain(url), reachedTop: true },
+ timeout: 3000,
+ bidderCode: 'adkernel'
+ });
+}
+
+function buildRequest(adUnits, bidderRequest = DEFAULT_BIDDER_REQUEST) {
+ bidderRequest = {
+ ...bidderRequest,
+ bids: adUnits
+ };
+ const pbRequests = spec.buildRequests(adUnits, bidderRequest);
+ const rtbRequests = pbRequests.map(r => JSON.parse(r.data));
+ return [pbRequests, rtbRequests];
+}
+
+function createRtbBidResponse(baseBid, extBid = undefined, respExt = {}) {
+ if (!Array.isArray(baseBid)) {
+ baseBid = [baseBid];
+ }
+ if (extBid === undefined) {
+ extBid = Array(baseBid.length).fill({});
+ } else if (!Array.isArray(extBid)) {
+ extBid = [extBid];
+ }
+ if (baseBid.length !== extBid.length) {
+ throw new Error('baseBid and extBid arrays should have the same length');
+ }
+ const bids = baseBid.map((bid, index) => merge(bid, extBid[index]));
+ return Object.assign({
+ id: 'xxx-xxx-xxx-xxx',
+ seatbid: [{
+ bid: bids
+ }],
+ bidid: 'some-bid-id',
+ cur: 'USD'
+ }, respExt);
+}